PHP

Парсинг: ищем все ссылки во всех скриптах

Недавно я писал пост про регулярные выражения в PHP, но вот реально начал клепать seo-checer и решил задаться вопросом: как определить количество ссылок в JavaScript. По началу вполне банальная задача оказалась весьма сложной штукой, требующей очень большого мыслительного напряга и php-кода.

Итак, допустим, вот наш скрипт ресурса bigmir. net (bigmir)net TOP 100):
<script type="text/javascript" language="javascript"></script>

Предполагаемые действия.

Для начала предположим, что отпарсенных скриптов много и мы не знаем в каких что находится, поэтому, будем предполагать разные варианты. Для того, чтобы узнать классификатор извлекаемых ссылок, мы не можем просто удалить лишний код - почистить нашу переменную, содержащую все скрипты для ее дальнейшей обработки по маскам: class="" и style="". В дальнейшем мы постараемся определить классификатор ссылки по типам: 1 - noindex; 2 - nofollow; 3 - inside; 4 - outside; 5 - hide. Здесь тип 3 и 4 означают внутренние и внешние ссылки, т.е. ведут на этот же самый сайд или на внешний (чужой); тип 5 означает "скрытность" ссылки, когда ссылки физически есть на сайте, но визуально они не отображаются на мониторе, обычно для этого используют 2 html-тега: "display:none" и "visibility:hidden". Разница между двумя тегами, скрывающими ссылки от пользователя является полное удаление с экрана ("display:none") и удаление с "бронированием места, которое отображается "пустым ("visibility:hidden").

1. Загружаем нужную страницу из сети (обработку правильности адреса ресурса опущу):
$html = file_get_contents($site_url);

2. Все скрипты присвоить переменной-массиву $scripts[$i]:
$p = "'|<\s*script[^>]*>(.*)<\s*/\s*script\s*>|i'";
preg_match_all($p,$html,$links_in_script);

3. Все скрипты (массивы) присвоим одной переменной, которая будет хранить весь нужный нам текст одной текстовой строкой:
$html_script_list = implode('',$links_in_script[0]);

Если содержимое переменной нужно вывести на экран (например, убедиться в ее правильности, заполненности), то ее следует перевести в html-код:
$html_script_list_echo = htmlspecialchars($html_script_list);

4. Теперь из переменной $html_script_list удалим весь мусор, который нам поможет искать наши ссылки:
$html_script_list = str_replace($del1,'',$html_script_list);
$html_script_list = str_replace($del2,'',$html_script_list);

Массив всех левых символов нужно подобрать в кучу, предположительно это:

- Все скобки, хотя, есть вероятность, что в якоре они могут использоваться: ( ) { } .
- html-коды невидимые: "& nbsp ;" - пробел.
- Символы комментариев в html-коде: "< ! - -" и "- - >".
- Спецкомманды (кодовые слова) скриптов: "www.", "var " и др.
- html-теги (пустые и заполненные), например, часто ставят для валидации кода на картинки пустые альты (alt="").
$del1 = array('(',')','{','}',' ','','www.','var ');

$del2 = array('style=""','class=""','id=""','alt=""','title=""');

$del3 = array('document.write','function ');

Во многих скриптах встречается частенько запись, не характерная для использования в ссылках как адресе, так и титуле ( ?"Y":"N" ):

- (navigator.javaEnabled()?"Y":"N")
- (document.cookie?"Y":"N")

Основная поверхностная чистка готова, теперь можно найти все ссылки, имеющиеся в теле скриптов сайта:
preg_match_all('|<\s*\\?/\s*a\s*>|,smi',$html_script_list,$links_in_script);

Здесь "smi" означает следующее:
- "s" и "m" - искать текст по маске, в которой нет любых пробелов (пробелов, табов) и нет энтеров (перевод каретки на новую строку, обозначается в html-коде как "\n").
- "i" - искать в любом регистре, т.е. <_a_> или <_A_>.

Данная маска "<\s*\\?/\s*a\s*>" позволит найти разные концовки ссылок, что даст абсолютно верное количество ссылок в яваскриптах анализируемой страницы сайта:

1: </a>
2: < /a>
3: </ a>
4: </a >
5: < / a>
6: < /a >
7: </ a >
8: < / a >

а также

1: <\/a>
2: < \/a>
3: < \ /a>
4: <\/ a>
5: <\ / a>
6: <\/a >
7: <\/a >
8: < \/ a>
8: < \ / a>
9: < \/a >
10: < \ /a >
11: <\/ a >
12: <\ / a >
13: < \/ a >
14: < \ / a >

и др.

\s - означает один пробел, таб, интер;
\s* - любое количество пробелов.

К сожалению, дальнейшие действия по поиску ссылок сводятся к обычным поискам нужных типов ссылок для их дальнейшей классификации, поэтому, никаких гарантий точности определения нет.

Теперь поищем закрытые от поисковика Гугл ссылки с "nofollow":
$p = "'|<\s*a\s*^[nofollow]nofollow|,i'";
preg_match_all($p,$html_script_list,$links_in_script_nofollow);

Теперь поищем закрытые от поисковика Яндекс ссылки с "noindex":
$p = "'|<\s*\\?/\s*a\s*>\s*<\s*/\s*noindex\s*>|,i'";
preg_match_all($p,$html_script_list,$links_in_script_nofollow);

Получил интересный вариант у себя при старом дедовском методе научного тыка:

1. |<\s*\\?/\s*a\s*>| - не работает.
2. |<\s*[\\]?/\s*a\s*>| - не работает.
3. |<\s*[\\?]/\s*a\s*>| - не работает.
4. |<[\s]*[\\]?/[\s]*a[\s]*>| - не работает.
... все подобные комбинации не работают. sad
5. |<[\s]*[.]?/[\s]*a[\s]*>| - работает (и почему-то только так), выдает концовку ссылки: "" или "<\/a>".

Парсим количество ссылок и получаем несколько проблем.
1. Есть два варианта подсчета количества ссылок на странице: подсчет начала ссылки (<_a_>), тела и концовки (). Эти три показателя всегда будут разными на сложных страницах с множеством скриптов, поэтому я для себя решил сделать два варианта: посчитать количество начал ссылок и концовок:
preg_match_all('|<[\s]*[\\]?/[\s]*a[\s]*>|i',$html,$result_tags_links_all_end);
preg_match_all('|<[\s]*a[\s]*(?:title\s*=\s*[\'"]?[.]*[\'"]?)?[\s]*[^>]*>.*<[\s]*[\\]?/[\s]*a[\s]*>|i',$html,$result_tags_links_all_full);

Обратите внимание, нужно обязательно добавить условие "(?:title\s*=\s*[\'"]?[.]*[\'"]?)?", которое мало кто добавляет, поэтому в разных счетчиках показывается разное количество ссылок. Здесь (?smile обозначает искать, но не сохранять в массив найденное для экономии памяти сервера. Нужно оно для того, если кто-то решит вставить какой-нибудь хитрый символ в титул ссылки, тогда она не засчитается. Но если угодно, можно простым дедовским методом вытащить начало ссылки: "<\s*a\s[^>]*>".

Выведем результат:
echo $links_in_script_nofollow = count($links_in_script_nofollow[0]);
echo $links_in_script_noindex = count($links_in_script_noindex[0]);

Обратите внимание: протокол передачи данных не указан (http://), т.к. их очень много, можно поставить любой.
Добавлено: 24 Августа 2013 11:25:13 Добавил: Андрей Ковальчук Нравится 0
Добавить
Комментарии:
Нету комментариев для вывода...