鉴于此html:
<ul>
<li>This is <a href="#">a link</a></li>
<li>This is <a href="#">another link</a>.</li>
</ul>
如何使用XPath获得以下结果:
[
'This is a link',
'This is another link.'
]
我尝试过的事情:
//ul/li/text()
但这会给我['This is ', 'This is .']
(与a
代码中的文字一起
此外:
string(//ul/li)
但是这给了我['This is a link']
(所以只有第一个元素)
另外
//ul/li/descendant-or-self::text()
但这给了我['This is ', 'a link', 'This is ', 'another link', '.']
还有其他想法吗?
答案 0 :(得分:3)
XPath通常无法选择不存在的内容。 HTML中不存在这些内容:
[
'This is a link',
'This is another link.'
]
它们可能在概念上存在于更高的抽象级别,即浏览器对源代码的呈现,但严格地说,即使它们是分开的,例如在颜色和功能上。
在DOM级别上,只有单独的文本节点,而且所有XPath都可以为您选择。
因此,您有三种选择。
text()
个节点,并在Python代码中加入各自的值。<li>
元素,并为每个元素使用Scrapy评估string(.)
或normalize-space(.)
。 normalize-space()
会以你期望的方式处理空格。<li>
元素并访问其.text
属性 - 该属性在内部查找所有后代文本节点并为您加入。我个人会以//ul/li
作为我的基本XPath表达式来使用后者,因为这样可以提供更清晰的解决方案。
正如@paul在评论中指出的那样,Scrapy提供了一个很好的流畅界面,可以在一行代码中执行多个处理步骤。以下代码实现了变体#2:
selector = scrapy.Selector(text='''<ul>
<li>This is <a href="#">a link</a></li>
<li>This is <a href="#">another link</a>.</li>
</ul>''')
selector.css('ul > li').xpath('normalize-space()').extract()
# --> [u'This is a link', u'This is another link.']
答案 1 :(得分:2)
@Tomalak在saying中是正确的,XPath通常无法选择那些不存在的内容。
但是,在这种情况下,您需要的结果是li
的string(//ul/li)
元素。正如您所发现的那样,
//ul/li
让你关闭,但只返回第一个所需的字符串。
这指出了XPath 2.0中解决的XPath 1.0的缺点。
在 XPath 1.0 中,您必须在XPath之外迭代由//ul/li/string()
选择的节点集 - 在XSLT,Python,Java等中。
在 XPath 2.0 中,最后一个位置步骤可以是一个函数,因此您可以使用,
This is a link
This is another link.
直接返回
string()
按要求。
如果您坚持使用仅支持XPath 1.0但又知道
的Scrapy,这比实际更具教育意义private val converters = HashMap<String, ValueConverter<Event>>()
,通常有助于推理XPath文本选择。