Pull to refresh

Comments 47

UFO just landed and posted this here
Я думал это твоя статья, пока автора не увидел
UFO just landed and posted this here
Лично я давным давно отказался от регулярок в своих парсерах в пользу DOM и Xpath. Это действительно удобный инструмент.
У вас были какие то проблемы с валидностью? Незакрытый тэг? Ведь всякое бывает.
От регулярок просто устал.
А при использовании xpath сразу через tidy прогонял html и честно говоря еще не встречал проблем с валидностью.
Tidy. Я знаю что это, но никогда с ним не работал. Действительно крутая штука?
Да. Но стоит учитывать некоторые моменты при работе с ним. Например, если в исходном коде html в таблице нет тега , то tidy его создает сам. Поэтому нужно повнимательней быть при составлении xpath запросов.
Вы можете применять его для парсинга любой html-страницы

Если она является валидным xhtml-документом.
UFO just landed and posted this here
UFO just landed and posted this here
загрузчик html достаточно сообразителен, чтобы исправить ошибки, поэтому валидность не имеет особого значения — можно парсить даже полный бред:
$crazyHtml = 'd<dd';
$dom =new  DomDocument();
$dom->loadHtml($crazyHtml);
echo $dom->saveHtml();

другое дело, что алгоритмы исправлений могут отличаться у разных библиотек и браузеров, давая на выходе разные деревья. например php, этот пример интерпретирует вот так:
PHP Warning:  DOMDocument::loadHTML(): Couldn't find end of Start Tag dd in Entity, line: 1 in /tmp/a.php on line 3
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html><body><p>d</p><dd></dd></body></html>
Также как SQL, xpath является декларативным языком программирования.
Это не язык программирования, а язык запросов. Вы же CSS не считаете языком программирования?
SQL, кстати, тоже языком программирования не является.
SQL с некоторыми модификациями, между прочим, Тьюринг-полный. А значит, такой же язык программирования, как и php/java, etc. Хотя в базовой версии, согласен, не совсем.
С расширениями — вполне.
А языки запросов — это не языки программирования? Почему?
Я знакомство с XPath начинал отсюда zvon.org/xxl/XPathTutorial/General_rus/examples.html

А вообще очень классный язык. А для любителей парсить HTML регулярками — вот stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags#answer-1732454

Кстати, про оси навигации тоже полезно почитать.

И еще момент — можно XPath запросы прямо из FireBug консоли напрямую делать через функцию $x например $x("//a/@href");
После 5ти лет работы с xsl-шаблонами, строки типа ".//*[@id='w3c_home_upcoming_events']/ul/li[1]/div[2]/p[1]/a" уже не удивляют :)
>Старайтесь отказаться от регулярных выражений при парсинге веб-страниц в пользу xpath.
>Это сделает ваш код проще, понятнее. Вы допустите меньше ошибок. Сократиться время отладки.

Допустим у меня есть такой узел Numbers, я хочу заменить его на Количество

Примитивнейше регулярное выражение, а как это сделать при помощи Xpath, ну хотя бы концептуально?
Сорри, пример такой:

<тэг span>Numbers</тэг span>

заменить на

<тэг span>Количество</тэг span>
хотелось бы внести ясность — идея Xpath заключается в получении данных. Для трансформации существует XSLT.
Важное замечание к топику — если вы разбираете DOM дерево средствами PHP(или другого языка), то такой инструмент как FirePath — не лучший помошник, ибо он показывает код, уже адаптированный WebKitом.
В свою очередь я делал это так:
PHP(Curl)->Tidy->сохранял в виде файла. Файл открывал чем-нибудь типа SketchPath и оттуда брал готовый XPath.
Общий совет: не надо использоваться в xpath запросах конструкцию // без лишней надобности. Это неэффективно: запрос пройдет *весь* DOM, в поисках удовлетворяющих условиям элементов. Потрудитесь указать полный путь до элемента (ну или хотя бы путь до области где могут быть эти элементы), это поможет вам сэкономить нервы и время на больших объемах данных.
попробуйте SAXparser при работе с большими объемами. Так вы сэкономите не только свое время но и ресурсы сервера.
Разные вещи. Мне нужен DOM, SAX-пасеры тут не помогут.
ru.wikipedia.org/wiki/SAX

Применяются SAX-парсеры… для чтения XML-потоков большого объема (когда построение DOM требует слишком большого объема памяти).
Я знаю что такое SAX, поэтому и говорю, что разные вещи.

