如何使用Nokogiri解析HTML表格?

34

我安装了Ruby和Mechanize。在我看来,使用Nokogiri可以实现我想做的事情,但我不知道该如何做。

这个table怎么样?它只是vBulletin论坛站点的一部分HTML。我试图保留HTML结构,但删除了一些文本和标记属性。我想获取每个主题的一些详细信息,例如:标题、作者、日期、时间、回复数和浏览量。

请注意,HTML文档中只有少数几个表格。我需要一个特定的带有其的表格,<tbody id="threadbits_forum_251">。名称将始终相同(我希望如此)。我能在代码中使用和吗?

<table >
  <tbody>
    <tr>  <!-- table header --> </tr>
  </tbody>
  <!-- show threads -->
  <tbody id="threadbits_forum_251">
    <tr>
      <td></td>
      <td></td>
      <td>
        <div>
          <a href="showthread.php?t=230708" >Vb4 Gold Released</a>
        </div>
        <div>
          <span><a>Paul M</a></span>
        </div>
      </td>
      <td>
          06 Jan 2010 <span class="time">23:35</span><br />
          by <a href="member.php?find=lastposter&amp;t=230708">shane943</a> 
        </div>
      </td>
      <td><a href="#">24</a></td>
      <td>1,320</td>
    </tr>

  </tbody>
</table>

实际上,属性可以使查找数据更容易,特别是使用xpath。 - Wayne Conrad
@Wayne,你能告诉我为什么属性可以使它更容易吗? - Radek
1
通常情况下,你会发现你需要的数据具有特定的属性,这恰好使得你能够更容易地构建一个xpath来挑选出这些数据。例如,如果你想要的表格是“<table class='message'>”,而其他的表格都不是你想要的但没有这个CSS类,那么选择你想要的表格的xpath就很简单: "//table[@class='message']"。 - Wayne Conrad
注意:在选择器中或使用<tbody>标签作为路标时要非常小心。虽然规范说明HTML应该有它们,但并不是必需的,许多HTML表定义中没有它们。问题在于浏览器在渲染页面时经常添加它们,并在查看页面源时显示它们,因此不要信任浏览器的HTML源视图。相反,请始终使用wget、curl或nokogiri在命令行中查看实际页面源以验证实际标记。 - the Tin Man
1个回答

56
#!/usr/bin/ruby1.8

require 'nokogiri'
require 'pp'

html = <<-EOS
  (The HTML from the question goes here)
EOS

doc = Nokogiri::HTML(html)
rows = doc.xpath('//table/tbody[@id="threadbits_forum_251"]/tr')
details = rows.collect do |row|
  detail = {}
  [
    [:title, 'td[3]/div[1]/a/text()'],
    [:name, 'td[3]/div[2]/span/a/text()'],
    [:date, 'td[4]/text()'],
    [:time, 'td[4]/span/text()'],
    [:number, 'td[5]/a/text()'],
    [:views, 'td[6]/text()'],
  ].each do |name, xpath|
    detail[name] = row.at_xpath(xpath).to_s.strip
  end
  detail
end
pp details

# => [{:time=>"23:35",
# =>   :title=>"Vb4 Gold Released",
# =>   :number=>"24",
# =>   :date=>"06 Jan 2010",
# =>   :views=>"1,320",
# =>   :name=>"Paul M"}]

3
我认为CSS的等效写法是 doc.css('tbody#threadbits_forum_251 tr'),但我实际上没有在代码中测试过…… - kejadlen
嗨,韦恩,我是Ruby Baby。首先...我安装了Mechanize,并且据说它使用Nokogiri进行解析,因此我可以使用HTML Nokogiri方法。但我无法像那样使用setpu使其工作。我必须单独安装Nokogiri吗?但是我似乎已经安装了它。doc = Nokogiri :: XML(f)给我一个错误./nokogiri.rb:7:未初始化常量Nokogiri(NameError)。老实说,我也不理解XPath。 //table/tbody[@id="threadbits_forum_251"]/tr 对我来说就像来自不同世界的魔术。我想说这意味着搜索id = xxx的table&tbody,但为什么/tr呢? - Radek
为什么代码以 // 开头?我找不到任何好的(对我来说足够好的)文档... - Radek
@Wayne,非常感谢您。我根据您的另一个示例更新了代码,现在它运行得非常好。我还有几个问题。其中最重要的是如果您能为我建议任何文档。下一个问题是为什么xpath末尾有/tr,您已经很好地向我解释了。我想提取帖子的url,我尝试了[:url,'td [3] / div [1] / a'],[:url,'td [3] / div [1] / a href / text()'],[:url,'td [3] / div [1] / a / href / text()'],[:url,'td [3] / div [1] / a / href'],但都没有奏效。我从哪里可以学习如何提取href、id、alt、src等内容?谢谢 - Radek
3
主要是因为数组哈希是可能最简单的实现方式,这使得示例更加清晰。此外,我不知道这对你是否有所影响,在 Ruby < 1.9 中,哈希没有明确定义的顺序,因此您将失去行的原始顺序。 - Wayne Conrad
显示剩余8条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接