Парсинг страницы на PHP

Последнее время мне очень часто приходится парсить страницы разных сайтов. Когда я начинал изучать эту тему, то заметил, что есть 2 подхода к анализу контента страницы: анализ регулярными выражениями и с помощью phpQuery или simpleHtmlDOM. Будучи не сторонником использования чужих библиотек я выбрал 1ый путь.

 

Разбираемся в регулярках

 

Начнем с описания синтаксиса регулярных выражений.

 

Разберем простейший шаблон:

 

<(h1|h2|h3)><a href=”(.*?)”>(.*?)</a></(h1|h2|h3)>

 

( ) является подшаблоном знак | означает или, то есть подшаблон (h1|h2|h3) означает вхождение или h1, или h2, или h3. Точка в подшаблоне (.*?) обозначает любой символ. * - неограниченное количество совпадений. А ? оптимизирует и минимизирует, но об этом позже. Кроме того в preg_match этот подшаблон отвечает за искомый фрагмент текста.

 

В регулярных выражениях существует еще и другой тип шаблонов: #шаблон#

 

#a|z# означает вхождение a или z.

Совпадает в строках:

Abraham J. Simpson

go to the zoo

 

и не совпадает в строке

 

Home sweet home (нет ни a, ни z)

 

 

#ˆa# - символ находится в начале строки

#т$# - символ находится в конце строки

 

 

Можно также указать количество совпадений.

{ } - эти знаки в шаблоне обозначают сколько раз должно быть совпадение

? тоже самое, что и {0,1} - ноль или один раз
* тоже самое, что и {0, } - ноль или более раз

+ тоже самое, что и {1, } - один или более раз

 

первая цифра-минимальное количество совпадений, вторая — максимальное(если её нет, то бесконечное количество).

 

Кроме этого, классы символов можно обозначать так:
[[:alnum:]] - все алфавитно-цифровые символы [a-zA-Z0-9]
[[:alpha:]] - все алфавитные символы [a-zA-Z]
[[:blank:]] - символ табуляции и пробел [t ] 
[[:cntrl:]] - все управляющие символы
[[:digit:]] - все десятичные цифры [0-9]
[[:graph:]] - все печатные символы, за исключением пробела
[[:lower:]] - все строчные буквы [a-z]
[[:upper:]] - все прописные буквы [A-Z]
[[:print:]] - все печатные символы
[[:punct:]] - все знаки препинания [.,;:-.,;:-]
[[:space:]] - все пустые символы
[[:xdigit:]] - все шестнадцатиричные цифры

точка. — любой символ(- только точка).

 

Модификаторы:

ставятся после шаблона, например #шаблон#i

 

i - игнорировать регистр 
s - метасимвол '.' соответствует и символу n (перевод каретки), то есть классу [-xFF-xFF]
U - минимизировать числитель, то есть искать как можно меньше совпадений, похоже на действие ?.
m - претензии 'ˆ' и '$' учитывают [n]
D - претензия '$' не учитывает [n]
A - привязать шаблон к началу текста
x - разрешить комментарии: пробел и #
X - воспринимать неверную подстановку как ошибку.
- предварительная оптимизация шаблона
- используется в функции 'preg_replace' для ее активации

Регулярные выражения в действии

 

И так, немного разобравшись в теории, преступим к практике.

 

Решим легонькую задачку - найти все ссылки на странице:

 

 

$content=file_get_contents("http://7ion.ru");//берем страницу

$LinksArray=NULL;//тут будут ссылки

preg_match_all("/<a[[:print:]]href=["|'](.*?)["|'].*?>(.*?)<.{0,1}a.{0,1}>/i",$content,$LinksArray,PREG_PATTERN_ORDER);//применяем регулярку

var_dump($LinksArray);//выводим ссылки

 

 

Основой кода является выражение "/<a[[:print:]]href=["|'](.*?)["|'].*?>(.*?)<.{0,1}a.{0,1}>/i"

давайте разберем его:

 

первым делом ищем тег ссылки: <a[[:print:]]href=["|'](.*?)["|'].*?> нам нужен только url, но к сожалению обойтись выражением типа <a href=”(.*?)”> не удастся. Во-первых в теге могут присутствовать разного рода включения(типа style или onclick), от них избавляемся шаблоном [[:print:]], а во-вторых неизвестно какие кавычки будут ограничивать адрес(используем шаблон ["|']-или " или ').

Текст ссылки берем шаблоном (.*?), а на закрывающий тег натравливаем <.{0,1}a.{0,1}> так как не знаем куда вебмастер поставит символ /. Естественно необходимо применить модификатор i чтоб не думать о регистре.

 

Думаю теперь вам под силу отпарисить любую страницу, если возникнут трудности, пишите, помогу.


© Alexander Semion