Scrapy 无法识别 Firebug 列出的 "tbody" 和 "ul" 元素

Scrapy can't identify "tbody" and "ul" elements as listed by Firebug

我正在尝试提取此 mailing list 的每个标题,同时记录每个线程有多少回复。

根据 Firebug,包含所有标题的 <ul> 的 Xpath 是:

/html/body/table[2]/tbody/tr1/td[2]/table/tbody/tr/td/ul

但是,如果我直接将它粘贴到 Scrapy Shell,它会产生一个空列表:

scrapy shell http://seclists.org/fulldisclosure/2002/Jul/index.html
response.xpath('/html/body/table[2]/tbody/tr[1]/td[2]/table/tbody/tr/td/ul')
[]

经过反复试验(因为我无法从文档中找出任何方法来列出给定选择器的直接 sub-elements(如果您知道,请告诉他们),我想发现元素“tbody”在 Xpath 上不起作用。通过删除它们,我能够导航到 /td:

almost_email_threads = response.xpath('/html/body/table[2]/tr[1]/td[2]/table/tr/td')

但是,如果我现在尝试达到“ul”,它将不起作用:

email_threads.xpath('/ul')
[]

现在,最让我困惑的是 运行:

response.xpath('/html/body/table[2]/tr[1]/td[2]/table/tr/td//ul')

给我 ul,但顺序与网站上显示的顺序不同。它以不同的顺序跳过线程。此外,似乎无法计算每个线程的回复量。

我在这里错过了什么?自从我使用 Scrapy 以来已经有一段时间了,但我不记得有这么难弄清楚,而且无论出于何种原因,教程都没有为我提供 Bing 或 Google。

我从未使用过 Firebug,但查看您引用的 HTML 页面,我会说以下 XPath 表达式将为您提供所有顶级线程:

//li[not(ancestor::li) and ./a/@name]

从每个列表元素开始,您需要计算列表的数量 children 以获得对任何给定线程的回复数量。

使用 Scrapy shell,结果是:

> scrapy shell http://seclists.org/fulldisclosure/2002/Jul/index.html
In [1]: threads = response.xpath('//li[not(ancestor::li) and ./a/@name]')
In [2]: for thread in threads:
   ...:     print thread, len(thread.xpath('descendant::li'))
<Selector xpath='//li[not(ancestor::li) and ./a/@name]' data=u'<li><a name="0" href="0">Testing</a> <em'> 0
<Selector xpath='//li[not(ancestor::li) and ./a/@name]' data=u'<li><a name="1" href="1">full disclosure'> 4
<Selector xpath='//li[not(ancestor::li) and ./a/@name]' data=u'<li><a name="3" href="3">The Death Of TC'> 1
<Selector xpath='//li[not(ancestor::li) and ./a/@name]' data=u'<li><a name="7" href="7">Re: Announcing '> 24
[...]

关于如何从给定选择器中列出所有 sub-elements 的问题,您只需要意识到 运行 选择器上的 XPath 查询的结果是 SelectorList其中每个列表元素实现 Selector 接口。因此,您可以简单地再次使用 XPath,例如列出所有 children:

In [3]: thread.xpath('child::*')
Out[3]: 
[<Selector xpath='child::*' data=u'<a name="309" href="309">it\'s all about '>,
 <Selector xpath='child::*' data=u'<em>Florin Andrei (Jul 31)</em>'>,
 <Selector xpath='child::*' data=u'<ul>\n<li><a name="313" href="313">it\'s a'>]