17

目标:从特定元素(例如li)中提取文本,同时忽略各种混合标签,即展平第一级子元素并简单地分别返回每个展平子元素的连接文本。

例子:

<div id="mw-content-text"><h2><span class="mw-headline" >CIA</span></h2>
    <ol>
    <li>Central <a href="/Intelligence_Agency.html">Intelligence Agency</a>.</li>
    <li>Culinary <a href="/Institute.html">Institute</a> of <a href="/America.html">America</a>.</li>
    </ol>

    </Div>  

所需文字:

  • 中央情报局
  • 美国烹饪学院

除了周围的锚标记阻止简单的检索。

要分别返回每个 li 标签,我们使用简单的:

//div[contains(@id,"mw-content-text")]/ol/li

但这也包括周围的锚标签等。和

//div[contains(@id,"mw-content-text")]/ol/li/text()

仅返回 li 的直接子元素的文本元素,即 'Central','.'...

寻找自我和后代的文本元素似乎是合乎逻辑的

//div[contains(@id,"mw-content-text")]/ol/li[descendant-or-self::text]

但这根本没有回报!

有什么建议么?我正在使用 Python,所以我愿意使用其他模块进行后处理。

(我正在使用看起来符合 XPath 1.0 的 Scrapy HtmlXPathSelector)

4

3 回答 3

26

你快到了。有一个小问题

//div[contains(@id,"mw-content-text")]/ol/li[descendant-or-self::text]

修正后的表达式为

//div[contains(@id,"mw-content-text")]/ol/li[descendant-or-self::text()]

但是,有一个更简单的表达式可以准确地生成指定下所有文本节点的所需串联li

string(//div[contains(@id,"mw-content-text")]/ol/li)
于 2012-05-16T12:48:53.723 回答
5

我认为以下将返回正确的结果:

//div[contains(@id,"mw-content-text")]/ol/li//text()

注意 text() 之前的双斜杠。这意味着必须返回低于 li 的任何级别的文本节点。

于 2012-05-16T12:28:35.100 回答
2

字符串连接很棘手。这是使用的快速解决方案lxml

>>> from lxml import etree
>>> doc = etree.HTML("""<div id="mw-content-text"><h2><span class="mw-headline" >CIA</span></h2>
...     <ol>
...     <li>Central <a href="/Intelligence_Agency.html">Intelligence Agency</a>.</li>
...     <li>Culinary <a href="/Institute.html">Institute</a> of <a href="/America.html">America</a>.</li>
...     </ol>
...
...     </Div>""")
>>> for element in doc.xpath('//div[@id="mw-content-text"]/ol/li'):
...   print "".join(element.xpath('descendant-or-self::text()'))
...
Central Intelligence Agency.
Culinary Institute of America.

请注意,这//可能具有较差的性能/意外执行,应尽可能避免,但对于示例 HTML 片段很难做到这一点。

于 2012-05-16T12:26:06.620 回答