xpath 在页面中找到包含 HTML 的 link
xpath find link containing HTML in page
这与 xpath find specific link in page 不是同一个问题。我有 <a href="http://example.com">foo <em class="bar">baz</em>.</a>.
并且需要通过包含结束点的完整 foo <em class="bar">baz</em>.
找到 link。
据我所知,XPath 看不到原始 HTML 标记,它在 HTML 文档的抽象层上工作。尝试将 HTML 标记包含的尽可能多的信息合并到 XPath 表达式中会产生类似这样的结果:
//a[
node()[1][self::text() and .='foo ']
/following-sibling::node()[1][self::em[@class='bar' and .='baz']]
/following-sibling::node()[1][self::text() and .='.']
]
关于正在使用的谓词的简要说明:
node()[1][self::text() and .='foo ']
:让第一个子节点的文本节点的值等于 "foo"
/following-sibling::node()[1][self::em[@class='bar' and .='baz']]
:直接跟在 <em>
之后 class 等于 "bar"
并且值等于 "baz"
/following-sibling::node()[1][self::text() and .='.']
:紧跟一个文本节点,其值等于 "."
这不是 100%,因为我们可以通过调用 string()
删除其他 HTML 标签,但就我的目的而言,这看起来足够了:
//a[string() = 'bar baz.']/em[@class='bar' and .='baz']
注意:我正在跟进OP的评论
OP 自己的答案的(视觉上)更简单的变体可能是:
//a[. = "foo baz."][em[@class = "bar"] = "baz"]
甚至:
//a[.="foo baz." and em[@class="bar"]="baz"]
(假设您想要 select <a>
节点,而不是 child <em>
)
关于OP的问题:
why the [em[]=
doesn't need the dot?
在谓词内部,针对右侧的字符串测试 =
会将左侧部分转换为字符串,此处 <em>
为其字符串表示形式,即 string()
将 return.
XPath 1.0 规范文档有 an example of this:
chapter[title="Introduction"]
selects the chapter children of the context node that have one or more title children with string-value equal to "Introduction"
稍后,the same spec says 布尔测试:
If one object to be compared is a node-set and the other is a string, then the comparison will be true if and only if there is a node in the node-set such that the result of performing the comparison on the string-value of the node and the other string is true.
在 OP 的回答中,//a[string() = 'bar baz.']/em[@class='bar' and .='baz']
,.
是必需的,因为 'baz'
上的测试是在上下文节点上
请注意,我的回答有些天真,并假设 <a>
中只有 1 <em>
child,因为 [em[@class="bar"]="baz"]
正在寻找一个 em[@class="bar"]
匹配项string-value 条件,而不是唯一或第一个条件。
考虑这个输入(第二个 <em class="bar">
child,但为空):
<a href="http://example.com">foo <em class="bar">baz</em><em class="bar"></em>.</a>.
并且此测试使用 Scrapy select 或
>>> import scrapy
>>> s = scrapy.Selector(text="""<a href="http://example.com">foo <em class="bar">baz</em><em class="bar"></em>.</a>.""")
>>> s.xpath('//a[.="foo baz." and em[@class="bar"]="baz"]').extract_first()
u'<a href="http://example.com">foo <em class="bar">baz</em><em class="bar"></em>.</a>'
>>>
XPath 匹配,但您可能不想要它。
这与 xpath find specific link in page 不是同一个问题。我有 <a href="http://example.com">foo <em class="bar">baz</em>.</a>.
并且需要通过包含结束点的完整 foo <em class="bar">baz</em>.
找到 link。
据我所知,XPath 看不到原始 HTML 标记,它在 HTML 文档的抽象层上工作。尝试将 HTML 标记包含的尽可能多的信息合并到 XPath 表达式中会产生类似这样的结果:
//a[
node()[1][self::text() and .='foo ']
/following-sibling::node()[1][self::em[@class='bar' and .='baz']]
/following-sibling::node()[1][self::text() and .='.']
]
关于正在使用的谓词的简要说明:
node()[1][self::text() and .='foo ']
:让第一个子节点的文本节点的值等于"foo"
/following-sibling::node()[1][self::em[@class='bar' and .='baz']]
:直接跟在<em>
之后 class 等于"bar"
并且值等于"baz"
/following-sibling::node()[1][self::text() and .='.']
:紧跟一个文本节点,其值等于"."
这不是 100%,因为我们可以通过调用 string()
删除其他 HTML 标签,但就我的目的而言,这看起来足够了:
//a[string() = 'bar baz.']/em[@class='bar' and .='baz']
注意:我正在跟进OP的评论
OP 自己的答案的(视觉上)更简单的变体可能是:
//a[. = "foo baz."][em[@class = "bar"] = "baz"]
甚至:
//a[.="foo baz." and em[@class="bar"]="baz"]
(假设您想要 select <a>
节点,而不是 child <em>
)
关于OP的问题:
why the
[em[]=
doesn't need the dot?
在谓词内部,针对右侧的字符串测试 =
会将左侧部分转换为字符串,此处 <em>
为其字符串表示形式,即 string()
将 return.
XPath 1.0 规范文档有 an example of this:
chapter[title="Introduction"]
selects the chapter children of the context node that have one or more title children with string-value equal to "Introduction"
稍后,the same spec says 布尔测试:
If one object to be compared is a node-set and the other is a string, then the comparison will be true if and only if there is a node in the node-set such that the result of performing the comparison on the string-value of the node and the other string is true.
在 OP 的回答中,//a[string() = 'bar baz.']/em[@class='bar' and .='baz']
,.
是必需的,因为 'baz'
上的测试是在上下文节点上
请注意,我的回答有些天真,并假设 <a>
中只有 1 <em>
child,因为 [em[@class="bar"]="baz"]
正在寻找一个 em[@class="bar"]
匹配项string-value 条件,而不是唯一或第一个条件。
考虑这个输入(第二个 <em class="bar">
child,但为空):
<a href="http://example.com">foo <em class="bar">baz</em><em class="bar"></em>.</a>.
并且此测试使用 Scrapy select 或
>>> import scrapy
>>> s = scrapy.Selector(text="""<a href="http://example.com">foo <em class="bar">baz</em><em class="bar"></em>.</a>.""")
>>> s.xpath('//a[.="foo baz." and em[@class="bar"]="baz"]').extract_first()
u'<a href="http://example.com">foo <em class="bar">baz</em><em class="bar"></em>.</a>'
>>>
XPath 匹配,但您可能不想要它。