Как вытащить api с сайта
Перейти к содержимому

Как вытащить api с сайта

Я хочу стянуть информацию с сайта. Как это сделать?

Допустим, нам нужно получить данные с сайта, сбор которых вручную нецелесообразен или невозможен из-за объёма. В таком случае мы можем автоматизировать процесс, используя инструменты, описанные далее.

Библиотека requests

Python-библиотека для выполнения запросов к серверу и обработки ответов. Фундамент скрипта для парсинга и наше основное оружие. Пользуясь данной библиотекой мы получаем содержимое страницы в виде html для дальнейшего парсинга.

import requests response = requests.get('https://ya.ru') # get-запрос print(response.text) # вывод содержимого страницы payload = 'key1': 'value1', 'key2': 'value2'> response = requests.get('http://httpbin.org/get', params=payload) # запрос с параметрами headers = 'user-agent': 'my-app/0.0.1'> response = requests.get(url, headers=headers) # запрос с определенными html заголовками 

API

Application programming interface — программный интерфейс приложения, предоставляемый владельцем веб-приложения для других разработчиков. Отсутствие API, способного удовлетворить наши нужды — первое в чем стоит убедиться прежде чем бросаться анализировать исходный код страницы и писать для нее парсер. Множество популярных сайтов имеет собственное api и документацию, которая объясняет как им пользоваться. Мы можем использовать api таким образом — формируем http-запрос согласно документации, и получаем ответ при помощи requests.

BS4

Beautifulsoup4 — это библиотека для парсинга html и xml документов. Позволяет получить доступ напрямую к содержимому любых тегов в html.

from bs4 import BeautifulSoup soup = BeautifulSoup(raw_html, 'html.parser') print(soup.find("p", class_="some-class").text) # вывод содержимого тэга 'p' классом 'some-class' 

Selenium Web Driver

Данные на сайте могут генерироваться динамически при помощи javascript. В таком случае спарсить эти данные силами requests+bs4 не удастся. Дело в том, что bs4 парсит исходный код страницы, не исполняя js. Для исполнения js кода и получения страницы, идентичной той, которую мы видим в браузере, можно использовать selenium web driver — это набор драйверов для различных браузеров, снабжающийся библиотеками для работы с этими драйверами.

А что делать, если там авторизация?

Предварительно авторизоваться, отправив post-запрос и инициировать сессию:

session = requests.Session() data = "login_username":"login", "login_password":"password"> url = "http://site.com/login.php" response = session.post(url, data=data) 

А что, если сайт банит за много запросов?

  • Установить задержку между запросами:
response = requests.get(url, timeout=(10, 0.01)) # таймаут на соединения, таймаут на чтение (в секундах) 
  • Притвориться браузером, используя selenium web driver или передав содержимое заголовка user-agent, формируя запрос:
user_agent = ('Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:50.0) ' 'Gecko/20100101 Firefox/50.0') request = requests.get(url, headers='User-Agent':user_agent>) 
  • Использовать прокси:
request = requests.get(url, proxies="http":"http://10.10.1.10:3128">) 

Попробуйте бесплатные уроки по Python

Получите крутое код-ревью от практикующих программистов с разбором ошибок и рекомендациями, на что обратить внимание — бесплатно.

Переходите на страницу учебных модулей «Девмана» и выбирайте тему.

Как можно получить скрытый API сайта

Response html странички

Суть: парсер циан. Нашёл API циан, но там передаются не все данные. Решил не трогать API и парсить саму страничку, но прокси быстро улетают в бан, хотя задержка большая стоит. После этого решил покопаться в консоли разработчика и увидел в Response следующую картину: Как я понял скрипт //cdn.cian.site/frontend/header-frontend/main.289cc52627b5bd8057f8.js генерирует страничку и делает XMLHttpRequest запросы внутри. Как мне определить и взять API из этого файла? Изменять я его не могу т.к. он сервере. Буду очень благодарен за ответ.

