使用Nokogiri遍历没有CSS类的HTML?

时间:2012-01-31 12:38:53

标签: ruby-on-rails ruby xpath nokogiri

我有以下HTML:

<table width="100%" border="0" cellpadding="6" cellspacing="1">
  <tbody>
    <tr>
      <td bgcolor="#ffd204" width="40%" nowrap=""><b>Tracking Number:</b></td>
      <td bgcolor="#ffffff" width="60%" nowrap="">C123456789012345</td>
    </tr>
    <!-- ...there could be additional table rows here... -->
    <tr>
      <td bgcolor="#ffd204" width="40%" nowrap=""><b>Deliver To:</b></td>
      <td bgcolor="#ffffff" width="60%" nowrap="">ANYWHERE, NY</td>
    </tr>
  </tbody>
</table>

比如说,我需要提取ANYWHERE, NY数据。我怎么用Nokogiri呢?或者是否有更好的东西来遍历这种没有任何CSS选择器来搜索的东西?

2 个答案:

答案 0 :(得分:8)

由于我们没有要使用的CSS类,id属性或其他语义标记,我们会在本文档中寻找可能不会更改的内容来锚定我们的搜索。在这种情况下,我怀疑“Deliver To:”标签总是在我们想要的td之前。所以:

require 'nokogiri'

html = # Fetch either from http via open-uri's open() or from file via IO.read()
doc = Nokogiri.HTML(html) 
delivery = doc.at_xpath '//td[preceding-sibling::td[b="Deliver To:"]]/text()'    
p delivery.content
#=> "ANYWHERE, NY"

XPath表达式说:

  • // - 在任何级别,
  • td - 找到一个名为td
  • 的元素
  • […] - 但仅限......
    • preceding-sibling:: - 它有一个先前的兄弟
    • td - 这是一个名为td
    • 的元素
    • […] - 但仅限......
      • b - 它有一个名为b
      • 的子元素
      • ="Deliver To:" - 其文字内容等于此字符串
  • /text() - 然后找到td的子文本节点。

因为我们使用at_xpath而不是xpath,所以Nokogiri返回它可以找到的第一个匹配节点 - 在这种情况下碰巧是该td的唯一子文本节点 - 而不是数组节点

如果<td>可以有标记,例如<td…>ANYWHERE,<br>NY</td>,您可以修改表达式以省略尾随/text()(这样您只选择<td>本身)然后使用text方法获取其中的组合可见文本。

答案 1 :(得分:0)

鉴于您不介意进行一些预处理,您可以这样做:

lookup = {}
c = Nokogiri::HTML(open("http://..."))
c.search("tr").each do |tr|
  cells = tr.search("td")
  lookup[cells.first.text.gsub(':', '')] = cells.last.text
end

puts lookup["Tracking Number"]

我没有测试该代码,因此可能存在一些语法问题。