PHP

Регулярные выражения. Функции парсинга PHP

Довольно-таки часто новичкам да и продвинутым сайтостроителям часто требуется что-то сграбить с другого сайта. Нужную информацию можно сграбить при помощи потокового RSS, но иногда такой способ бывает не совсем удобен, поэтому, программисты используют регулярные выражения в функциях PHP preg_match() и preg_match_all(), если требуется украсть (отпарсить, от агл. parse - "анализ, разбор") какую-либо информацию с какой-либо страницы сети Интернет. Например, можно каждый час грабать "дорожные пробки" поисковиков, "погоду" метеослужб, "курс валют" банков и прочую нужную информацию для своего сайта, если источники не предлагают свои информеры.

Чтобы найти нужный кусок текста и перетащить эту информацию на свой сайт, нужно задать символьную последовательность (маску поиска), по которой будет вестись весь перебор символов и, в случае нахождения, заданный набор символов (нужная сграбленная информация) будет присвоенна переменной, которую потом можно будет распечатать на экране монитора с помощью функции PHP "echo". Функцию PHP preg_match() парсит только до первого нахождения заданной символьной последовательности, функция preg_match_all() парсит все вхождения.
Символьнный поиск по маске
 - это означает, что вы ищете либо "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). Например:
[PHP]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
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]<?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(), почти все счетчики-чекеры, определяющие параметры браузера, ОС (операционная система) и языка клепают именно так. smile Если вы писали сами или знаете, где есть интересные статьи на эту тему, поделитесь, пожалуйста, ссылками. Кто не в курсе что это и зачем, просьба не спамить в данном топике - все "левые" комментарии отсюда будут удаляться.
Добавлено: 24 Августа 2013 10:28:45 Добавил: Андрей Ковальчук Нравится 0
Добавить
Комментарии:
Нету комментариев для вывода...