Seoscan — анализ сайта
Решил наконец то основательно взяться за продвижение, ибо хочется почувствовать уже, что сайт создается не только для самоутверждения и собственного удовольствия, но и для общественности. Справедливости ради стоит отметить, что некоторая аудитория у сайта уже есть. По последним данным анализа логов посещаемость сайта составляет в среднем 160 уникальных посетителей в сутки. Это неплохой показатель, учитывая, что целенаправленного продвижения не осуществлялось, следовательно, объяснение может быть одно — тематичность статей. Анализ поисковых запросов показывает, что материал в блоге получается довольно таки уникальным, что подтверждает мою стратегию, согласно которой я публикую статьи на темы, которые практически не освещены в интернете. Прежде чем взяться за продвижение, я создал на сайте инструмент для оперативного анализа СЕО-состояния сайта, и нарек его SeoScan. Для чего же он мне понадобился…
… если в интернете полно такого добра? Во-первых, моя склонность к творчеству — люблю что-то сделать и потом пользоваться этим. Это дает ряд преимуществ, например, если пользуешься чужим продуктом, и чего-то тебе не хватает, то нельзя взять, и добавить это. В случае же со своим продуктом ты можешь делать что хочешь. Так же получилось и с SeoScan — я изучил несколько подобных сервисов, взял от них лучшие идеи, и реализовал в своем проекте. Во-вторых, при реализации получил много новых знаний и навыков. В-третьих, своему продукту все-таки как-то больше доверяешь — яркий пример: один из изучаемых сервисов показал, что мой домен присутствует в каталоге DMOZ, а это не так. Ну и в-четвертых — дополнительный полезный функционал на сайте (ознакомиться можно тут).
Что же полезного я узнал, разрабатывая сеоскан? Пришось основательно заняться парсингом всего и вся. В первую очередь это конечно касается отределения Google PR и Яндекс тИЦ. Начну со второго, поскольку яндекс оказался более демократичным в предоставлении данных. Все нужные данные можно получить через xml-интерфейс Яндекс-тулбара. Что-то удалось нагуглить, что-то отреверсить из того-же тулбара. В общем, код получения Яндекс-ТИЦ на php очень прост:
function getTCY($url) { $xml = $this->parent->getURL('http://bar-navig.yandex.ru/u?ver=2&show=32&url='.$url); return $xml ? (int) substr(strstr($xml, 'value="'), 7) : false; }
$this->parent->getURL — особенность моей ZendFramework реализации. На самом деле это функция из родительского класса для получения контента по указанному URL (о ней чуть ниже).
Не сложнее и функция получения Alexa Rank на php:
function getAlexaRank($url) { $file = $this->parent->getURL('http://data.alexa.com/data?cli=10&dat=snbamz&url='.$url); if (!$file) return false; return simplexml_load_string($file); }
Вот с GooglePR пришлось повозиться. Во-первых, гугл почему-то не хочет официально делиться своими данными. Алгоритм вычисления PageRank не документирован, поэтому честным программерам пришлось реверсить Google Toolbar, в результате чего удалось выяснить, что для того, чтобы получить страницу с кодом, нужно сформировать http-запрос, и помимо параметра с интересующим доменом передать некую контрольную сумму. Алгоритм отреверсили, и в сети его можно легко найти. Нашел, интегрировал, протестрировал — круто пашет… на домашнем тестовом сервере. Перенес на продакшн — не пашет. Стал искать. Выяснилось внезапно, что на проде оказывается 64-битная система (:. Таким образом, алгоритм подсчета контрольной суммы, расчитаный на 32x архитектуру, работает некорректно в связи с арифметическим переполнением. Снова принялся за поиски. Долго искал, много пробовал — все тщетно. В итоге все-таки удалось по крохам собрать 64-битную версию алгоритма определения Google PR для php. Вот она:
function strToNum($str, $check, $magic) { $int32Unit = 4294967296; // 2^32 $length = strlen($str); for ($i = 0; $i < $length; $i++) { $check *= $magic; /** * Если выпадаем за граници инта (обычно +/- 2.15e+9 = 2^31), то * получим undefined, читать ниже по ссылке: * http://www.php.net/manual/en/language.types.integer.php * потому танцуем с бубном */ if ($check >= $int32Unit) { $check = ($check - $int32Unit * (int) ($check / $int32Unit)); //if the check less than -2^31 $check = ($check < -2147483648) ? ($check + $int32Unit) : $check; } $check += ord($str{$i}); } return $check; } /** * Получаем хеш URL-а * @param string $string * @return integer */ function hashUrl($string) { $check1 = $this->strToNum($string, 0x1505, 0x21); $check2 = $this->strToNum($string, 0, 0x1003F); $check1 >>= 2; $check1 = (($check1 >> 4) & 0x3FFFFC0 ) | ($check1 & 0x3F); $check1 = (($check1 >> 4) & 0x3FFC00 ) | ($check1 & 0x3FF); $check1 = (($check1 >> 4) & 0x3C000 ) | ($check1 & 0x3FFF); $T1 = (((($check1 & 0x3C0) << 4) | ($check1 & 0x3C)) <<2 ) | ($check2 & 0xF0F ); $T2 = (((($check1 & 0xFFFFC000) << 4) | ($check1 & 0x3C00)) << 0xA) | ($check2 & 0xF0F0000 ); return ($T1 | $T2); } /** * Получаем чексум URL-а * @param integer $Hashnum хеш URL-а * @return integer */ function checkHash($hashNum) { $checkByte = 0; $flag = 0; $hashStr = sprintf('%u', $hashNum) ; $length = strlen($hashStr); for ($i = $length - 1; $i >= 0; $i --) { $re = $hashStr{$i}; if (1 === ($flag % 2)) { $re += $re; $re = (int)($re / 10) + ($re % 10); } $checkByte += $re; $flag ++; } $checkByte %= 10; if (0 !== $checkByte) { $checkByte = 10 - $checkByte; if (1 === ($flag % 2) ) { if (1 === ($checkByte % 2)) { $checkByte += 9; } $checkByte >>= 1; } } return '7' . $checkByte . $hashStr; } /** * Получаем PR с одного из сайтов гугла "закосив" под мозиллу * @param string $url URL страницы */ function getPageRank($url) { if ( ! preg_match('/^(http:\/\/)(.*)/i', $url)) { $url = 'http://' . $url; } $googlehost = 'toolbarqueries.google.com'; $googleua = 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.6) Gecko/20060728 Firefox/1.5'; $ch = $this->checkHash($this->hashUrl($url)); /** * Используя сокеты, вероятность бана снижается до 0, * темболее что едим только 30 первых символов ;) */ $fp = fsockopen($googlehost, 80, $errno, $errstr, 30); if ($fp) { $out = "GET /search?client=navclient-auto&ch=$ch&features=Rank&q=info:$url HTTP/1.1\r\n"; $out .= "User-Agent: $googleua\r\n"; $out .= "Host: $googlehost\r\n"; $out .= "Connection: Close\r\n\r\n"; fwrite($fp, $out); while ( ! feof($fp)) { $data = fgets($fp, 128); // ПР идёт в строке Rank_1:1:Х где Х наш ПР $pos = strpos($data, "Rank_"); if($pos === false){} else{ fclose($fp); $pr=substr($data, $pos + 9); $pr=trim($pr); $pr=str_replace("\n",'',$pr); return $pr ? $pr : '0'; } } fclose($fp); } }
Стыдно признаться, но я по сей день не приучил себя к использованию регулярных выражений, а ведь это МОЩЬ! Я четко осознаю факт. Чтобы устранить данный недостаток, необходима постоянная практика, поэтому парсинг данных в задаче СЕО-анализа — отличная возможность потренироваться в регулярках. Первая задача для регулярок — определение наличия сайта в каталогах DMOZ и YACA (яндекс-каталог).
function getDMOZ($domain) { $url='http://www.dmoz.org/search?q='.$domain; $xml = $this->parent->getURL($url); if (!$xml) return 'n/a'; $href = 'http://search.dmoz.org/cgi-bin/search?search='.$domain; $p=strpos($xml,'Open Directory Categories'); if ($p===false) $p=strpos($xml,'Open Directory Sites'); if ($p===false) return array('href'=>$href, 'txt' => "Нет"); $xml = substr($xml, $p, strlen($xml) - $p); $regex_pattern = "/(.*?)<\/a>/i"; preg_match_all($regex_pattern,$xml,$links); if (count($links[0])==0) return 'n/a'; $ar = explode(':', strip_tags($links[4][0])); return array('href'=>$href, 'txt' => $ar[count($ar)-2].':'.$ar[count($ar)-1]); }
Вообще, для парсинга html-документов существует очень мощное средство в php — класс DOMDocument. На продакшн-сервере этого класса не оказалось, пришлось его устанавливать из портов. Напомню, на проде у меня на данный момент стоит FreeBSD. Компиляция порта php5-dom завершалась с ошибкой
Error: shared library "Aiksaurus-1.2.0" does not exist
Долго гуглил, но безрезультатно. Но проблема сама не уйдет, поэтому решил спросить у FreeBSD-комьюнити. Прикольный форум, чувствуется профессиональный подход, модерация на высшем уровне, правят даже орфографические ошибки. В общем, посоветовали мне там обновить дерево портов. Это оказалось не очень сложно, все что нужно — утилита csup.
Что еще интересного? Пожалуй вот еще что. Попытавшись запустить анализ для сайта http://google.com наткнулся на то, что сервер вернул 301 Redirect — таким образом гугл перенаправляет пользователя на локализованую версию сайта для его региона (в нашем случае google.ru). Естетственно, никому не нужен анализ такого контента. Как же достичь целевой страницы? С помощью cURL это делается легко, нужно всего лишь добавить заголовок
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
Однако я стлокнулся с одним нюансом. Если в настройках php установлен safe_mode = On или переменная open_basedir, то опция CURLOPT_FOLLOWLOCATION не будет иметь эффекта. Что же тогда делать? Ответ прост — воспроизвести логику CURLOPT_FOLLOWLOCATION. Для этого нужно написать одну рекурсивную функцию. Вот она:
private $curl_loops = 0; private $curl_max_loops = 20; function curl_redir_exec($ch) { if ($this->curl_loops++ >= $this->curl_max_loops) { $this->curl_loops = 0; return FALSE; } curl_setopt($ch, CURLOPT_HEADER, true); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $data = curl_exec($ch); list($header, $data) = explode("\n\r", $data, 2); $this->http_hdr = explode("\n", $header); $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); if ($http_code == 301 || $http_code == 302) { $matches = array(); preg_match('/Location:(.*?)\n/', $header, $matches); $url = @parse_url(trim(array_pop($matches))); if (!$url) { //couldn't process the url to redirect to $this->curl_loops = 0; return $data; } $last_url = parse_url(curl_getinfo($ch, CURLINFO_EFFECTIVE_URL)); if (!$url['scheme']) $url['scheme'] = $last_url['scheme']; if (!$url['host']) $url['host'] = $last_url['host']; if (!$url['path']) $url['path'] = $last_url['path']; $new_url = $url['scheme'] . '://' . $url['host'] . $url['path'] . ($url['query']?'?'.$url['query']:''); $this->final_url = $new_url; curl_setopt($ch, CURLOPT_URL, $new_url); error_log('Redirecting to', $new_url); return $this->curl_redir_exec($ch); } else { $this->curl_loops=0; return $data; } } function getUrl($url) { $this->curl_loops = 0; $this->curl_max_loops = 20; $this->final_url = $url; $ch = curl_init($url); $cont = $this->curl_redir_exec($ch); curl_close($ch); return $cont; }
Интересно, а когда начнётся размещение на страницах блога контекстной либо иной рекламы….
Так сказать монетизация сайта….
Это хороший вопрос (:
Я думал об этом, и, в принципе, прихожу к выводу, что ничего уже сейчас не мешает этого делать. Аудитория какая-то есть, пусть случайная, но все же для контекстной рекламы должно хватить. В Яндекс-Директ пока рановато, ибо у них есть странная политика — в контекстной рекламной сети могут участвовать только сайты с посещаемостью не ниже 300 за последний месяц. У Google AdSense нет таких ограничений, поэтому можно начать с нее. Было бы прикольно, если контекстной рекламой хотя бы окупался хостинг.
Google AdSense это то что нужно сейчас.
Пора набить на этом деле руку, а за одно и нас просвятить, что да как.
В сети сейчас много различных статей на тему о монетизации и хочется проверить эту информацию на живом примере.
Может я ошибаюсь, но Ваша статья о тв программе произвела буквально фурор на блоге. Было очень много отзывов в том числе и от меня. Не хотите продолжить усовершенствовать этот скрипт? Пара предложений в отзывах прозвучало.
Хотелось бы почитать статьи в Вашем исполнении с примерами на тему о Яндекс.Картах Google.Map.
Хотя мне кажется было бы интересней о OpenStreetMap так сказать о свободной карте со свободной лицензией. А то эти монополисты, я про Яндекс, совсем уже зажрались и хотят прибрать всё к своим рукам.
Начал изучать современные методы продвижения (последний раз СЕО занимался года два назад), наткнулся на одну интересную идейку. Сейчас занимаюсь ее реализацией. Как закончу, напишу статью и после этого займусь интеграцией Google AdSense. Просто не могу себя остановить, когда делаю что-то творческое))
По поводу тв-скрипта… Да, можно развивать эту идею. Можно, например, оформить его, как плагин к разным популярным CMS (wordpress, drupal, joomla). Естественно, неплохо бы для начала облагородить по-всякому, например, добавить анонсы, да и вообще, причесать код. Извечная проблема — времени катастрофически не хватает…(((
Эх… в наш век информатизации существует столько интересных вещей, которыми хотелось бы заняться. Жаль, что нельзя разорваться))
Про геосервисы — несомненно интересная тема, я думаю, что у OpenStreetMap хорошие перспективы. Но лично у меня пока не возникает никаких идей по поводу того, что бы можно замутить полезного на сайте с использованием служб геолокации. По этому поводу только одна мысль мне недавно пришла в голову, во время поездки в Амстердам :)
заметил в в Вашем сео-анализаторе некоторое противоречие. он определяет тИЦ и GooglePR домена. для тИЦ это может быть и не критично — он присваивается всему домену, но для PageRank — весьма. PR расчитывается на конкретную страницу. так что, может быть имеет смысл над этим подумать…
да, пожалуй соглашусь. я думал об этом, когда проектировал, и даже оставил в коде возможность быстрого переключения на такое поведение. как протестирую, обновлю на продакшне. пожалуй, это нужно сделать во всех других видах анализа, где анализируется именно сама страница, а не домен.
Здравствуйте. А не могли бы Вы скинуть скрипт seoscan полностью. Заранее благодарен.