Отслеживать
задан 31 янв 2022 в 14:18
65 7 7 бронзовых знаков

1 ответ 1

Сортировка: Сброс на вариант по умолчанию

Никак. Это все живёт в рамках сессии. Сгенерился токен, с ним вот такой js запросы вне этого js работать не будут.

Я Апи маркета юзал через проки. При бане прокси она автоматом улетала в валгаллу. Но надо постоянно подкидывать прокси в топку

Отслеживать
ответ дан 31 янв 2022 в 14:40
Yuriy Belalov Yuriy Belalov
79 2 2 бронзовых знака

  • javascript
  • python
  • парсер
  • api
  • rest
    Важное на Мете
Похожие

Подписаться на ленту

Лента вопроса

Для подписки на ленту скопируйте и вставьте эту ссылку в вашу программу для чтения RSS.

Дизайн сайта / логотип © 2023 Stack Exchange Inc; пользовательские материалы лицензированы в соответствии с CC BY-SA . rev 2023.11.29.1725

Нажимая «Принять все файлы cookie» вы соглашаетесь, что Stack Exchange может хранить файлы cookie на вашем устройстве и раскрывать информацию в соответствии с нашей Политикой в отношении файлов cookie.

Как использовать API сайта, у которого нет API?

У меня достаточно часто появляется задача получить данные от стороннего сайта, при этом далеко не всегда этот сайт предоставляет возможность удобно получить эти данные через API. Единственное решение в таком случае — парсить html содержимое страниц. Когда-то я писал регэкспы, потом появились библиотеки, позволяющие получить нужное содержимое по css-селектору, а сейчас и это кажется сложной задачей, которую хотелось бы упростить.

Сегодня я хочу рассказать вам о моей небольшой библиотеке, позволяющей описать в API-стиле http-запросы и парсить ответ сервера в нужный вам формат.

Примечание: не стоит забывать об авторских правах, если вы используете чужие данные.

Установка

Библиотека доступна к установке через composer, поэтому все, что необходимо сделать — это добавить зависимость «sleeping-owl/apist»: «1.*» в ваш composer.json и вызвать composer update.

У данной библиотеки нет зависимостей от каких-либо фреймворков, поэтому вы можете использовать ее с любым фреймворком, либо же в чистом PHP-проекте. Для сетевых запросов используется Guzzle, для манипуляций с dom-деревом используется «symfony/dom-crawler».

Использование

После установки вы можете приступить к созданию нового класса, олицетворяющего API нужного вам сайта. Библиотека не накладывает никаких ограничений на то, как и где вы будете создавать свой класс. Нужно расширить класс SleepingOwl\Apist\Apist и указать базовый урл:

use SleepingOwl\Apist\Apist; class HabrApi extends Apist < protected $baseUrl = 'http://habrahabr.ru'; >

Это все, что нужно для базового описания. Далее вы можете добавлять в данный класс методы, которые вам нужны:

public function index() < return $this->get('/', [ 'title' => Apist::filter('.page_head .title')->text()->trim(), 'posts' => Apist::filter('.posts .post')->each([ 'title' => Apist::filter('h1.title a')->text(), 'link' => Apist::filter('h1.title a')->attr('href'), 'hubs' => Apist::filter('.hubs a')->each(Apist::filter('*')->text()), 'author' => [ 'username' => Apist::filter('.author a'), 'profile_link' => Apist::filter('.author a')->attr('href'), 'rating' => Apist::filter('.author .rating')->text() ] ]) ]); > 

Здесь метод «get» — это тип используемого http-запроса, также доступны остальные методы (post, put, patch, delete и т.д.).
Первый параметр — урл данного метода, он может быть как относительным, так и абсолютным.
Второй параметр — это и есть та основа, из-за которой я создал эту библиотеку. Он описывает структуру, которую необходимо получить в результате вызова данного метода. Это может быть как массив, так и одиночное значение. То есть для описанного выше метода результат будет такого вида:

