image
Для целого ряда приложений, связанных с мониторингом интернет-ресурсов и сбором статистики, актуальна задача поиска текстовой информации в сети. Для чего именно это может пригодится и как это сделать?

Если интересно, то Добро пожаловать под кат!

Яркими примерами являются задачи копирайтинга, поиск заимствований, утечек документов, в конце концов. Нужен ли для этого свой краулер или можно воспользоваться поисковиками? В ходе решения этого вопроса возникла идея написать “краулер для краулера”, другими словами, сбор данных с поисковиков по заданному запросу.

Первый резонный вопрос: почему не использовать штатное API поисковика? Если мы используем только один поисковик, то можно и API, но для этого надо будет следить за его изменениями и править свой код. Мы же решили сделать универсальный механизм: заменив XPath в настройках, можно настроиться на работу с любыми поисковыми системами (но не ограничиваться ими). Разумеется, пришлось предусмотреть работу со списком прокси, чтобы, во-первых, не забанили, а, во-вторых, чтобы можно было получать поисковую выдачу для разных регионов (по geoIP используемого прокси).

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



Схема работы приложения предельно проста: интерфейс взаимодействия с системой реализован на flask, на вход которого ожидается запрос формата JSON-RPC, имеющий следующий вид:

requests.post('http://127.0.0.1:5000/social', json={
   "jsonrpc":"2.0",
   'id':123,
   'method':'initialize',
   'params':{
      'settings':{
         'searcher':'<твой любимый поисковик>',
         'search_q':[
            'why people hate php'
         ],
         'count':1
      }
   }
})

Далее инициализируется задача в очереди RabbitMQ. Когда приходит её очередь выполнения, модуль обработки задач принимает её в разработку. При выполнении процесса предоставляется актуальный proxy, создается эмулятор работы браузера.

Для чего же нам использовать ту злосчастную эмуляцию, а не использовать всеми любимый requests? Ответ прост:

  • для решения проблемы с динамически подгружаемым контентом;
  • притворяться ужом (пользователем с реальным браузером) для отсрочки блокировки прокси.

Для этого и используется selenium webdriver, который позволяет нам получить страницу в том виде в котором ее получает пользователь в своем браузере (со всеми отработавшими скриптами и проверками), и, в случае необходимости, дает возможность имитировать действия на странице, к примеру, для получения следующей порции данных.

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

Как только желаемая страница нами получена, дело остается за малым и его с радостью выполнит parser (с использованием сконструированного нами конфига, содержащего Xpath необходимых элементов), который, в свою очередь, отправит интересующую нас информацию в MongoDB.
На каждом этапе выполнения в Redis указывается статус обработки задачи, основываясь на ее id.

Рассмотрим возможные проблемы, с которыми мы можем столкнуться:

  1. Реклама в выдаче — зашумляет данные, раздувает базу;
  2. Сайты могут подгружать контент динамически, например, при прокручивании страницы;
  3. Капча — ну здесь всё очевидно.

Если же сайт маскирует рекламу среди полезного контента, то нам на помощь приходит firefox webdriver + adblock + selenium. Однако, в случае поисковиков, реклама достаточно просто выявляется при помощи XPATH и убирается из выдачи.

Итак, капча — наш злейший враг.
Распознавать её — задача нетривиальная и требует значительных ресурсов для реализации. Значит будем искать путь обхода.

И нами он был найден! Для этого мы и будем использовать прокси. Как оказалось, большая часть прокси, находящихся в открытом доступе, не позволяет обойти нашего оппонента (так как уже давно скисли и забанены), ситуация с платными прокси обстоит немного лучше, но тоже не идеальна (и все-таки дает нам лучик света в темном царстве).

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

Также можно использовать антикапча сервис, но это уже совсем другая история…

Как результат мы получили архитектуру и прототип системы, позволяющую производить сбор данных с поисковых и других источников.
Спасибо за внимание.

Комментарии (11)


  1. kruslan
    26.10.2017 12:15

    Вместо прокси лучше тор.


    1. mixamax Автор
      26.10.2017 12:30

      Пробовали. Тор быстро блокировался. Да и скорость тора несколько ниже.


      1. kruslan
        26.10.2017 15:58

        Ну у нас обратный опыт ;)


  1. dernasherbrezon
    26.10.2017 12:42

    Схема работы приложения предельно проста

    RabbitMQ, Consul и две базы данных не выглядит простым.


    Ладно, Consul еще понятно — наверное используется для масштабирования.
    Но зачем две почти одинаковые базы? Зачем RabbitMQ?


    1. mixamax Автор
      26.10.2017 12:56

      RabbitMQ — очередь тасков на случай, если нагрузка по запросам возрастёт. В MongoDB хранятся данные по скачанным результатам, в то время как Redis используется как кеш для сохранения статусов обратки.


      1. dernasherbrezon
        26.10.2017 17:49

        Вы ответили на вопрос "что они делают?", но не "зачем они там?".


        1. mixamax Автор
          26.10.2017 22:53

          Про rabbit написано выше. Redis используется, чтобы не дёргать лишний раз основную БД. Конечно, можно всё реализовать через MongoDB в т.ч. и очередь, но лучше использовать инструменты, предназначенные для этих целей.


  1. ilyaplot
    26.10.2017 14:12

    включение таймаута на его использование, запросы должны идти с некоторой задержкой

    Были в моей практике серверы, которые выдавали бан на основе анализа таймаута между запросами. Теперь я всегда устанавливаю рандомный таймаут.
    Еще один прием — обязательно передаю HTTP referer. В больщинстве случаев он должен быть известен, но я не думаю, что кто-то заморачивался с проверками его корректности. Он просто должен быть.
    Так же, я встречал системы, которые используют mousmove для проверки на ботов. Приходилось эмулировать запросы подобных скриптов на сервер, которые отрабатывали в течение 10-20 секунд после скачивания страницы.


    1. mixamax Автор
      26.10.2017 15:13

      Про рандомный таймаут — да, это полезное дополнение. Если говорить про заголовки HTTP, тот тут уже не только referer, лучше на этапе анализа ресурсов изучить запросы и передаваемые хедеры. В некоторых случаях оказывается, что требуется нечто большее…
      Анализ поведения пользователя на сайте (mousemove и подобные) по большей части появляется в задачах связанных с накруткой активности/просмотров. В этом случае надо уже придумывать более сложные механизмы и сценарии поведения, но это уже другая задача.


  1. vtulin
    27.10.2017 17:30

    Наверное правильнее всё же назвать «Парсер для краулера», он же у вас не убегает за пределы поисковиков. Или я не догнал? Вон тот «Spider» в центре это кто такой?


    1. mixamax Автор
      27.10.2017 22:51

      На текущий момент не убегает, в дальнейшем предполагается нарастить этот функционал. Тот «Spider», который в центре отвечает за переход между страницами выдачи и скачивание их.