Blog. Just Blog

Парсер REFERER'ов с поисковых систем

Версия для печати Добавить в Избранное Отправить на E-Mail | Категория: Web-мастеру и не только | Автор: ManHunter
Обработка заголовка HTTP referer является одной из важных задач при раскрутке сайта и сборе статистики. По нему можно определить, какие ресурсы ссылаются на ваш сайт. Но особую ценность представляют данные посещений с поисковых систем, так как эта информация позволяет наиболее четко определить, по каким ключевым словам ваш сайт может быть найден, а также проанализировать эффективность поисковой оптимизации вашего ресурса. Если вы пользуетесь сторонними счетчиками посещений, то эту информацию они обычно предоставляют сами. В некоторых случаях такие данные предоставляют серверные системы статистики типа Webalizer. Я принципиально не пользуюсь ни тем, ни другим, обрабатываю все данные самостоятельно. Для этого была написана функция обработки рефереров, которую я использую в своих проектах. Данные поискового запроса обычно передаются методом GET и содержатся в строке браузера, но основная проблема в том, что кодировка этих данных может быть разной даже в пределах одной и той же поисковой системы. Как выяснилось, не везде доступна штатная функция PHP is_unicode(), поэтому для подстраховки пришлось написать свою. Проверка выполняется согласно правилам формирования Юникода.
  1. // Функция проверки является ли переменная строкой в Юникоде 
  2. // Если штатная функция не определена, то применить нашу
  3. if (!function_exists('is_unicode')) {
  4.   function is_unicode($str) {
  5.     for ($i=0$i<strlen($str); $i++) {
  6.       // Если символ с кодом больше 191, то возможно это юникод
  7.       if (ord($str[$i])>191) {
  8.         // Следующий символ должен быть в интервале
  9.         // 10000000b ... 10111111b (128...191)
  10.         if (ord($str[($i+1)])<128 || ord($str[($i+1)])>191) {
  11.           // Условие не выполнено, значит это не юникод
  12.           return false;
  13.         }
  14.         else {
  15.           // Пропускаем один байт, т.к. он является частью символа
  16.           $i++;
  17.         }
  18.       }
  19.     }
  20.     // Проверка пройдена, это юникод
  21.     return true;
  22.   }
  23. }
Теперь, когда мы можем четко определить кодировку строки запроса, нам необходимо выделить ее из строки URL. Для этого достаточно выполнить в интересуемом поисковике любой запрос и посмотреть как формируется ссылка.

Если сервер настроен правильно, то поле реферера обычно доступно в переменных окружения через функцию getenv() или через суперглобальные массивы $_ENV и $_SERVER. Готовая функция разбора реферера у меня получилась следующей:
  1. // Функция разбора поля REFERER
  2. function parse_refer($refer) {
  3.   // База данных поисковых систем
  4.   $search_engines=Array(
  5.     Array("name"=>"Картинки.Mail""pattern"=>"go.mail.ru/search_images""param"=>"q="),
  6.     Array("name"=>"Mail""pattern"=>"go.mail.ru""param"=>"q="),
  7.     Array("name"=>"Google Images""pattern"=>"images.google.""param"=>"q="),
  8.     Array("name"=>"Google""pattern"=>"google.""param"=>"q="),
  9.     Array("name"=>"Google""pattern"=>"google.""param"=>"as_q="),
  10.     Array("name"=>"Live Search""pattern"=>"search.live.com""param"=>"q="),
  11.     Array("name"=>"RapidShare Search Engine""pattern"=>"rapidshare-search-engine""param"=>"s="),
  12.     Array("name"=>"Rambler""pattern"=>"rambler.ru""param"=>"query="),
  13.     Array("name"=>"Rambler""pattern"=>"rambler.ru""param"=>"words="),
  14.     Array("name"=>"Yahoo!""pattern"=>"search.yahoo.com""param"=>"p="),
  15.     Array("name"=>"Nigma""pattern"=>"nigma.ru/index.php""param"=>"s="),
  16.     Array("name"=>"Nigma""pattern"=>"nigma.ru/index.php""param"=>"q="),
  17.     Array("name"=>"MSN""pattern"=>"search.msn.com/results""param"=>"q="),
  18.     Array("name"=>"Ask""pattern"=>"ask.com/web""param"=>"q="),
  19.     Array("name"=>"QIP""pattern"=>"search.qip.ru/search""param"=>"query="),
  20.     Array("name"=>"RapidAll""pattern"=>"rapidall.com/search.php""param"=>"query="),
  21.     Array("name"=>"Яндекс.Картинки""pattern"=>"images.yandex.ru/""param"=>"text="),
  22.     Array("name"=>"Яндекс.Mobile""pattern"=>"m.yandex.ru/search""param"=>"query="),
  23.     Array("name"=>"Яндекс""pattern"=>"hghltd.yandex.net""param"=>"text="),
  24.     Array("name"=>"Яндекс""pattern"=>"yandex.ru""param"=>"text=")
  25.   );
  26.  
  27.   // Отрезать от ссылки "хвост"
  28.   $tmp=explode("?",$refer);
  29.   $chk_site=$tmp[0];  // Имя сайта
  30.   // Разобрать "хвост" на отдельные параметры
  31.   $params=split("&",implode("&",$tmp));
  32.  
  33.   $result_engine="";
  34.   $result_title=$refer;
  35.   for ($i=0$i<count($params); $i++) {
  36.     // Параметр пустой, пропустить
  37.     if ($params[$i]=="") { continue; }
  38.     foreach ($search_engines as $engine) {
  39.       // Поиск по всем сигнатурам
  40.       if (strpos($chk_site,$engine['pattern']) && substr($params[$i],0,strlen($engine['param']))==$engine['param']) {
  41.         // Сигнатура найдена
  42.         $result_title=substr($params[$i],strlen($engine['param']));
  43.         $result_engine=$engine['name'];
  44.         break;
  45.       }
  46.     }
  47.   }
  48.  
  49.   if ($result_engine!="") {
  50.     // Привести строку в текстовый вид
  51.     $str=trim(urldecode($result_title));
  52.     // Если строка в юникоде, то перевести ее в кодировку win1251
  53.     if (is_unicode($str)) {
  54.       $str=iconv("utf-8","windows-1251",$str);
  55.     }
  56.     if ($str!="") {
  57.       // Сформировать строку "Имя поисковой системы: запрос"
  58.       $result=$result_engine.": ".$str;
  59.     }
  60.     // Пустой поисковый запрос
  61.     else {
  62.       $result="";
  63.     }
  64.   }
  65.   else {
  66.     $result="";
  67.   }
  68.   return $result;
  69. }