$api = new HabrApi; $result = $api->index(); 

Примечание: результат будет типа array, json-формат здесь использован для удобства.

Третьим опциональным параметром могут идти любые дополнительные параметры запроса, get или post переменные, загружаемые файлы, заголовки запроса и т.п. С полным списком можно ознакомиться в документации Guzzle.

Создание фильтров

Пара слов о том, как это работает: каждый объект, созданный через Apist::filter($cssSelector) после загрузки данных заменяется на нужное значение, он сохраняет не только сам селектор, по которому он будет искать данные, но и всю вереницу вызовов, которые к нему были применены. После загрузки данных он пытается применить эти методы к найденным элементам.

    Методы класса Symfony\Component\DomCrawler\Crawler для перемещения по dom-дереву и получению данных:

Apist::filter('.navbar li')->eq(3)->filter('a.active')->text(); Apist::filter('input')->first()->attr('value'); Apist::filter('.content')->html(); 
Apist::filter('body')->element(); // Вернет объект класса Symfony\Component\DomCrawler\Crawler, отвечающий за элемент body Apist::filter('.post')->each(. ); // Этот объект будет заменен на массив, каждый элемент которого будет создан согласно схеме, которая была передана параметром. Все внутренние css-селекторы будут применены относительно текущего элемента. Apist::filter('.errors')->exists()->then(. )->else(. ); // Описывает условие, если элемент с классом "errors" был найден, то используется значение из блока "then", иначе из блока "else" 
Apist::filter('.title')->text()->mb_strtoupper()->trim()->substr(5); function myFunc($string, $find, $replace) < return str_replace($find, $replace, $string); >Apist::filter('.title')->text()->myFunc('My', 'Your'); // Если убрать ->text(), то в функцию будет передан объект, а не строка. Это можно использовать в своих целях при необходимости. 

Upd: в версии 1.2.0 добавилась возможность инициализировать апи из yaml файла, подробнее можно посмотреть в документации.

Как спарсить любой сайт?

Меня зовут Даниил Охлопков, и я расскажу про свой подход к написанию скриптов, извлекающих данные из интернета: с чего начать, куда смотреть и что использовать.

Написав тонну парсеров, я придумал алгоритм действий, который не только минимизирует затраченное время на разработку, но и увеличивает их живучесть, робастность, масштабируемость.

TL;DR

Чтобы спарсить данные с вебсайта, пробуйте подходы именно в таком порядке:

  1. Найдите официальное API,
  2. Найдите XHR запросы в консоли разработчика вашего браузера,
  3. Найдите сырые JSON в html странице,
  4. Отрендерите код страницы через автоматизацию браузера,
  5. Если ничего не подошло — пишите парсеры HTML кода.

Совет профессионалов: не начинайте с BS4/Scrapy

BeautifulSoup4 и Scrapy — популярные инструменты парсинга HTML страниц (и не только!) для Python.

Крутые вебсайты с крутыми продактами делают тонну A/B тестов, чтобы повышать конверсии, вовлеченности и другие бизнес-метрики. Для нас это значит одно: элементы на вебстранице будут меняться и переставляться. В идеальном мире, наш написанный парсер не должен требовать доработки каждую неделю из-за изменений на сайте.

Приходим к выводу, что не надо извлекать данные из HTML тегов раньше времени: разметка страницы может сильно поменяться, а CSS-селекторы и XPath могут не помочь. Используйте другие методы, о которых ниже. ⬇️

Используйте официальный API

�� Ого? Это не очевидно ��? Конечно, очевидно! Но сколько раз было: сидите пилите парсер сайта, а потом БАЦ — нашли поддержку древней RSS-ленты, обширный sitemap.xml или другие интерфейсы для разработчиков. Становится обидно, что поленились и потратили время не туда. Даже если API платный, иногда дешевле договориться с владельцами сайта, чем тратить время на разработку и поддержку.

