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'}
>>>
我正在使用代码
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'}
>>>