使用Scrapy我想解析一个包含非语义表的网页。我正在寻找的是“打印每一个兄弟,直到你遇到以下元素”-XPath-query。
<table>
<tr>
<th>Title</th>
<th>Name</th>
<th>Comment</th>
<th>Note</th>
</tr>
<tr style="background-color:#CCDDEF;">
<td colspan="4"> <b>HEADER1</b></td>
</tr>
<tr>
<td>Title1.1</td>
<td>-</td>
<td>Info1.1</td>
<td></td>
</tr>
<tr style="background-color:#CCDDEF;">
<td colspan="4"> <b>HEADER2</b></td>
</tr>
<tr>
<td>Title2.1</td>
<td>Name2.1</td>
<td></td>
<td></td>
</tr>
<tr>
<td>Title2.2</td>
<td>Name2.2</td>
<td>Info2.2</td>
<td></td>
</tr>
<tr style="background-color:#CCDDEF;">
<td colspan="4"> <b>HEADER3</b></td>
</tr>
<tr>
<td>Title3.1</td>
<td>Name3.1</td>
<td></td>
<td></td>
</tr>
</table>
我想将每个标题下的每个标题,名称,注释和注释分组。我尝试过使用各种XPath(following-sibling
,preceding-sibling
和count
的变体),但我得到的一切都没有,或者每个tr
都不是标题。
我目前正在使用//tr[@style]
或//tr[td[@colspan="4"]]
收件人。
以下是我的Scrapy-spider中的parse-function(它打印标题和所有tr
不是标题):
def parse(self, response):
hxs = HtmlXPathSelector(response)
sites = hxs.select('//*[@id="content-text"]//tr[td[@colspan="4"]]')
for site in sites:
print site.select('./td/b/text()').extract()
print site.select('./following-sibling::tr[not(td[@colspan])]')
答案 0 :(得分:2)
此XPath表达式:
/*/tr[@style or td[@colspan='4']][1]/following-sibling::tr
[count(. | /*/tr[@style or td[@colspan='4']][2]/preceding-sibling::tr)
=
count(/*/tr[@style or td[@colspan='4']][2]/preceding-sibling::tr)
]
选择第一个和第二个标题之间的所有tr
元素:
<tr>
<td>Title1.1</td>
<td>-</td>
<td>Info1.1</td>
<td/>
</tr>
要选择位于第K个和第(K + 1)个标头之间的所有tr
元素,只需将上述表达式1
替换为K
(数字)和{{ 1}} 2
(数字)。
基于XSLT的验证:
K+1
在提供的XML文档上应用此转换时:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<xsl:copy-of select=
"/*/tr[@style or td[@colspan='4']][1]/following-sibling::tr
[count(. | /*/tr[@style or td[@colspan='4']][2]/preceding-sibling::tr)
=
count(/*/tr[@style or td[@colspan='4']][2]/preceding-sibling::tr)
]
"/>
</xsl:template>
</xsl:stylesheet>
评估Xpath表达式并将选定的节点复制到输出中:
<table>
<tr>
<th>Title</th>
<th>Name</th>
<th>Comment</th>
<th>Note</th>
</tr>
<tr style="background-color:#CCDDEF;">
<td colspan="4">
<b>HEADER1</b>
</td>
</tr>
<tr>
<td>Title1.1</td>
<td>-</td>
<td>Info1.1</td>
<td></td>
</tr>
<tr style="background-color:#CCDDEF;">
<td colspan="4">
<b>HEADER2</b>
</td>
</tr>
<tr>
<td>Title2.1</td>
<td>Name2.1</td>
<td></td>
<td></td>
</tr>
<tr>
<td>Title2.2</td>
<td>Name2.2</td>
<td>Info2.2</td>
<td></td>
</tr>
<tr style="background-color:#CCDDEF;">
<td colspan="4">
<b>HEADER3</b>
</td>
</tr>
<tr>
<td>Title3.1</td>
<td>Name3.1</td>
<td></td>
<td></td>
</tr>
</table>
<强>解释强>:
这是Kayessian(在Michael Kay博士之后)节点集交集公式的简单应用:
<tr>
<td>Title1.1</td>
<td>-</td>
<td>Info1.1</td>
<td/>
</tr>
在这个特例中,我们用$ns1[count(.|$ns2) = count($ns2)]
代替:
$ns1
我们将/*/tr[@style or td[@colspan='4']][1]/following-sibling::tr
替换为:
$ns2