使用Nokogiri解析表

时间:2011-01-31 12:30:05

标签: ruby xpath nokogiri

我想用Nokogiri解析一张桌子。我是这样做的

def parse_table_nokogiri(html)

    doc = Nokogiri::HTML(html)

    doc.search('table > tr').each do |row|
        row.search('td/font/text()').each do |col|
            p col.to_s
        end
    end

end

我有一些表有这样的行:

<tr>
  <td>
     Some text
  </td>
</tr>

......有些人有这个。

<tr>
  <td>
     <font> Some text </font>
  </td>
</tr>

我的XPath表达式适用于第二种情况,但不适用于第一种情况。是否有一个我可以使用的XPath表达式,它将从单元格的最内层节点给我文本,以便我可以处理这两种情况?


我已将更改合并到我的代码段

def parse_table_nokogiri(html)

    doc = Nokogiri::HTML(html)
    table = doc.xpath('//table').max_by {|table| table.xpath('.//tr').length}

    rows = table.search('tr')[1..-1]
    rows.each do |row|

        cells = row.search('td//text()').collect {|text| CGI.unescapeHTML(text.to_s.strip)}
        cells.each do |col|

            puts col
            puts "_____________"

        end

    end

end

3 个答案:

答案 0 :(得分:6)

使用

td//text()[normalize-space()]

这将选择当前节点的任何td子节点(代码中已选择tr)的所有非空白空间文本节点后代。

或者,如果您想选择所有文本节点后代,请考虑它们是否只是空格:

td//text()

<强>更新

OP已在评论中发出信号,表示他收到的内容只有td(又称不间断的空间)。{/ p>

要同时排除其内容仅由(一个或多个)字符组成的'&#160;',请使用:

td

答案 1 :(得分:2)

简单:

doc.search('//td').each do |cell|
  puts cell.content
end

答案 2 :(得分:1)

简单(但不是干)使用交替的方式:

require 'nokogiri'

doc = Nokogiri::HTML <<ENDHTML
<body><table><thead><tr><td>NOT THIS</td></tr></thead><tr>
  <td>foo</td>
  <td><font>bar</font></td>
</tr></table></body>
ENDHTML

p doc.xpath( '//table/tr/td/text()|//table/tr/td/font/text()' )
#=> [#<Nokogiri::XML::Text:0x80428814 "foo">,
#=>  #<Nokogiri::XML::Text:0x804286fc "bar">]

有关更干的答案,请参阅XPath with optional element in hierarchy

但是,在这种情况下,您只需执行以下操作:

p doc.xpath( '//table/tr/td//text()' )
#=> [#<Nokogiri::XML::Text:0x80428814 "foo">,
#=>  #<Nokogiri::XML::Text:0x804286fc "bar">]

请注意,没有明确tbody元素的表结构(以及我的上面)对XHTML无效。但是,鉴于您明确table > tr,我认为您有理由这样做。