понедельник, 28 марта 2016 г.

Веб поиск на Go. Краулер. Как не скачать лишнего

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

Лучшая страница, эта та, которую мы так и не запросили. На каждом сайте есть служебные страницы, на которых вы вряд ли найдёте полезный контент. При должном трудолюбии админов, они выносят ссылки на него в robots.txt. Следовать правилам описанным в нём считается за правило хорошего тона для ботов. Так же это возможность избежать ненужного трафика и уменьшенный риск быть забаненным. На форумах пишут, что одним из способов вычислить бота - дать невидимую для пользователя ссылку, которая запрещена в robots.txt. Поисковые боты yandex, google и т.п. не пойдут по ней, а вот самописные - могут. Для Go есть замечательная библиотека robotstxt-go, которая возьмёт обработку этого файла на себя, так что причин не следовать robots.txt не остаётся.

Не всегда запрещённые к индексированию ссылки выносят в robots.txt, часто это любят делать в теле страницы. Для этого существуют специальные метатеги, в которых могут запретить индексировать текущую страницу или запретить переходить по ссылкам внутри этой страницы. Часть ссылок закрывают от индексирования атрибутом rel у тега "a" со значением "nofollow".

Следующий рубеж обороны - анализ кода состояния в ответе сервера. Успешным можно считать по сути только 200-й код, другие 2xx ответы в моей практике не встречались. Несколько подряд идущих ошибок 5xx зачастую говорят о том, что у сервера сработала защита от DDoS атаки и стоит временно прекратить обращаться к нему, иначе следующим этапом будет блокировка нашего IP. Если анализировать код до того, как вы скачали тело ответа - можно сэкономить ресурсы себе и веб-серверу.

Ещё один фильтр до непосредственного скачивания тела ответа - анализ заголовков. В частности в "Content-Type" помимо кодировки хранится информация о типе ответа. Это так называемые MIME-типы, их много, но нужен чаще всего всего один - "text/html". Это поможет вам избавиться от необходимости, например, скачивать архив PDF с сайта xakep.ru. Последний, кстати, забанил мой IP на пару часов после того, как я это сделал. Получить из "Content-Type" тип MIME можно при помощи стандартной библиотеки mime.

Я анализировал другие заголовки в ответе сервера. Например, большие надежды были на заголовок "Expires" и прочие отвечающие за кеширование страницы. Ожидалось, что если сервер говорит не кешировать или ставит маленькое время устаревания кеша, то на странице нет постоянного контента и это страница из серии "топ постов за неделю" или нечто подобное. Но в большинстве своём, подобные заголовки устанавливаются чуть ли не случайным образом и сильной корреляции обнаружить не удалось.

После скачивания страницы, перед тем, как положить её в базу, неплохо проверить, что полученный HTML валидный. Хотя на топовых сайтах редко встречаются страницы с поломанным HTML, но всё же это случается. Ещё нужно учитывать, что парсер HTML в Go всеядный и легко съест часть HTML или допустим XML. Например мне попадались вот такие страницы - этакий кусок HTML выдернутого из середины реального документа. Или например rss с заголовком в ответе "Content-Type"="text/html", хотя должно было быть "application/rss+xml". Отсеять такие страницы не сложно - пробуем распарсить начало страницы, если не находим тег "html", значит страницу в БД не сохраняем.

На этом пожалуй закончу, ссылка на референсную реализацию на Go приведу в конце цикла статей по краулеру.

Комментариев нет:

Отправить комментарий