目标:从特定元素(例如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)
答案 0 :(得分:25)
你几乎就在那里。 :
中存在一个小问题//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)
答案 1 :(得分:5)
我认为以下内容会返回正确的结果:
//div[contains(@id,"mw-content-text")]/ol/li//text()
注意text()之前的双斜杠。这意味着必须返回li以下任何级别的文本节点。
答案 2 :(得分: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片段很难做到。