На выходе получаем строку типа "Google: парсер ссылки на php" в кодировке win1251, или пустую строку, если реферер разобрать и опознать не удалось. Пример использования:
  1. $refer=trim(getenv('HTTP_REFERER'));
  2. $engine=parse_refer($refer);
  3. // Дальше выполняются какие-то действия, например запись в базу
Базу поисковиков, известных функции, можно легко пополнять по уже имеющимся образцам. Параметр name - название поисковой системы, pattern - сигнатура, которая однозначно должна присутствовать в имени домена поисковика и param - сигнатура строки, после которой начинается текст поискового запроса. При использовании функции не забывайте проверять, чтобы в обработку не попадали внутрисайтовые рефереры.

Поделиться ссылкой ВКонтакте
Просмотров: 23833 | Комментариев: 27

Метки: PHP, SEO
Внимание! Статья опубликована больше года назад, информация могла устареть!

Комментарии

Отзывы посетителей сайта о статье
ManHunter (03.04.2015 в 22:17):
Ну какой год-то был. Все течет, все изменяется.
Дмитрий (03.04.2015 в 22:12):
А вот так, кстати, работает тоже не плохо: mb_convert_encoding() … проверка у вас злая
ManHunter (05.09.2014 в 18:06):
Гуглояндексами дело не ограничивается, есть же всякие mail, rambler, nigma и т.п. Не так много, но скрипт на них до сих пор прекрасно работает. Да и гугл с яндексом в статистике изредка проскакивает.
Роман Петрович (05.09.2014 в 18:04):
усё закрыли лавочку, посковики больше не отдают поисковый запрос в реферере
ManHunter (28.08.2012 в 11:48):
Напиши быстрее, выше, сильнее. А пока из всего говна я тут вижу только тебя.
шкодер (28.08.2012 в 11:47):
скрипт парсера полное говно. совершенно не оптимизирован с точки зрения быстродействия
Alex (07.06.2012 в 02:11):
Как раз то, что искал. Спасибо. Отличный блог!
M@k][SiMk0 (29.04.2012 в 11:55):
можно просто резать ссылку реферера и выделять имя домена
а можно и юзать сигнатуры

$referer = $_SERVER['HTTP_REFERER']; // узнаем рефера
$url_referer = str_replace("http://", "", $referer); // удаляем http:// перед ссылкой
list($domen, $domen2, $domen3, $domen4) = explode("/", $url_referer;); // разбиваем на масив то что перед каждым / слешем
echo $url_referer; // выводим нужный нам отрезок текста - в данном случае тоупо адрес домена
ManHunter (30.09.2011 в 14:39):
Кроме сигнатур надо еще много чего добавлять, так что здесь халявы не будет.
Riller (15.09.2011 в 15:23):
А скажите пожалуйста, новые сигнатуры для определения появились или нет? Если появились просьба выложить их здесь.
Kola (18.05.2011 в 13:35):
for ($i=0; $i<count($params); $i++)

Этот цикл можно начинать с единички, хотя так ошибки никакой. И спасибо за скрипт, оказался полезным.
QQq (09.02.2011 в 20:14):
огромное спасибо за парсер!
Алексей (07.07.2010 в 16:55):
Огромное Вам спасибо! Как просто и ясно все получилось.
Vasek (26.05.2010 в 20:34):
Появилась ли более свежая версия парсера?
ManHunter (16.02.2010 в 06:56):
По той же причине, по которой я не пользуюсь готовыми фреймворками, jquery, вордпрессами и прочим. Все, что я в состоянии написать сам - я обязательно напишу сам.
sharovatov (15.02.2010 в 23:34):
а почему Вы принципиально не пользуетесь системами вроде awstats/webalizer?
ManHunter (05.10.2009 в 18:06):
Есть такое дело, я уже штук пять разных сигнатур для всяких гуглов добавил.
Александр (05.10.2009 в 17:54):
Кстати, недавно обратил внимание, что реферер с images.google.ru и images.google.com отличаются тем, как передается поисковая фраза. Если при переходе с images.google.ru через GET передается параметр "q", то при переходе с com текст запроса запрятан уже в "prev", т.е. там приходится еще произвести дополнительный парсинг и urldecode.
ManHunter (18.07.2009 в 09:25):
Очень неудачная аналогия. Но спорить не собираюсь.
Василий (18.07.2009 в 08:06):
Значит программы ломать и закодированные скрипты вскрывать - это по честному, а накрутить счетчик у сайта это преступление? Чушь собачья.
ManHunter (16.07.2009 в 19:42):
Ты явно ошибся сайтом с такими вопросами. Если не можешь продвигать сайты по-честному, то здесь тебе делать нечего.
Василий (16.07.2009 в 19:26):
А как сделать чтобы скрыть свой REFERER при раскрутке сайта (при накрутке) или заменять его каждый раз на разные данные?
ManHunter (10.07.2009 в 14:01):
Идешь и читаешь:
http://ru2.php.net/manual/ru/r...lesystem.php
Сергей (10.07.2009 в 13:58):
Подскажите пожалуйста как результат записывать в файл. Пожалуйста, а то я новичек в этом деле.
Den (20.04.2009 в 05:14):
function utf8_to_cp1251($text)
{
  $encoded_data = mb_convert_encoding($text, 'Windows-1251', 'UTF-8');
  $data = (mb_detect_encoding($str, "auto", true) == '') ? $text : $encoded_data;
  return $data;
}
ManHunter (22.02.2009 в 04:22):
Kulesh, зачем мне тут лекция по программированию? Попробуй выполнить свой код на такой строке:

$str=iconv("windows-1251","utf-8","хуй") ."хуй";

Фактически результирующая строка $str НЕ является юникодом, но при этом пройдет твою проверку и не пройдет мою. Причину объяснять надо или сам найдешь свою ошибку? И использование тернарного оператора при одном условии - дурной тон. Разверни свой код, посмотри что он выполняет:

if (iconv("utf-8","windows-1251",$str)=="") {
  $str=$str;
}
else {
  $str=iconv("utf-8","windows-1251",$str);
}

Не многовато ли лишних движений в виде ненужного присваивания и двойного вызова одной и той же функции?
Kulesh (21.02.2009 в 16:40):
is_unicode не везде работает
Я приминил более, как я считаю, быстрый способ избежать её использования.
Вместо куска кода:
    if (is_unicode($str)) {
      $str=iconv("utf-8","windows-1251",$str);
    }
можно воткнуть:
$str = iconv("utf-8","windows-1251",$str)==''?$str:iconv( "utf-8","windows-1251",$str);

Здесь используется тернарный оператор, он должен быть знаком всем, кто имел дело с С-подобным языком. Поскольку такой оператор всего один. Это условный оператор, предназначеный для выбора одного из двух значений в зависимости от третьего:
$a?$b:$c
выражение примет значение $b, если $a имеет значение true, и получает значение $c, если $a имеет значение false.

Добавить комментарий

Заполните форму для добавления комментария
Имя*:
Текст комментария (не более 2000 символов)*:

*Все поля обязательны для заполнения.
Комментарии, содержащие рекламу, ненормативную лексику, оскорбления и т.п., а также флуд и сообщения не по теме, будут удаляться. Нарушителям может быть заблокирован доступ к сайту.
Наверх
Powered by PCL's Speckled Band Engine 0.2 RC3
© ManHunter / PCL, 2008-2024
При использовании материалов ссылка на сайт обязательна
Время генерации: 0.11 сек. / MySQL: 2 (0.0057 сек.) / Память: 4.5 Mb
Наверх