Регулярные выражения. Функции парсинга PHP.
Sunday, November 22, 2009 12:31:52 AM
Довольно-таки часто новичкам да и продвинутым сайтостроителям часто требуется что-то сграбить с другого сайта. Нужную информацию можно сграбить при помощи потокового RSS, но иногда такой способ бывает не совсем удобен, поэтому, программисты используют регулярные выражения в функциях PHP preg_match() и preg_match_all(), если требуется Чтобы найти нужный кусок текста и перетащить эту информацию на свой сайт, нужно задать символьную последовательность (маску поиска), по которой будет вестись весь перебор символов и, в случае нахождения, заданный набор символов (нужная сграбленная информация) будет присвоенна переменной, которую потом можно будет распечатать на экране монитора с помощью функции PHP "echo". Функцию PHP preg_match() парсит только до первого нахождения заданной символьной последовательности, функция preg_match_all() парсит все вхождения.
Символьнный поиск по маске
[ab] - это означает, что вы ищете либо "a", либо "b". [a-z] - все английские буквы от "a" до "z". [a-zA-Z] - любая английская буква, большая или маленькая. [a-fq-x] - любая маленькая английская буква в диапозоне от "a" до "f" и от "q" до "x". [0-9] - любая цифра от 0 до 9. [a-z][a-z][0-9][0-9] - символьная строка, состоящая из первых любых двух маленьких букв и двух любых цифр. [14a-cz] - символьная строка, состоящая из одного любого символа: 1, 4, буквы "a", "b", "c" или "z". Заметка: литералами могут быть не только буквы и цифры, а так же знаки препинания, математические знаки, например ',' (запятая), '!' (восклицательный знак), '+' (плюс), '-' (минус). Если вы поставите минус между a и z, то это будет интервал, но если вы поставите минус сразу же после открытой квадратной скобки, то это будет минус, например: [-,a-z] - символьная строка, состоящая из симоволов: "минус", "запятая" и одна любая маленькая английская буква. Квантификаторы Квантификаторы призванные на сокращение повторений записи (в фигурных скобках): [a-z]{2}[0-9]{3} - символьная строка, состоящая из первых любых двух маленьких букв и трех любых цифр. [a-z]{1,3} - символьная строка, состоящая из одной, двух или трех маленьких английских букв. [a-z]{2,} - символьная строка, состоящая из двух и более маленьких английских букв. [a-z]* - символьная строка, состоящая из любого количества маленьких английских букв или ни одной. Идентично [a-z]{0,}. [a-z]+ - символьная строка, состоящая из любого количества маленьких английских букв, но минимум одной. Идентично [a-z]{1,}. [a-z]? - символьная строка, состоящая из не более, чем одной любой маленькой английской буквы, которая может и отсутствовать. Идентично [a-z]{0,1}. [^abc] - символьная строка, состоящая из любого символа, кроме маленьких букв латинского алфавита "a", "b" и "c". Инструкции ([a-z]{5})([1-8]{3}) - символьная строка, состоящая из пяти маленьких английских букв и трех цифер от 1 до 8. При этом, переменная (в Perl) $0 будет содержать всю строку; $1 - только первую часть, т.е. пять любых маленьких английских букв; $2 - только вторую часть, т.е. три любых цифры от 1 до 8. Символьная строка имеет начало и конец: вначале каждой строки и в конце каждой строки стоит невидимый символ. Для того, чтобы найти совпадающее символьное выражение в нашей строке, существуют спец. символы: ^ ("крышка", "птичка", циркумфлекс)- символ начала строки, ставится в начале строки. $ (знак доллара) - символ конца строки, ставится в конце строки. Запись будет выглядеть так: ^[a-z]{2}[1-5]{3}$ - найти символьное совпадение в строке, которая начинается на первые две любые маленькие английские буквы и заканчивается на три любые цифры от 1 до 5. В программах для того, чтобы показать, где начинается условие поиска (регулярное выражение), используют разделители, например, "слеши" (наклонная черта) или "тильды" (волнистое тире - "~"): preg_match("/^[a-z0-9]/",$string,$mathces); Символы \s - соответствует литералу 'пробел', либо литералу 'перевод строки', либо литералу 'табулятор'. \S - любой видимый символ, не совпадающий с \s, т.е. [^\s]. \w - любой буквенный символ из [a-zA-Z_]. \W - любой символ, не входящий в определение \w, т.е. [^a-zA-Z_]. \d - любой символ из [0-9]. \D - любой символ, не являющийся цифрой. \f - подача листа. \b - "забой" или "граница слова" в зависимости от ситуации. . ("точка") - абсолютно любой символ из видимых и невидимых. \ ("слеш") - позволяет любой спецсимвол описать обычным литералом (простым символом). Например: \. - даст "точку". \\ - даст "слеш". \\\ - даст два обратных "слеша", т.е. "\\". \\\\? - даст "\" или "\\". \< и \> - позиция в начале и в конце слова, т.е. \<cat даст "category", но не "mycat", противоположно действует cat\>, которая даст "mycat" ("notmycat" и др.). Примеры: Запись [a-z\s] будет выглядеть понятней и читабельней, чем [a-z ]. Условия (?<=символы) - символы спереди, которые обязательно должны совпасть в искомой строке. (?=символы) - символы сзади, которые обязательно должны совпасть в искомой строке. (?<!символы) - символы сзади, которые обязательно должны отсутствовать в искомой строке. (?!символы) - символы спереди, которые обязательно должны совпасть в искомой строке. (?# comment #) - комментарий для себя. ?: - позволяет не запоминать (не "есть память" сервера), например: (?:be)|(?:not\sto\sbe) - не будут запоминаться в переменные \1, \2 (в Perl - $1, $2). Например:preg_match_all("/(?<!<TD>)(?<=>)\d*\.\d*(?!<\/B>)(?=<\/A>)/",$string,$matches);
print_r($matches);
(be)|(not\sto\sbe) - найти в строке символьное совпадение первой группы литералов (символов) "be" или "not to be". Пример:
preg_match("/^(be)|(not\sto\sbe)$/",$alternate,$answer);
Регулярное выражение совпадет в случае если $alternate = "be" или $alternate = "not to be".
s(o|u)n - идентично (son)|(sun) и совпадет с "son" и с "sun".
s[o|u]n - совпадет только с "so|un".
[(July|Jul)] = [July?] = либо "July", либо "Jul".
--------------------------
В PHP поддерживается два стандарта регулярных выражений - POSIX и PCRE (Perl Compatible Regular Expressions). Первый устаревший и медленный, примеров почти нет, документация на английском; второй (функции preg_*) - современный, документация полная. Подробнее об этих стандартах написано в Вики: Regular expression. Вот все функции PHP:
preg_filter — Perform a regular expression search and replace
preg_grep — Return array entries that match the pattern
preg_last_error — Returns the error code of the last PCRE regex execution
preg_match_all — Perform a global regular expression match
preg_match — Perform a regular expression match
preg_quote — Quote regular expression characters
preg_replace_callback — Perform a regular expression search and replace using a callback
preg_replace — Perform a regular expression search and replace
preg_split — Split string by a regular expression
Синтаксис регулярных выражений.
--------------------------
Примеры парсинга
Ищем все Jpeg-картинки: "\.jpg$". Ищем все ссылки на странице: ^http:// Ищем картинки только в полном пути, а не в бэкграундах и т.д.: ^http://.*\.jpg$ Ищем любую последовательность из символа "А": "A*" - это даст "А", либо "ААА", либо "ААААА". Ищем документ в сети (главную страницу): "index\.(asp|htm|cfm|php|html)". Ищем один слеш или больше: "\\\\+" (первый слеш экранирующий, второй слеш - это сам слеш, затем идет любое количество слешей). Ищем код, например, 12B3C2F0-9D8E-9A99-7A1181C5F546F938: [A-F0-9]{8,8}-[A-F0-9]{4,4}-[A-F0-9]{4,4}-[A-F0-9]{16,16} Найдем страницы от 0 до 9: "page[0-9]\.html" = "page[0-9]+\.html" = "page[0-9]{1,1}\.html" = "page[123456789]\.html". Можно записать приближенно: "page.\.html". Примеры выше взял отсюда: http://stedee.id.au/So_You_Want_to_Learn_Regular_Expressions.<?php
//Получаем всю html-страницу нужного документа сети и
присваиваем содержимое страницы переменной $html.
$html = file_get_contents($site);
//Парсим заголовок (титул) самой html-страницы.
preg_match('|<title>(.*)</title>|mi',$html,$result1);
//Парсим все заголовки html-страницы H1.
preg_match_all('|<h1>(.*)</h1>|mi',$html,$result2);
//Выводим на экран все данные html-страницы
echo '
Титул: '.$result1[1].'<br />
Н1 : '.$result2[1];
?>
Найдем айпи (ip), оно может быть одного из трех форматов:
х.х.х.х
хх.хх.хх.хх
ххх.ххх.ххх.ххх
где (х|xx|xxx) = 0...255.
preg_match("^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$",$alternate,$answer);
Эта маска позволит получить такую последовательность:
999.999.999.999
000.000.000.000
А далее ее уже нужно обрабатывать, чтоб получить правильный айпи-адресс нужного диапазона без ошибок, проверять на совпадение.
Если на сайте нет RSS (его парсить гораздо проще), то парсить html-страницу можно так:
<?php
// Получаем HTML-код страницы с помощью функции PHP file_get_contents.
$content = file_get_contents('http://news.google.ru/news?ned=tru_ru&rec=0');
// Определяем позицию строки, с которой мы будем копировать код. Функция strpos.
$pos = strpos($content,'<table border=0 align=right cellspacing=0 cellpadding=0>');
// Присваиваем переменной $content скопированный с помощью substr код, начиная с позиции $pos.
$content = substr($content,$pos);
// Находим позицию второй строки.
$pos = strpos($content,'<br><br><br clear=all>');
// Отрезаем нужное количество символов от нулевого.
$content = substr($content,0,$pos);
// Чтобы не подгружать изображения, удаляем теги [html:img с помощью str_replace (заменяем на пустоту).
$content = str_replace('<img src=/images/cleardot.gif width=1 height=2]','',$content);
// выводим полученный код.
echo $content;
?>
Нашел здесь.
--------------------------
Регулярные выражения в сети:
http://phpclub.ru/detail/article/regexp_1
http://phpclub.ru/detail/article/regexp_2
P.S. Нужно стараться делать парсеры не чистого html-файла, а XML-файла, потому как он при парсинге не загружается полностью в память, а читается последовательно и вызывается соответсвующее событие. Но у себя я решил пока начать с простого и наклепал при помощи регулярок простой чекер, который показывает в каких каталогах находится ваш сайт, также ТИЦ, ПР, Алексу (популярность сайта по посещаемости в сети), индексацию сайта (количество проиндексированных страниц поисковиками) и беклинки (обратные ссылки на ваш сайт).Со временем постараюсь его доработать, посмотрим, что из этого выйдет.
Нашел немного интересных ссылок про регулярные выражения на английском на каком-то странном сайте deitel.com. К сожалению, со всех сайтов вытягивать информацию, не заходя на них (парсить, в общем), не получается, если они находятся на серверах, которые выдают эти самые сайты в различных кодировках, например, мой блог сервер выдает в кодировке charset=UTF-8, поэтому, я не могу проверить регулярками, например, Веб-архив (archive.org), который выдается в кодировке charset=iso-8859-1. Вот такая жопа. И нигде не могу найти в сети пример конвертера, сам тоже не знаю, как конвертер написать. Капец. Зато нашел в сети конвертер в charset=UTF-8 из charset=windows-1251:
<?php
function utf8win1251($s){
$out="";$c1="";$byte2=false;
for ($c=0;$c<strlen($s);$c++) {
$i=ord($s[$c]);
if ($i<=127) $out.=$s[$c];
if ($byte2) {
$new_c2=($c1&3)*64+($i&63);
$new_c1=($c1>>2)&5;
$new_i=$new_c1*256+$new_c2;
if ($new_i==1025) $out_i=168; else
if ($new_i==1105) $out_i=184; else $out_i=$new_i-848;
$out.=chr($out_i);
$byte2=false;
} if (($i>>5)==6) {$c1=$i; $byte2=true;}
} return $out;
}
?>
Применить его к регуляркам не сложно, следует прописать, например, так (кол-во бэклинков в Яндексе):
<?php
function backs_blogs_yandex($link) {
//Показаны сообщения <b>1</b> — <b>10</b> из <b>414</b> найденных.
$url = 'http://blogs.yandex.ru/search.xml?text=&holdres=mark&link='.$link;
$buf = utf8win1251(file_get_contents($url));
preg_match('|из\s<b>(\d*)</b>|smi',$buf,$r);
return $r[1] ? $r[1] : '?';
}
?>
Кто знает, как вытянуть информацию о нахождении сайта в Веб-архиве, прокомментируйте, пожалуйста.
http://web.archive.org/web/*/isle-blog.ruТе, кто часто встречал набор символов, типа \n\t\s\r и подобные и не знает, что это такое и откуда, то загляните в Вики: Управляющие символы. Заметка: Функция PHP file() при получении содержимого страницы с удаленного хоста отправляет среди прочих заголовок X-Powered-By: PHP/5.3.0. Некоторые сайты отслеживают наличие такого заголовка (USER_AGENT) и не отдают по такому запросу контент, выдавая ошибку типа 503 (сервер понял комманду, но решил ее не выполнять по какой-либо причине; 404 - запрещенный вызов и т.д.). Чтобы избежать подобного рода ошибок и всё же вытащить контент, можно воспользоваться CURL и формировать заголовки (типа USER_AGENT и т.п.), маскируясь под браузер, тогда нельзя будет распознать, что это: скрипт (бот) или браузер. Например (стырил с форума forum.php.su):
<?
@set_time_limit(0);
@ini_set("display_errors","1");
$responce = "";
$fsock = fsockopen("www.site.ru",80,$errnum,$errstr,2);
$headers = "GET http://www.site.ru/ HTTP/1.1\n";
$headers .= "Host: www.monet.com\n";
$headers .= "User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.8.0.2) Gecko/20060308 Firefox/1.5.0.2\n";
$headers .= "Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5\n";
$headers .= "Accept-Language: ru-ru,ru;q=0.8,en-us;q=0.5,en;q=0.3\n";
$headers .= "Accept-Charset: windows-1251,utf-8;q=0.7,*;q=0.7\n";
$headers .= "Keep-Alive: 500\n";
$headers .= "Connection: close\n";
$headers .= "Content-Type: application/x-www-form-urlencoded\r\n\r\n";
fwrite ($fsock,$headers);
while (!feof($fsock)) $responce .= fread($fsock,1024);
fclose ($fsock);
echo $responce;
?>
Получить юзер-агент у себя на сайте любой ОС и любого браузера можно коммандой:
<?php echo $_SERVER['HTTP_USER_AGENT']; ?>Именно из юзер-агента можно вытащить информацию через функцию PHP preg_match(), почти все счетчики-чекеры, определяющие параметры браузера, ОС (операционная система) и языка клепают именно так.
Если вы писали сами или знаете, где есть интересные статьи на эту тему, поделитесь, пожалуйста, ссылками. Кто не в курсе что это и зачем, просьба не спамить в данном топике - все "левые" комментарии отсюда будут удаляться. Кому интересны заметки, подписывайтесь на блог "Заметки степного сеошника", чтоб не пропустить все самое интересное.