Sitemap.xml — список страниц сайта, которые точно нужно проиндексировать гуглу. Полезно, если нужно найти все объекты на сайте. Пример: http://techcrunch.com/sitemap.xml

RSS-лента — API, который выдает вам последние посты или новости с сайта. Было раньше популярно, сейчас все реже, но где-то еще есть! Пример: https://habr.com/ru/rss/hubs/all/

Поищите XHR запросы в консоли разработчика

Кабина моего самолета

Все современные вебсайты (но не в дарк вебе, лол) используют Javascript, чтобы догружать данные с бекенда. Это позволяет сайтам открываться плавно и скачивать контент постепенно после получения структуры страницы (HTML, скелетон страницы).

Обычно, эти данные запрашиваются джаваскриптом через простые GET/POST запросы. А значит, можно подсмотреть эти запросы, их параметры и заголовки — а потом повторить их у себя в коде! Это делается через консоль разработчика вашего браузера (developer tools).

В итоге, даже не имея официального API, можно воспользоваться красивым и удобным закрытым API. ☺️

Даже если фронт поменяется полностью, этот API с большой вероятностью будет работать. Да, добавятся новые поля, да, возможно, некоторые данные уберут из выдачи. Но структура ответа останется, а значит, ваш парсер почти не изменится.

Алгорим действий такой:

Кнопка, которую я искал месяцы

  1. Открывайте вебстраницу, которую хотите спарсить
  2. Правой кнопкой -> Inspect (или открыть dev tools как на скрине выше)
  3. Открывайте вкладку Network и кликайте на фильтр XHR запросов
  4. Обновляйте страницу, чтобы в логах стали появляться запросы
  5. Найдите запрос, который запрашивает данные, которые вам нужны
  6. Копируйте запрос как cURL и переносите его в свой язык программирования для дальнейшей автоматизации.

Вы заметите, что иногда эти XHR запросы включают в себя огромные строки — токены, куки, сессии, которые генерируются фронтендом или бекендом. Не тратьте время на ревёрс фронта, чтобы научить свой парсер генерировать их тоже.

Вместо этого попробуйте просто скопипастить и захардкодить их в своем парсере: очень часто эти строчки валидны 7-30 дней, что может быть окей для ваших задач, а иногда и вообще несколько лет. Или поищите другие XHR запросы, в ответе которых бекенд присылает эти строчки на фронт (обычно это происходит в момент логина на сайт). Если не получилось и без куки/сессий никак, — советую переходить на автоматизацию браузера (Selenium, Puppeteer, Splash — Headless browsers) — об этом ниже.

Поищите JSON в HTML коде страницы

Как было удобно с XHR запросами, да? Ощущение, что ты используешь официальное API. �� Приходит много данных, ты все сохраняешь в базу. Ты счастлив. Ты бог парсинга.

Но тут надо парсить другой сайт, а там нет нужных GET/POST запросов! Ну вот нет и все. И ты думаешь: неужели расчехлять XPath/CSS-selectors? ��‍♀️ Нет! ��‍♂️

Чтобы страница хорошо проиндексировалась поисковиками, необходимо, чтобы в HTML коде уже содержалась вся полезная информация: поисковики не рендерят Javascript, довольствуясь только HTML. А значит, где-то в коде должны быть все данные.

Современные SSR-движки (server-side-rendering) оставляют внизу страницы JSON со всеми данные, добавленный бекендом при генерации страницы. Стоп, это же и есть ответ API, который нам нужен! ������

Вот несколько примеров, где такой клад может быть зарыт (не баньте, плиз):

Красивый JSON на главной странице Habr.com. Почти официальный API! Надеюсь, меня не забанят.И наш любимый (у парсеров) Linkedin!

