Поиск открытого API сайта или Ускоряем парсинг в 10 раз / Хабр

Без рубрики


https://habr.com/ru/post/680320/image

Цель статьи — описать алгоритм действий поиска открытого API сайта.

Целевая аудитория статьи — программисты, которым интересен парсинг и анализ уязвимостей сайтов.

В статье рассмотрим пример поиска API сайта edadeal.ru, познакомимся с протоколом google protobuf и сравним скорость различных подходов парсинга

1. Введение

Парсинг (в контексте статьи) — это автоматизированный процесс извлечение данных из Интернета.

Существует 2 подхода к извлечению данных со страниц сайта

  1. Извлекать данные из HTML-кода страницы сайта

    Плюсы — этот способ прост и работает всегда, так как код страницы всегда доступен пользователю

    Минусы — этот способ может работать долго (несколько секунд), если часть данных генерирует java script (например, данные появляются только после прокручивания страницы или нажатия кнопки)

  2. Использовать API сайта

    Плюсы — быстрее первого способа и не зависит от изменений структуры html-страницы

    Минус — не у всех сайтов есть открытое API

В статье рассмотрим пример поиска API сайта edadeal.ru, познакомимся с протоколом google protobuf и сравним скорость двух подходов парсинга

2. Постановка задачи

Задача — извлечь данные о продуктах с сайта Едадил (название продукта, цена, размер скидки, магазин, город и т.д)

3. Решение

1 Делаем запрос к странице, которую мы хотим парсить.

2 Перебираем все запросы, которые делает сайт. Для этого используем DevTools браузера

https://habr.com/ru/post/680320/image

3 Анализируем запросы

Из названия запроса понимаем, что нам нужен запрос

https://squark.edadeal.ru/web/search/offers?count=30&locality=moskva&page=1&retailer=5ka

В ответ на запрос получаем файл (назовем его binary_file.bin). Как узнать кодировку этого файла?

Формат файла из пункта 3 нам подсказывает строка-хедер content-type: application/x-protobuf

4 Определим структуру данных (.proto файл)

с помощью утилиты protoc (http://google.github.io/proto-lens/installing-protoc.html) преобразуем закодированный файл в понятный человеку формат

protoc --decode_raw < binary_file.bin

Получаем список словарей:

1 {
  1: "e341_26007177W202222O32631623332600A"
  2: "320242321203320260320273320265321202320275320260321217 320261321203320274320260320263320260 Familia Plus, 2 321201320273320276321217, 12 321200321203320273320276320275320276320262, 1 321203320277."
  3: "https://leonardo.edadeal.io/dyn/cr/catalyst/offers/u4nf6zbkjc3m5lss46ucvxjafm.jpg"
  4: 0x43ad7eb8
  5: 0x4347e666
  7: ";5332^c2121346204237RT002026610"
  8: 0x41400000
  9: "321210321202"
  10: 0x422c0000
  11: "%"
  13: 43
  15: "2022-07-26T00:00:00Z"
  16: "2022-08-01T00:00:00Z"
  19: "A105L332nPg230342q3753133514336"
  20 {
    1: 0x3f800000
    2: 0x418547ae
    3: "321210321202"
    4: 1
  }
  21: "224331203202B3032134622431RT002026610"
  22: "K3202537{O271273374K351376224310*"
  22: "300336d(224kL25224300355256247327R35"
  22: "303O:202330262A32624623307D314F303G"
  22: "210"22?250|L.272375345{335c,26"
  22: "=3yP2604N33426737732036F326331\"
  22: "E21100246e6EI22300)2423348216M"
  22: "V#26322367324H350232r1310_KX273"
  23: "320232320276320273320270321207320265321201321202320262320276"
  24: 1
}

5 Формируем .proto файл

Используем номера из предыдущего пункта, по контенту из предыдущего пункта нужно догадаться, какие поля, что означают (например 3 — это ссылка на изображение продукта)

Методом проб и ошибок получаем следующую структуру:

syntax = "proto2";

message Offers {
  repeated Offer offer = 1;
}

message Offer {
  optional string name = 2;
  optional string image_url = 3;
  optional float price_before = 4;
  optional float price_after = 5;
  optional float amount = 8;
  optional float discount = 10;
  optional string start_date = 15;
  optional string end_date = 16;
}

4 Переходим к написанию кода

Создаем питоновский файл с описанием структуры из .proto файла

protoc --proto_path=proto_files --python_out=proto_structs offers.proto

proto_files — имя директории с .proto файлами

proto_structs — в этой директории сохраняются результаты (_pb2.py файлы)

Код работает следующим образом:

  1. Делает запрос к API сайта
  2. Преобразует ответ сайта в json
  3. Выводит результат
import json
import requests

from google.protobuf.json_format import MessageToJson
from proto_structs import offers_pb2

def parse_page(city = "moskva", shop = "5ka", page_num = 1):
    """
    :param city: location of the shop
    :param shop: shop name
    :param page_num: parsed page number
    :return: None
    """
    url = f"https://squark.edadeal.ru/web/search/offers?count=30&locality={city}&page={page_num}&retailer={shop}"
    data = requests.get(url, allow_redirects=True)  # data.content is a protobuf message

    offers = offers_pb2.Offers()  # protobuf structure
    offers.ParseFromString(data.content)  # parse binary data
    products: str = MessageToJson(offers)  # convert protobuf message to json
    products = json.loads(products)
    print(json.dumps(products, indent=4, ensure_ascii=False,))

if __name__ == "__main__":
    parse_page()

Результат работы программы — список продуктов с описанием

{
    "offer": [
        {
            "name": "Наггетсы, куриные с ветчиной, Мираторг, 300 г",
            "imageUrl": "https://leonardo.edadeal.io/dyn/cr/catalyst/offers/necnmkv43splbm3hr5636snpry.jpg",
            "priceBefore": 218.99000549316406,
            "priceAfter": 109.48999786376953,
            "amount": 300.0,
            "discount": 51.0,
            "startDate": "2022-08-02T00:00:00Z",
            "endDate": "2022-08-08T00:00:00Z"
        },
        ...

5 Сравним результаты

Время выполнения кода из предыдущего пункта 0.3 — 0.4 секунды

Альтернативный вариант парсинга — загрузка всего html-кода страницы и извлечения нужной информации из этого кода

from selenium import webdriver

driver = webdriver.Chrome()
driver.get("https://edadeal.ru/moskva/retailers/5ka")
# извлечение данных из html кода

Время полной загрузки страницы 5 — 6 секунд.

6 Выводы

Лучше использовать API сайта для извлечения данных, если есть такая возможность

Использование API сайта позволяет не зависеть от измений в html-коде страниы



Source link

Добавить комментарий