САЙТОСТРОЙ.РУ
Построй свой сайт!

Автоматизированный парсинг бирж, каталогов и онлайн-баз

опубликовано 27.12.2015

Бывает необходимо выгрузить данные с сайтов в виде файла-таблицы для дальнейшего анализа. Но, понятно, что вручную такие операции выполнять не хочется, а Web 2.0 не позволяет нам воспользоваться традиционными способами парсинга. Зачастую контент подгружается по мере или по запросу необходимости фоново и обычный разбор страниц, полученных через wget или file_get_contents оказывается уже бессилен.

В этой статье я расскажу о том, как, используя средства браузера, научиться эмитировать действия пользователя, чтобы собрать необходимый нам контент. В качестве инструмента я предлагаю использовать Mozilla Firefox, но, в принципе, можно справиться и в Google Chrome. В качестве примера я выбрал биржу статей Miralinks, а именно - каталог её площадок. Этот сайт не так давно сменил фронтенд-фреймворк и его интерфейс стал полностью динамическим, а значит, это будет прекрасной иллюстрацией, как добывать информация с "сайта будущего".

Итак, нас интересует каталог площадок. Для этого залогинимся и заходим в "Каталог площадок" (http://www.miralinks.ru/catalog):

каталог площадок Miralinks

Загрузилась сначала страница, а через некоторое время заполнилась и табличка. Данные из таблички загрузились отдельным запросом. Теперь давайте посмотрим, как именно выглядит этот запрос. Для этого в Firefox выберем пункт меню "Разработка" - "Инструменты разработки" - вкладка "Сеть". Здесь отображается исчерпывающая информация по запросам, выполняемым браузером. Нам необходимо перезагрузить страницу, чтобы зафиксировать запросы (отслеживание начинается после запуска инструмента). Последовали десятки обращений, в основном это картинки и JS-скрипты. Внимательно посмотрим и найдём POST-запрос с каким-нибудь говорящим названием и имеющим тип "json":

JSON-запрос для получения списка площадок Miralinks

Перейдём в правую часть вкладки "Сеть", выберем там вкладку "Параметры" и посмотрим, какие параметры запроса были переданы этому скрипту:

параметры Json-запроса к списку площадок Miralinks

Здесь множество различных параметров, но среди них есть 2, говорящие сами за себя: iDisplayStart и iDisplayLength. Первый очень похож на первую запись или страницу для отображения, а второй - на число запрашиваемых элементов.

Давайте проверим нашу догадку, нажав на номер страницы "2" в интерфейсе пользователя. Откроем параметры нового запроса к скрипту loadDataTableDataCatalog:

параметры второго запроса к ML на получение списка площадок

Да, если iDisplayLength = 20, то iDisplayStart у второй страницы будет тоже равен 20. Теперь можно попробовать поменять число элементов на страницу в интерфейсе пользователя (с 20 на 50). Мы увидим, что поменялся и параметр iDisplayLength.

Но можно ли запрашивать больше, чем 50 элементов на страницу, чтобы ускорить нашу выгрузку и обезопасить себя от бана? Давайте попробуем поменять этот параметр, благо Firefox позволяет нам сконструировать произвольный запрос на основе эталонного (в Chrome пока такого инструмента нет, именно этому я советовал Firefox). Для этого нажмём на запрос к loadDataTableDataCatalog в списке запросов и выберем в контекстном меню "Изменить и снова отправить":

Изменить и отправить снова запрос на получение параметров

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

редактирование параметров запроса к Miralinks

Здесь мы можем поменять параметр iDisplayLength (я выделил это место) и выполнить этот запрос, нажав кнопку "Отправить". Я поменяю его на 57 (число взял из уникальности).

Но посмотрим теперь на результаты, чтобы убедиться, что изменение параметра работает. Для этого после выполнения запроса в правой части инструмента откроем вкладку "Ответ" и увидим разобранный JSON-объект:

разобранный ответ от Miralinks в формате объекта

Я выделил массив aaData внутри полученного объекта. Это как раз массив, содержащий объекты найденных площадок. Их как раз получилось 57 - от 0 до 56. Если развернуть свойства этих объектов, то увидим, что внутри содержатся HTML-куски для отображения строк таблицы в интерфейсе пользователя, а так же параметры площадок в числовом/текстовом виде (объект rowData):

параметры площадок Miralinks в объекте JSON

Вот мы и добрались до нужных нам данных! На данном этапе мы можем перебирать параметры iDisplayStart и iDisplayLength, чтобы последовательно получить данные по всем площадкам, но это была бы ручная выгрузка данных, а нам ведь нужно автоматизировать процесс. Давайте сделаем это, воспользовавшись великолепным инструментом, присутствующим как в Firefox, так и в Chrome, а именно - конструктором curl-запросов. Для тех, кто не в курсе, curl - программа на *nix, которая позволяет совершать HTTP/HTTPS-запросы из консоли и обладает исчерпывающим списком параметров для этого. Firefox и Chrome позволяют из любого запроса браузер сформировать строку запуска утилиты curl, полностью аналогичную эталонному запросу.

Выберем наш запрос к loadDataTableDataCatalog и в контекстном меню выберем пункт "Копировать как curl":

Копировать запрос как cURL в Firefox

В буфере обмена окажется полностью готовая к использованию команда, которую можно выполнить в консоли на Вашем сервере (я сократил окончание):

user@webserver:~$ curl "http://www.miralinks.ru/ajaxPort/loadDataTableDataCatalog" -H "Host: www.miralinks.ru" -H "User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:43.0) Gecko/20100101 Firefox/43.0" ...
Вуаля! Запрос выполнится и на экран выведется закодированный в JSON, готовый к парсингу. Теперь остаётся выполнять этот запрос циклически, например, сохраняю в файл через перенаправление, а затем при помощи PHP-функции json_decode() разобрать их, сагрегировав данные.

Хочу обратить внимание, что всю черновую работы выполнил за нас Firefox и JSON. Первый подставил Cookie авторизованного пользователя, реальный User-Agent и Referer, переписал параметры запроса и прочие заголовки, которые делает реальный браузер. Curl же заботится о том, чтобы сформировать на основе заданных параметров корректный POST-запрос. Нам остаётся только менять параметры iDisplayStart и iDisplayLength.

Вот такой простенький скрипт получился у меня для дампинга данных с Miralinks (запрос снова сокращён - он должен быть полностью таким, как нам вернул в буфере обмена браузер):

<?php
$total = 11412;
$num_on_page = 100;
$iterations = ceil($total / $num_on_page);

for ($iteration = 0; $iteration < $iterations; $iteration++) {
  print "nnIteration #" . $iteration . "n";
  $start = $iteration * $num_on_page;
  $curl_req = 'curl "http://www.miralinks.ru/ajaxPort/loadDataTableDataCatalog" (...) > ' . $iteration . '.json';
  system($curl_req);
  sleep(rand(5,10));
}

Число итераций определяется на основе числа доступных площадок, через интерфейс пользователя биржи:

Отображения числа доступных площадок на бирже Miralinks

И между запросами я сделал произвольную задержку от 5 до 10 секунд, чтобы не нарваться на ограничительные барьеры биржи. Во всяком случае, так больше шансов не попасть в бан.

Второй скрипт декодирует полученные данные, аккумулируя их в единый выходной поток, который можно сохранить как CSV-файл (разделитель ";"):

<?php

function printRow($arr)
{
  foreach ($arr as &$arr_arr) {
   $arr_arr = "'" . $arr_arr . "'";
  }
  print implode(';', $arr) . "n";
}

for ($i = 0; $i < 108; $i++) {
  $json = json_decode(file_get_contents($i . ".json"), true);

  if (0 == $i) {
    printRow(array_keys($json['aaData'][0]['rowData']));
  }

  foreach ($json['aaData'] as $json_row) {
    printRow(array_values($json_row['rowData']));
  }
}

Число 108 здесь взято из общего количество получившихся файлов дампа. Как видите, и он очень простой. Хотя такое упрощение даёт не совсем корректный результат: если первые столбцы в порядке, то последние могут "гулять" у разных записей. Это связано с тем, что на самом деле объект rowData содержит различный набор свойств, а он у меня фиксирован по свойствам первого попавшегося объекта.

Отмечу, что схожий алгоритм парсинга можно использовать практически на любых сайтах, поскольку браузер даёт нам URL, который фактически совпадает с тем, что запрашивает браузер. Серверу сложно обнаружить какую-то подтасовку. Таким же образом, как с Miralinks, мне удалось спарсить и биржу WebArtex. Правда, там есть нюанс, заключающийся в том, что данные возвращаются только в виду HTML-кусков. Регулярные выражения использовать в данном случае несколько несовременно, логичнее использовать DOM-импорт и разбор в виде дерева XML-тегов. Об этом пойдёт речь в будущей статье.

О парсинге информера биржи Miralinks речь шла в одной из предыдущих статей. Этот способ работает до сих пор.

Комментарии и вопросы

Статью никто не комментировал.


Задать вопрос или оставить комментарий

Ваше имя:
Комментарий:
Код с картинки справа:=


Просим с уважением относиться к труду автора сайта и при копировании документов указывать ссылки на http://saytostroy.ru.