API для всех и каждого: создаем мощный парсер веб-сайтов без единой строки кода
Часто возникает задача периодически парсить какой-нибудь сайт на наличие новой информации. Например, если ты пишешь агрегатор контента с новостного сайта или форума, в котором нет поддержки RSS. Проще всего написать cкрепер на Питоне и разобрать полученный HTML через beautifulsoup или регулярками. Однако есть более элегантный способ — самому сделать недостающие API для сайта и получать ответы в привычном JSON, как будто бы у сайта есть нативный API.
Не будем далеко ходить за примером и напишем парсер контента с «Хакера». Как ты знаешь, сайт нашего журнала сейчас не предоставляет никакого API для программного получeния статей, кроме RSS. Однако RSS не всегда удобен, да и выдает далеко не всю нужную информацию. Исправим это!
Постановка задачи
Итак, наша задача: сделать API вида GET /posts
, который бы отдавал десять последних статей с «Хакера» в JSON. Также нам нужно иметь возможность задавать сдвиг, то есть раз за разом получать следующие десять постов.
GET /posts
Ответ должен быть таким:
{ "posts": [ { title: "Американская компания захватила командный сервер хакеров из Ирана", excerpt: "Компания Palo Alto Networks сумела вывести из строя командные серверы, которые в течение девяти лет использовала группа хакеров из Ирана.", date: "2 часа назад" url: "https://xakep.ru/2016/06/30/iran-sinkhole/", image: "https://xakep.ru/wp-content/uploads/2016/06/Ahmadinejad-visit-to-Natanz-w-computers-712x400.jpg" }, { title: "Американская компания захватила командный сервер хакеров из Ирана", excerpt: "", date: "" url: "", image: "" }, ... ] }
Также нужно иметь возможность получать следующие десять постов — со второй страницы, третьей и так далее. Это делается через GET-параметр вида GET /posts?page=2
. Если page
в запросе не указан, считаем его равным 1
и отдаем посты с первой страницы «Хакера». В общем, задача ясна, переходим к решению.
Фреймворк для веба
WrapAPI — это довольно новый (пара месяцев от роду) сервис для построения мощных кастомных парсеров веба и предоставления к ним доступа по API. Не пугайся, если ничего не понял, сейчас поясню на пальцах. Работает так:
- Указываешь WrapAPI страницу, которую нужно парсить (в нашем случае главную «Хакера» — https://xakep.ru/).
- Говоришь, с какими параметрами обращаться к серверу, каким HTTP-методом (GET или POST), какие query-параметры передавать, какие POST-параметры в body, куки, хедеры. Короче, все, что нужно, чтобы сервер вернул тебе нормальную страничку и ничего не заподозрил.
- Указываешь WrapAPI, где на полученной странице ценный контент, который надо вытащить, в каком виде его представлять.
- Пoлучаешь готовый URL для API вида
GET /posts
, который вернет тебе все выдранные с главной «Хакера» посты в удобном JSON!
Немного о приватности запросов
Ты наверняка уже задумался о том, насколько безопасно использовать чужой сервис и передавать ему параметры своих запросов с приватными данными. Тем более что по умолчанию для каждого нового API-проекта будет создаваться публичный репозиторий и запускать API из него сможет любой желающий. Не все так плохо:
- Каждый API-репозиторий (а соответственно, и все API-запросы в нем) можно сделать приватным. Они не будут показываться в общем списке уже созданных API на платформе WrapAPI. Просто выбери достаточно сложное имя репозитория, и шанс, что на него кто-то забредет случайно, сведется к минимуму.
- Любой запрос к WrapAPI требует специального токена, который нужно получить в своей учетке WrapAPI. То есть просто так узнать URL к твоему репозиторию и таскать через него данные не получится. Токены подразделяются на два типа: серверные и клиентские, для использования прямо на веб-страничке через JavaScript. Для последних нужно указать домен, с которого будут поступать запросы.
- Ну и наконец, в скором времени разработчик обещает выпустить self-hosted версию WrapAPI, которую ты сможешь поставить на свой сервер и забыть о проблеме утечек данных (конечно, при условии, что в коде WrapAPI не будет бэкдоров).
Приготовления
Несколько простых шагов перед началом.
- Идем на сайт WrapAPI, создаем новую учетку и логинимся в нее.
- Устанавливаем расширение для Chrome (подойдет любой Chromium-based браузер), открываем консоль разработчика и видим новую вкладку
WrapAPI
. - Переходим на нее и логинимся.
Это расширение нам понадобится для того, чтобы перехватывать запросы, которые мы собираемся эмулировать, и быстро направлять их в WrapAPI для дальнейшей работы. По логике работы это расширение очень похоже на связку Burp Proxy + Burp Intruder.
Для работы с WrapAPI нужно повторно авторизоваться еще и в расширении в консоли разработчика Chrome
Отлавливаем запросы
Теперь нужно указать WrapAPI, какой HTTP-запрос мы будем использовать для построения нашего API. Идем на сайт «Хакера» и открываем консоль разработчика, переключившись на вкладку WrapAPI.
Для получения постов я предлагаю использовать запрос пагинации, он доступен без авторизации и может отдавать по десять постов для любой страницы «Хакера», возвращая HTML в объекте JSON (см. ниже).
Запросы, которые генерятся по нажатию на ссылки пагинатора, будем использовать как образец
Чтобы WrapAPI начал перехватывать запросы, нажми Start capturing requests и после этого выполни целевой запрос (на пагинацию). Плагин поймает POST-запрос к странице https://xakep.ru/wp-admin/admin-ajax.php
с кучей form/urlencoded-параметров в теле, в том числе и номером страницы. Ответом на запрос будет JSON-объект с параметром content
, содержащий закешированный HTML-код с новыми постами. Собственно, этот блок и нужно парсить WrapAPI.
Запрос пойман, сохраняем его на сервер WrapAPI
Конфигурируем WrapAPI
После того как ты выбрал нужное имя для твоего репозитория (я взял test001 и endpoint posts
) и сохранил его на сервер WrapAPI через расширение для Chrome, иди на сайт WrapAPI и открывай репозиторий. Самое время настраивать наш API.
Обзор нашего будущего API
Переходи на вкладку Inputs and request. Здесь нам понадобится указать, с какими параметрами WrapAPI должен парсить запрашиваемую страницу, чтобы сервер отдал ему валидный ответ.
Конфигурируем входные параметры запроса
Аккуратно перебей все параметры из пойманной WrapAPI полезной нагрузки (POST body payload) в поле слева. Для всех параметров, кроме paginated
, выставь тип Constant
. Это означает, что в запросы к серверу будут поставляться предопределенные значения, управлять которыми мы не сможем (нам это и не нужно). А вот для paginated
выставляй Variable API
, указав имя page
. Это позволит нам потом обращаться к нашему API по URL вида GET /posts?page=5
(с query-параметром page
), а на сервер уже будет уходить полноценный POST со всеми перечисленными параметрами.
Заголовки запроса ниже можно не трогать, я использовал стандартные из Chromium. Если парсишь не «Хакер», а данные с какого-нибудь закрытого сервера, можешь подставить туда нужные куки, хедеры, basic-auth и все, что нужно. Одним словом, ты сможешь настроить свой запрос так, чтобы сервер безо всяких подозрений отдал тебе контент.
Выставляем необходимые POST-параметры в формате form/urlencoded, чтобы наш запрос отработал правильно
Учим WrapAPI недостающим фичам
Теперь нужно указать WrapAPI, как обрабатывать полученный результат и в каком виде его представлять. Переходи на следующую вкладку — Outputs and response.
Извини, но продолжение статьи доступно только подписчикам
Подписка позволит тебе читать ВСЕ платные материалы сайта, включая эту статью, без каких-либо ограничений. Мы принимаем банковские карты, Яндекс.Деньги и оплату со счетов мобильных операторов. Подробнее о проекте
1 год3400 Р Экономия 1400 рублей! |
1 месяц400 Р |
Уже подписан?
Читайте также
- Ошибка в API Facebook предоставляла доступ к фото 6,8 млн пользователей
- Одного ноутбука оказалось достаточно для компрометации всей корпоративной сети
- Депутаты Госдумы разработали план по обеспечению работы Рунета на случай отключения от Сети
- Морские суда часто подвергаются кибератакам
- 25 декабря состоится встреча сообщества специалистов по кибербезопасности АСУ ТП / RUSCADASEC
- Уязвимость в приложении Logitech позволяла удаленно инициировать нажатие клавиш