Дискретность в эквивалентных методах синтаксического анализа lxml Python в HTML: cssselect vs xpath - PullRequest
0 голосов
/ 24 декабря 2011

Я пытался проанализировать домашнюю страницу example.com с xpath и cssselect, но мне кажется, что я либо не знаю, как работает xpath, либо xpath lxml не работает, так как в нем отсутствуют совпадения.

Вот быстрый и грязный код.

from lxml.html import *
mySearchTree = parse('http://www.example.com').getroot()
for a in mySearchTree.cssselect('tr a'):
    print 'found "%s" link to href "%s"' % (a.text, a.get('href'))

print '-'*8 +'Now for Xpath' + 8*'-'
# Find all 'a' elements inside 'tr' table rows with xpath
for a in mySearchTree.xpath('.//tr/*/a'):
    print 'found "%s" link to href "%s"' % (a.text, a.get('href'))

Результаты:

found "About" link to href "/about/"
found "Presentations" link to href "/about/presentations/"
found "Performance" link to href "/about/performance/"
found "Reports" link to href "/reports/"
found "Domains" link to href "/domains/"
found "Root Zone" link to href "/domains/root/"
found ".INT" link to href "/domains/int/"
found ".ARPA" link to href "/domains/arpa/"
found "IDN Repository" link to href "/domains/idn-tables/"
found "Protocols" link to href "/protocols/"
found "Number Resources" link to href "/numbers/"
found "Abuse Information" link to href "/abuse/"
found "Internet Corporation for Assigned Names and Numbers" link to href "http://www.icann.org/"
--------Now for Xpath--------
found "Presentations" link to href "/about/presentations/"
found "Performance" link to href "/about/performance/"
found "Reports" link to href "/reports/"
found "Root Zone" link to href "/domains/root/"
found ".INT" link to href "/domains/int/"
found ".ARPA" link to href "/domains/arpa/"
found "IDN Repository" link to href "/domains/idn-tables/"
found "Abuse Information" link to href "/abuse/"
found "Internet Corporation for Assigned Names and Numbers" link to href "http://www.icann.org/"

В основном xpath нашел все ссылки, которые должны были быть, кроме тех, которые были выделены жирным шрифтомПримером.Тем не менее, не следует ли использовать в шаблоне xpath подстановочный знак звездочки для этого ».//tr/*/a'?

Ответы [ 2 ]

3 голосов
/ 24 декабря 2011

Возможно, что-то еще происходит (я не изучал образец документа внимательно), но ваш селектор CSS и XPath не эквивалентны.

CSS tr a - это //tr//a в XPath. .//tr/*/a означает (концептуально, а не точно):

  1. .: текущий узел
  2. //: все потомки текущего узла
  3. tr: все tr элементов среди всех потомков текущего узла
  4. /: все найденные дети tr элементов
  5. *: любой элемент среди найденных потомков tr elements
  6. /: найдены все дочерние элементы любого дочернего элемента tr elements
  7. a: все a элементы, которые являются дочерними элементами элемента потомков элемента tr элемента

Другими словами, с учетом следующего HTML:

<ul>
    <li><a href="link1"></a><li>
    <li><b><a href="link2"></a></b><li>
</ul>

//ul/*/a будет соответствовать только link1 .

XPath Primer

На самом деле «XPath» представляет собой серию шагов определения местоположения , разделенных косыми чертами. Шаг локации состоит из:

  1. Ось (например, child ::)
  2. Тест узла (либо имя узла, либо один из специальных типов узлов, например, node(), text())
  3. Необязательные предикаты (в окружении []. Узел сопоставляется, только если все предикаты верны.)

Если бы мы разложили .//tr/*/a на шаги его расположения, это выглядело бы так:

  1. .
  2. ("пробел" между косыми чертами в "//")
  3. tr
  4. *
  5. a

Вероятно, не очевидно, какого черта я говорю. Это потому, что XPath имеет сокращенный синтаксис. Вот выражение с расширенными аббревиатурами (ось и тест узла разделены ::, шаги - /):

self::node()/descendent-or-self::node()/child::tr/child::*/child::a

(Обратите внимание, что self::node() является избыточным.)

Концептуально, что происходит на шаге:

  1. с учетом набора узлов контекста (по умолчанию это текущий узел или '/' для корневого узла)
  2. Для каждого узла контекста создайте набор узлов, которые удовлетворяют этапу размещения
  3. Объединение всех наборов узлов для контекста в один набор узлов
  4. Передайте этот набор на следующий шаг расположения в качестве заданных контекстных узлов.
  5. Повторять пока не вышло. Набор, оставленный после последнего шага, является набором для всего пути.

Обратите внимание, что это все еще упрощение. Прочитайте XPath Standard , если хотите узнать подробности.

1 голос
/ 24 декабря 2011
'tr a' -> '//tr//a'
...