Смысл в том, xpath-конструкция // неэффективна, и применять ее повсеместно вместо указания пути к элементу не рекомендуется.
это мнимая эффектность.

Да по полному пути элемент будет найден быстрее, но это мили секунды! DOM дерево в оперативной памяти и поиск по нему осуществляется очень быстро, даже если мы не укажем полный путь.

Не достаток «полного пути» — в том что эта длинная цепочка узлов сделает ваш запрос плохо читаемым. Увеличивается вероятность допустить ошибку с Вашей стороны и программисту который получит это запрос после вас будет сложнее в нем разобраться.

Согласен, но есть различия при использовании XPath для парсинга сгенерированного XML какого-нибудь API и парсинга HTML сайта — в первом случае глубина дерева обычно гораздо меньше, соответственно xpath от корня гораздо короче. А когда нужно парсить сайты, то XPath от корня проще поломать незначительными изменениями в верстке.

Еще гораздо более простая и полезная оптимизация — если нужно парсить, допустим, статью и комментарии на хабре, а все остальное (облако тегов, похожие топики) нет, то можно сперва выбрать DIV содержащий И комментарии И статью (для хабра //div[@id='main-content']), сохранить в переменную языка программирования и потом уже искать запросами в этом контексте.
На примере lxml питона:
context=document.xpath("//div[@id='main-content']")[0]
article_title=context.xpath("div[@class='hentry']/h2/span")
article_content=context.xpath("div[@class='hentry']/div[@class='content']")
comments=context.xpath("div[@id='comments']/ul")
В качестве альтернативы (и дополнения) к Firepath я так же использую Firefinder
Когда уже люди перестану писать бред типа $_res и поймут что вместо конкатенации достаточно перечисления аргументов echo через запятую…
xPath — действительно замечательная вещь, давно её использую!
Хотелось бы поделиться информацией об xPath в MySQL, с недавнего времени активно использую в одном проекте, работает чудесным образом и очень шустро. Работа с xml деревьями в MySQL поддерживается с версии 5.1 и выше.
Работать с XML можно посредствам двух функций: ExtractValue() и UpdateXML()

Пример:
SELECT * FROM taxonomy WHERE EXTRACTVALUE(`cluster`,'/sys-cluster/meta/title[self:text()]') = 'products';
хотя, можно и так:
SELECT * FROM taxonomy WHERE EXTRACTVALUE(`cluster`,'/sys-cluster/meta/title') = 'products';

Поражает скорость выборки данным методом:
mysql> SELECT benchmark(1000000, ExtractValue(@xml, '/a/b/c'));
+--------------------------------------------------+
| benchmark(1000000, ExtractValue(@xml, '/a/b/c')) |
+--------------------------------------------------+
| 0 |
+--------------------------------------------------+
1 row IN SET (4.77 sec)


Даю ссылки, где можно можно более подробнее с этим ознакомиться и посмотреть примеры:
http://adw0rd.ru/2009/xpath-mysql/
и официальный док http://dev.mysql.com/doc/refman/5.1/en/xml-functions.html
А индекс по XPath не умеет делать? Если нет, то не очень юзабельно ИМХО. (По крайней мере слышал, что в MSSQL индексы по полям XML поля можно строить, сам не щупал)
По XPath индексы делать нельзя. Но полнотекстовый поиск после некоторых шаманств с бубном сделать можно.
Хабралюди, помогите получить 4 кармы, есть интереснейшие посты по MySQL и PHP, уже подготовил, но нет возможности запостить. По XPath в том числе. Большое спасибо тем, кто откликнется. Прошу прощения за частичный офтоп.
Как раз появилась задача парсинга HTML страницы как XML документа и ваша статья очень пригодилась. Спасибо!
Спасибо, отличная статья. Но как быть с кодировкой? страница — в UTF-8, locale системы — UTF-8, на выходе — белиберда :(
Какая кодировка у файла скрипта на выходе которого белиберда?
UTF-8. Проблема решена простым хаком, найденным на странице документации в комментариях: $doc->loadHTML('<?xml encoding=«UTF-8»>'. $html); Это есть баг…
Или так

//==================================================
$content = mb_convert_encoding($content, 'HTML-ENTITIES', "UTF-8");
//==================================================
Существует программа паук позволяющая обработать все странички сайта и применить к каждой страничке набор XPath выражений.
Там же в ней есть сразу и возможность протестировать XPath выражения
http://dirs.info/spider/
Sign up to leave a comment.

Articles