我的初始代码是有效的,但是错过了网站中一些奇怪的格式:
response.xpath("//*[contains(., 'Description:')]/following-sibling::p/text()").extract()
<div id="body">
<a name="main_content" id="main_content"></a>
<!-- InstanceBeginEditable name="main_content" -->
<div class="return_to_div"><a href="../../index.html">HOME</a> | <a href="../index.html">DEATH ROW</a> | <a href="index.html">INFORMATION</a> | text</div>
<h1>text</h1>
<h2>text</h2>
<p class="text_bold">text:</p>
<p>text</p>
<p class="text_bold">text:</p>
<p>text</p>
<p class="text_bold">Description:</p>
<p>Line1</p>
<p>Line2</p>
Line3 <!-- InstanceEndEditable -->
</div>
我在拉线1和线2时没有问题。但是线3并不是我P级的兄弟。这只发生在我试图从表格中删除的某些页面上。
以下是链接:https://www.tdcj.state.tx.us/death_row/dr_info/wardadamlast.html
抱歉Xpath只是让我感到困惑,有没有办法提取标准//*[contains(., 'Description:')]
之后的所有数据,而不是必须是兄弟姐妹呢?
提前致谢。
编辑:更改示例以更多地反映实际情况。添加了原始页面的链接。
答案 0 :(得分:4)
您可以在<p>
包含“Description:”(following-sibling::node()
)之后选择所有兄弟节点(元素和文本节点),然后获取所有文本节点(descendant-or-self::text()
):
>>> import scrapy
>>> response = scrapy.Selector(text="""<div>
... <p> Name </p>
... <p> Age </p>
... <p class="text-bold"> Description: </p>
... <p> Line 1 </p>
... <p> Line 2 </p>
... Line 3
... </div>""", type="html")
>>> response.xpath("""//div/p[contains(., 'Description:')]
... /following-sibling::node()
... /descendant-or-self::text()""").extract()
[u'\n ', u' Line 1 ', u'\n ', u' Line 2 ', u'\nLine 3\n']
>>>
让我们把它分解。
因此,您已经知道如何找到包含“描述”的正确<p>
(使用XPath //div/p[contains(., 'Description:')]
):
>>> response.xpath("//div/p[contains(., 'Description:')]").extract()
[u'<p class="text-bold"> Description: </p>']
您想要<p>
轴+ following-sibling::
元素选择后的p
:
>>> response.xpath("//div/p[contains(., 'Description:')]/following-sibling::p").extract()
[u'<p> Line 1 </p>', u'<p> Line 2 </p>']
这不会给你第3行。所以你读了一下XPath并尝试“全能”*
:
>>> response.xpath("//div/p[contains(., 'Description:')]/following-sibling::*").extract()
[u'<p> Line 1 </p>', u'<p> Line 2 </p>']
仍然没有运气。为什么?因为*
只选择元素(通常称为“标记”,以简化)。
您所追踪的第3行是文本节点,即父<div>
元素的子节点。但是文本节点也是一个节点(!),所以你可以选择它作为上面着名的<p>
的兄弟节点:
>>> response.xpath("//div/p[contains(., 'Description:')]/following-sibling::node()").extract()
[u'\n ', u'<p> Line 1 </p>', u'\n ', u'<p> Line 2 </p>', u'\nLine 3\n']
好的,现在看来我们有了我们想要的节点(“标签”元素和文本节点)。但是你仍然在<p>
的输出中得到了那些“.extract()
”(XPath选择了元素,而不是它们的“内部”文本)。
所以你读了更多XPath并使用.//text()
步骤(大致是“所有子文本节点从这里”)
>>> response.xpath("//div/p[contains(., 'Description:')]/following-sibling::node()//text()").extract()
[u' Line 1 ', u' Line 2 ']
呃,等等,第3行去哪了?
事实上,此//
是/descendant-or-self::node()/
的缩写,因此./descendant-or-self::node()/text()
将仅选择下一个<p>
(文本节点)的子文本节点没有孩子,self::text()/text()
永远不会匹配任何文本节点)
>>> response.xpath("//div/p[contains(., 'Description:')]/following-sibling::node()/descendant-or-self::node()/text()").extract()
[u' Line 1 ', u' Line 2 ']
这里你可以做的是使用方便的descendant-or-self
轴+ text()
节点测试,所以如果following-sibling::node()
到达文本节点,{{1}中的“自我”将匹配文本节点,descendant-or-self
节点测试为true
text()
使用OP编辑过的问题中的示例网址:
>>> response.xpath("//div/p[contains(., 'Description:')]/following-sibling::node()/descendant-or-self::text()").extract()
[u'\n ', u' Line 1 ', u'\n ', u' Line 2 ', u'\nLine 3\n']