Алгоритм действий такой:

  1. В dev tools берете самый первый запрос, где браузер запрашивает HTML страницу (не код текущий уже отрендеренной страницы, а именно ответ GET запроса).
  2. Внизу ищите длинную длинную строчку с данными.
  3. Если нашли — повторяете у себя в парсере этот GET запрос страницы (без рендеринга headless браузерами). Просто requests.get .
  4. Вырезаете JSON из HTML любыми костылямии (я использую html.find(«= <") ).

Отрендерите JS через Headless Browsers

Если XHR запросы требуют актуальных tokens, sessions, cookies. Если вы нарываетесь на защиту Cloudflare. Если вам обязательно нужно логиниться на сайте. Если вы просто решили рендерить все, что движется загружается, чтобы минимизировать вероятность бана. Во всех случаях — добро пожаловать в мир автоматизации браузеров!

Если коротко, то есть инструменты, которые позволяют управлять браузером: открывать страницы, вводить текст, скроллить, кликать. Конечно же, это все было сделано для того, чтобы автоматизировать тесты веб интерфейса. I’m something of a web QA myself.

После того, как вы открыли страницу, чуть подождали (пока JS сделает все свои 100500 запросов), можно смотреть на HTML страницу опять и поискать там тот заветный JSON со всеми данными.

driver.get(url_to_open) html = driver.page_source
Selenoid — open-source remote Selenium cluster

Для масштабируемости и простоты, я советую использовать удалённые браузерные кластеры (remote Selenium grid).

Недавно я нашел офигенный опенсорсный микросервис Selenoid, который по факту позволяет вам запускать браузеры не у себя на компе, а на удаленном сервере, подключаясь к нему по API. Несмотря на то, что Support team у них состоит из токсичных разработчиков, их микросервис довольно просто развернуть (советую это делать под VPN, так как по умолчанию никакой authentication в сервис не встроено). Я запускаю их сервис через DigitalOcean 1-Click apps: 1 клик — и у вас уже создался сервер, на котором настроен и запущен кластер Headless браузеров, готовых запускать джаваскрипт!

Вот так я подключаюсь к Selenoid из своего кода: по факту нужно просто указать адрес запущенного Selenoid, но я еще зачем-то передаю кучу параметров бразеру, вдруг вы тоже захотите. На выходе этой функции у меня обычный Selenium driver, который я использую также, как если бы я запускал браузер локально (через файлик chromedriver).

def get_selenoid_driver( enable_vnc=False, browser_name="firefox" ): capabilities = < "browserName": browser_name, "version": "", "enableVNC": enable_vnc, "enableVideo": False, "screenResolution": "1280x1024x24", "sessionTimeout": "3m", # Someone used these params too, let's have them as well "goog:chromeOptions": , "prefs": < "credentials_enable_service": False, "profile.password_manager_enabled": False >, > driver = webdriver.Remote( command_executor=SELENOID_URL, desired_capabilities=capabilities, ) driver.implicitly_wait(10) # wait for the page load no matter what if enable_vnc: print(f"You can view VNC here: ") return driver

Заметьте фложок enableVNC . Верно, вы сможете смотреть видосик с тем, что происходит на удалённом браузере. Всегда приятно наблюдать, как ваш скрипт самостоятельно логинится в Linkedin: он такой молодой, но уже хочет познакомиться с крутыми разработчиками.

Парсите HTML теги

Мой единственный совет: постараться минимизировать число фильтров и условий, чтобы меньше переобучаться на текущей структуре HTML страницы, которая может измениться в следующем A/B тесте.

Даниил Охлопков — Data Lead @ Runa Capital

Подписывайтесь на мой Телеграм канал, где я рассказываю свои истории из парсинга и сливаю датасеты.

Надеюсь, что-то из этого было полезно! Я считаю, что в парсинге важно, с чего ты начинаешь. С чего начать — я рассказал, а дальше ваш ход ��

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *