Очень часто перед веб-мастерам встает задача парсинга выдачи поисковиков.
Это может быть нужно для того, чтобы:
- автоматизировать процесс обработки какой-то статистической информации;
- посчитать количество ссылающихся на ваш сайт ресурсов, определить их качество и прочие параметры;
- найти урлы сайтов, которые натырили у вас контент (хотя тут лучше использовать что-то наподобии CopyScape, однако я заметил, что он иногда выдает бред);
- определить частоту запросов.
И это лишь малый диапазон задач, в которых вам может понадобиться парсинг выдачи поисковиков. А точнее это то, что мне пришло в голову
А ведь еще у нас есть такие ребята как серые и черные оптимизаторы, которые при помощи поисковика ищут спамилки. Но это вообще отдельный разговор, который ничего общего с нашими благими целями не имеет
В данной статье я хотел бы рассказать как проще всего из выдачи Google доставать такие параметры как:
- время генерации ответа (может понадобиться для статистики и расчета общего времени парсинга);
- количество страниц, соответствующих вашему запросу (частота);
- ну и собственно ссылки на конечные ресурсы.
Реализовывать механизм получения выдачи вы можете на чем угодно: curl, сокеты, fopen. Особой разницы для нас между ними нет. Предположим, что получать содержимое выдачи вы уже умеете (а если не умеете, то читать дальше вам просто незачем).
И вот тут начинаются вопросы.
1. Как достать из выдачи время генерации и количество страниц на данный запрос?
Я делаю это таким кодом (выдрано из тучи моих классов и гигантского ядра парсера, так что если найдете какую-то ошибку - напишите в комментах):
$blue_line_pcre = "(Результаты|Результати|Results)(.*)";
$parse_time_pcre= '\<b\>([\d\,\.]+)\<\/b\>\s[^\d]+$';
$parse_num_pcre = '\<b\>([\d\,]+)\<\/b\>[^\d]+';
if(preg_match("/$blue_line_pcre/Ui",$Result,$matches)) {
unset($matches[0]);
if(!empty($matches[1])) {
$BlueLine=preg_replace("/\ \;/",'',$matches[2]);
} else {
$BlueLine='';
}
}
$find=$parse_num_pcre.$parse_time_pcre;
if(preg_match("/$find/Ui",$BlueLine,$matches)) {
unset($matches[0]);
$query_results_num=$matches[1];
$query_time=$matches[2];
}
То есть, предполагается, что в переменной $Result хранится html код выдачи (и очено важно к этому коду не забыть применить
$Result=preg_replace("/[\n\r\t]/", '', $Result);
, чтобы потом не ломать голову почему половина регулярок не работают).
После выполнения моего скрипта в переменной $BlueLine будет html код синей полоски Гугла, в которой будет написано, что-то на подобии “Результаты 1 - 10 из примерно 87 300 000 для вакансии. (0,04 секунд)”.
В переменной query_results_num будет количество сайтов, подходящих под ваш запрос, а в переменной query_time - время генерации выдачи.
Из кода выше вы могли заметить, что регулярное выражение для нахождения кода “синей линии” имеет следующий непонятный вид:
(Результаты|Результати|Results)(.*)
Это сделано исключительно для того, чтобы с равной точностью парсить выдачу как google.com, так и google.ru и google.com.ua.
Заметка: результаты выдачи по одному и тому же запросу на разных локализованных версиях Google отличаются! Хоть иногда эту разницу тяжело обнаружить, но все же она есть. Можете на досуге поиграться с каким-то ВЧ запросом. Расскажете о результатах своих наблюдений.
Также некоторые вопросы могут вызывать регулярные выражения для нахождения времени генерации и количества страниц:
$parse_time_pcre = '\<b\>([\d\,\.]+)\<\/b\>\s[^\d]+$';
$parse_num_pcre = '\<b\>([\d\,]+)\<\/b\>[^\d]+';
Для чего я использую вот такие конструкции [\d\,\.]? Исключительно для совместимости. Делаю я это потому, что разделителем целой и дробной части в нашей стране является “.”, а в США - “,”. В регулярном выражении для количества страниц вы также можете видеть символ “\,” - это используется для того, чтобы правильно находить количество страниц, так как американцы разделяют тысячи этим знаком.
2. Как достать ссылки из выдачи?
Эта даже проще чем выдирать параметры. Я делаю это при помощи следующего кода:
$find = $parse_links_pcre = "<a\shref=\"([^\"]+)\".*sclass=l";
if(preg_match_all("/$find/Ui",$Result,$matches)) {
unset($matches[0]);
$links=$matches[1];
}
В массиве $links будут все ссылки, найденный на текущей странице. Недостатки у такой унификации тоже есть: в результирующем массиве вы получите все ссылки “Translate” и этот метод не очень-то и быстро работает из-за использования в регулярном выражении “.*”. Но это место всегда можно подрихтовать под ваши конкретные требования. В оригинальном виде я тоже не особо часто использую данное регулярное выражение. Но есть также и плюсы у этого кода: он не загребает ссылки с оплаченных объявлений, а они, как вы знаете, вылазят на каждой странице поиска и могут очень сильно нарушить ваши статистические исследования или сбор ссылок.
Спасибо, что дочитали до конца. Рад буду выслушать ваши предложения и дополнения.