Романrspost # Saturday, November 28, 2009 1:18:30 PM
С позволения, сграбастаю себе в оффлайн для разбора. Как раз искал нечто похожее почитать, да вот: нашел компактно.
Спасибо.
Зайва Игорь Леонидовичisle0 # Sunday, November 29, 2009 8:41:43 AM
Единственная проблема сейчас для меня в регулярках - это двойные скобки, я их реплейсом обрезаю, пробелы, если есть - тримом. Если знаешь, как победить эту заразу (скобки), наклепай примерчик, пожалуйста
Романrspost # Sunday, November 29, 2009 2:00:30 PM
Но всё что найду и всё, до чего дойду, выложу.
Anonymous # Monday, February 22, 2010 11:41:53 PM
Зайва Игорь Леонидовичisle0 # Tuesday, March 2, 2010 7:37:09 PM
preg_match_all('|\svasea\s|si',$content,$result);
Далее циклом:
echo $result[0][n];
Anonymous # Wednesday, March 3, 2010 9:17:42 PM
Anonymous # Wednesday, March 3, 2010 9:47:25 PM
Зайва Игорь Леонидовичisle0 # Friday, March 5, 2010 4:04:02 PM
Originally posted by anonymous:
Нужно копать в сторону "экранированных кавычек" - дело в них... Для того, чтобы в php вывести текст с кавычками, их нужно заэкранировать или использовать спец.символы юникода, например:
вместо
Тогда, если выводить переменную как html, то будет результат "жирным" на мониторе, а чтобы переменную вывести как текст, то я использую функцию htmlspecialchars() (аналог htmlentitites()). Это удобно, когда нужно отпарсить страницу html и вывести ее теги (пример выше).
Экранирование кавычек для их вывода в php:
Вывод будет:
Чтобы кавычки не экранировать, можно использовать одинарные и двойные кавычки, например, так:
Зайва Игорь Леонидовичisle0 # Friday, March 5, 2010 4:15:59 PM
Originally posted by anonymous:
Раз слово в тексте есть, значит, находит
Конструкция '\\\"' означает, что нужно вывести один слеш и одну двойную кавычку, т.е.: \" - это и выводится в тексте. Если нужно вывести вместо '\"весло\"' просто '"весло"', то написать нужно так: '\"' вместо '\\\"' - тогда будет выведена только двойная кавычка без слеша, т.е. получим: просто '"весло"'
Все спецсимволы в регулярках должны быть экранированы - это двойные кавычки и слеши, как правило, а также спец.символы управления в регулярках, т.е.: \s - пробелы, \w - символы буквенные (латинские), \d - цифры и т.д.
Зайва Игорь Леонидовичisle0 # Friday, March 5, 2010 4:28:29 PM
Originally posted by anonymous:
Это конвертор с одной кодировки в другую, например, из вин-1251 в utf-8. Для конвертации есть несколько уже встроенных функций, как правило, хостеры их всегда устанавливают на сервер. Я обычно использую:
echo iconv('windows-1251','utf-8','слово');А можно просто редактировать php-файл в редакторе, который сохраняет utf-8 кодировку, т.е. просто написать:
Если php-документ в соответствующей кодировке.
Я иногда пользуюсь Штирлицем - помогает
Anonymous # Thursday, July 22, 2010 11:14:44 AM
Anonymous # Thursday, July 22, 2010 11:34:57 AM
Зайва Игорь Леонидовичisle0 # Tuesday, July 27, 2010 3:19:06 AM
Приведенный вами пример неправильный:
"[0-9]{1,9}-..." - может быть "1", "11", "111", ... "111111111" - это первая часть айпи, а части не могут иметь более трех цифр и не могут быть более 255.
Нужно именно так:
"[0-9]{1,3}-..." - тогда получим варианты, типа "1", "11" или "111", т.е. 1-3 цифры.
Татьянаtaranna # Sunday, September 19, 2010 6:34:40 AM
Зайва Игорь Леонидовичisle0 # Sunday, September 19, 2010 9:39:45 AM
Я интересуюсь парсингом как способом передачи информации с одного сайта на другой, а не как способом загаживания сети и чужих ресурсов спамом. Если действительно интересуетесь парсингом, можете задать свои вопросы в личку, могу для вас статейку написать, если оно действительно нужно, но вроде вы и сами в php разбираетесь, раз статьи соответствующие публикуете.