xpath - 在无语义表中获取从标题到下一个标题的 sibling

标签 xpath scrapy

使用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-siblingpreceding-siblingcount 的变体),但我要么什么也没得到,要么什么都得不到tr 这不是 header 。

我目前正在使用 //tr[@style]//tr[td[@colspan="4"]] 获取 header 。

以下是我的 Scrapy-spider 中的解析函数(它打印标题和所有不是标题的 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])]')

最佳答案

此 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) 个 header 之间的所有 tr 元素,只需将上述表达式中的 1 替换为 K(数字)和 2 以及 K+1(数字)。

基于 XSLT 的验证:

<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>

当此转换应用于提供的 XML 文档时:

<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 表达式并将所选节点复制到输出:

<tr>
   <td>Title1.1</td>
   <td>-</td>
   <td>Info1.1</td>
   <td/>
</tr>

说明:

这是 Kayessian(Michael Kay 博士之后)公式在节点集交集上的简单应用:

$ns1[count(.|$ns2) = count($ns2)]

在这种特殊情况下,我们将 $ns1 替换为:

/*/tr[@style or td[@colspan='4']][1]/following-sibling::tr

我们将 $ns2 替换为:

/*/tr[@style or td[@colspan='4']][2]/preceding-sibling::tr

关于xpath - 在无语义表中获取从标题到下一个标题的 sibling ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14074462/

相关文章:

html - 使用 scrapy 和 xpath 在::before 和::after 之间抓取 HTML 元素

python - xpath 获取表中的第三个 tr 及更多内容

cookies - 如何将 Scrapy 登录 cookie 传递给 Selenium?

python - 如何使用 Python Scrapy 模块列出我网站上的所有 URL?

xslt - 如何识别 XSLT 输入或 XPath 中的行号?

python - 带有 Xpath/BeautifulSoup 的 h3/h2 标签之间的 HTML

c# - HTML 敏捷包 2

python - 如何使用scrapy选择表格?

python-3.x - 抓取 + 飞溅 : not rendering full page javascript data

selenium - 如何在 Scrapinghub 上安装 xvfb 以使用 Selenium?