Для целого ряда приложений, связанных с мониторингом интернет-ресурсов и сбором статистики, актуальна задача поиска текстовой информации в сети. Для чего именно это может пригодится и как это сделать?
Если интересно, то Добро пожаловать под кат!
Яркими примерами являются задачи копирайтинга, поиск заимствований, утечек документов, в конце концов. Нужен ли для этого свой краулер или можно воспользоваться поисковиками? В ходе решения этого вопроса возникла идея написать “краулер для краулера”, другими словами, сбор данных с поисковиков по заданному запросу.
Первый резонный вопрос: почему не использовать штатное 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.
Рассмотрим возможные проблемы, с которыми мы можем столкнуться:
- Реклама в выдаче — зашумляет данные, раздувает базу;
- Сайты могут подгружать контент динамически, например, при прокручивании страницы;
- Капча — ну здесь всё очевидно.
Если же сайт маскирует рекламу среди полезного контента, то нам на помощь приходит firefox webdriver + adblock + selenium. Однако, в случае поисковиков, реклама достаточно просто выявляется при помощи XPATH и убирается из выдачи.
Итак, капча — наш злейший враг.
Распознавать её — задача нетривиальная и требует значительных ресурсов для реализации. Значит будем искать путь обхода.
И нами он был найден! Для этого мы и будем использовать прокси. Как оказалось, большая часть прокси, находящихся в открытом доступе, не позволяет обойти нашего оппонента (так как уже давно скисли и забанены), ситуация с платными прокси обстоит немного лучше, но тоже не идеальна (и все-таки дает нам лучик света в темном царстве).
Первая мысль — поиграться с user-agent. Экспериментальным путем выяснено, частая ротация user-agent лишь приближала прокси к преждевременной кончине (блокировку прокси поисковыми сервисами никто не отменял). Верным решением для продления жизни прокси оказалось включение таймаута на его использование, запросы должны идти с некоторой задержкой. Это, конечно, не панацея, но лучше, чем ничего.
Также можно использовать антикапча сервис, но это уже совсем другая история…
Как результат мы получили архитектуру и прототип системы, позволяющую производить сбор данных с поисковых и других источников.
Спасибо за внимание.
Автор: Михаил