xpath parent 和 scrapy 中的后代

xpath parent and descendants in scrapy

我正在使用代码

response.xpath("//*[contains(text(), 'Role')]/parent/parent/descendant::td//text()").extract()

到 select 所有 td text() 内容来自以下行中的单词 'Role' 在以下内容中找到 html table:

<table class="wh_preview_detail" border="1">
   <tr>
      <th colspan="3">
         <span class="wh_preview_detail_heading">Names</span>
      </th>
   </tr>
   <tr>
      <th>Role</th>
      <th>Name No</th>
      <th>Name</th>
   </tr>
   <tr>
      <td>Requestor</td>
      <td>589528</td>
      <td>John</td>
   </tr>
   <tr>
      <td>Helper</td>
      <td>589528</td>
      <td>Mary</td>
   </tr>
</table>

'Role' 关键字仅用作 table 的标识符。

在这种情况下,我期待结果:

['Requestor', '589528', 'John', ...]

然而,我在 scrapy 中执行时得到一个空数组。

我的目标是最终将元素再次分组为记录。 我花了几个小时尝试其他人的示例并在终端和 Chrome 中进行试验,但现在除了 'simple' XPath 之外的所有内容都超出了我的范围。 我希望了解 Xpath,因此理想情况下想要一个带有解释的通用答案,这样我就可以学习和分享。谢谢你。

作为一般性建议,通过沿着树向下一步一步地构建 XPath 表达式通常更容易,而不是一直向下选择 //typeiwant,然后为树中之前的内容添加谓词(与 parent 或祖先)

让我们看看如何使用 Scrapy 选择器解决您的用例:

>>> import scrapy
>>> t = '''<table class="wh_preview_detail" border="1">
...    <tr>
...       <th colspan="3">
...          <span class="wh_preview_detail_heading">Names</span>
...       </th>
...    </tr>
...    <tr>
...       <th>Role</th>
...       <th>Name No</th>
...       <th>Name</th>
...    </tr>
...    <tr>
...       <td>Requestor</td>
...       <td>589528</td>
...       <td>John</td>
...    </tr>
...    <tr>
...       <td>Helper</td>
...       <td>589528</td>
...       <td>Mary</td>
...    </tr>
... </table>'''
>>> selector = scrapy.Selector(text=t, type="html")
>>>
>>> # what you want comes inside a <table>,
>>> # after a <tr> that has a child `<th>` with text "Role" inside
>>> selector.xpath('//table/tr[th[1]="Role"]')
[<Selector xpath='//table/tr[th[1]="Role"]' data=u'<tr>\n      <th>Role</th>\n      <th>Name '>]
>>>
>>> # check with .extract() is that's the one...
>>> selector.xpath('//table/tr[th[1]="Role"]').extract()
[u'<tr>\n      <th>Role</th>\n      <th>Name No</th>\n      <th>Name</th>\n   </tr>']
>>> 

然后,您感兴趣的行与 <tr> 和 "Role" 处于同一树级别。在 XPath 术语中,这些 <tr> 元素沿着 following-sibling

>>> for row in selector.xpath('//table/tr[th[1]="Role"]/following-sibling::tr'):
...     print('------')
...     print(row.extract())
... 
------
<tr>
      <td>Requestor</td>
      <td>589528</td>
      <td>John</td>
   </tr>
------
<tr>
      <td>Helper</td>
      <td>589528</td>
      <td>Mary</td>
   </tr>
>>> 

所以你有每一行,每行有 3 个单元格,映射到 3 个字段:

>>> for row in selector.xpath('//table/tr[th[1]="Role"]/following-sibling::tr'):
...     print({
...         "role": row.xpath('normalize-space(./td[1])').extract_first(),
...         "number": row.xpath('normalize-space(./td[2])').extract_first(),
...         "name": row.xpath('normalize-space(./td[3])').extract_first(),
...     })
... 
{'role': u'Requestor', 'number': u'589528', 'name': u'John'}
{'role': u'Helper', 'number': u'589528', 'name': u'Mary'}
>>>