如何使用带有nokogiri的XPath解析for循环中的inner_html

时间:2013-06-19 14:32:07

标签: ruby nokogiri

我在一个只有我发现的inner_html的for循环中解析时遇到了麻烦。我想在内容中再次使用XPath。我是ruby的新手,所以更好的解决方案就在桌面上。

#!/usr/bin/ruby -w

require 'rubygems'
require 'nokogiri'

page1 = Nokogiri::HTML(open('mycontacts.html'))


# Search for nodes by xpath
page1.xpath('//html/body/form/div[2]/span/table/tbody/tr').each do |row|
  #puts a_tag.content
  puts "new row"
  row_html = row.inner_html

  puts row_html
  puts ""

  name = row_html.xpath("/td[1]").text
  puts "name is " + name

end

for循环中每行的输出类似于:

new row
<th>First Name</th>
<th>Last Name</th>
<th>Phone</th>

这是我得到的错误:

screen-scraper.rb:20:在block in <main>': undefined method xpath'中#(NoMethodError)

我想解析每个tr并得到如下数据:Barney Rubble,Fred Flintstone

<table>
    <tbody>
        <tr>
            <th>First Name</th>
            <th>Last Name</th>
        </tr>
        <tr>
            <td>Fred</td>
            <td>Flintstone</td>
        </tr>
        <tr>
            <td>Barney</td>
            <td>Rubble</td>
        </tr>
    </tbody>
</table>

我愿意接受建议。我认为只解析for循环中的inner_html更容易,但是如果有更容易的方法来获取for循环中的节点,那也可以。

...谢谢

3 个答案:

答案 0 :(得分:1)

您可以修复它而不是使用name = row_html.xpath("/td[1]").text,使用name = Nokogiri::HTML(row_html).xpath("/td[1]").text。如果你分享了你的完整HTML,那么有一种很好的技巧。

Nokogiri::HTML(row_html)会为您提供课程Nokogiri::HTML::Document的实例。现在#xpath#css#search所有方法都是Nokogiri::HTML::Document类的实例方法。

考虑到如果您的inner_html生成了您提供的HTML表格,那么您可以将其想象如下。

我测试了代码,并希望它会给你结果:

require "nokogiri"

doc = Nokogiri::HTML(<<-eohl)
<table>
    <tbody>
        <tr>
            <th>First Name</th>
            <th>Last Name</th>
        </tr>
        <tr>
            <td>Fred</td>
            <td>Flintstone</td>
        </tr>
        <tr>
            <td>Barney</td>
            <td>Rubble</td>
        </tr>
    </tbody>
</table>
eohl

doc.css("table > tbody > tr"). each do |nd|
 nd.children.each{|i| print i.text.strip,"  " unless i.text.strip == "" }
 print "\n"
end
# >> First Name  Last Name  
# >> Fred  Flintstone  
# >> Barney  Rubble 

现在看看#inner_html给出了什么,哪个会回答你为什么你有没有这样的方法错误:

require "nokogiri"

doc = Nokogiri::HTML(<<-eohl)
<table>
    <tbody>
        <tr>
            <th>First Name</th>
            <th>Last Name</th>
        </tr>
        <tr>
            <td>Fred</td>
            <td>Flintstone</td>
        </tr>
        <tr>
            <td>Barney</td>
            <td>Rubble</td>
        </tr>
    </tbody>
</table>
eohl

doc.search("table > tbody > tr"). each do |nd|
 p nd.inner_html.class
end

# >> String
# >> String
# >> String

答案 1 :(得分:1)

问题是由row_html获得的Nokogiri::XML::Node#inner_html只是一个字符串。 要再次调用xpath,必须先使用Nokogiri::HTML(row_html)使用Nokogiri再次解析字符串。

更好的方法是从不首先拨打inner_html,将row保留为Nokogiri::XML::Node,然后拨打row.xpath(...)

例如,使用您提供的表格并输出您想要的内容:

page1.xpath('//html/body/form/div[2]/span/table/tbody/tr').each do |row|
    puts "#{row.children[0].text} #{row.children[1].text}"
end

答案 2 :(得分:1)

  

...我注意到Firebug会产生一些与Nokogiri(或它的依赖项)不兼容的xpath表达式。我对Chrome的Debug XPath输出感到好运。

Firebug或浏览器的许多其他XPath输出的问题是,在生成XPath并合成<tbody>标记时,它们遵循HTML规范,即使原始源没有。 XPath反映了这一点。

我们将原始HTML传递给Nokogiri进行解析,以及错误的XPath,Nokogiri找不到<table><tbody><tr>链。

这是一个例子。从这个HTML开始:

<html>
  <body>
    <table>
      <tr>
        <td>
          foo
        </td>
      </tr>
    </table>
  </body>
</html>

将其保存到文件并在Firefox,Chrome或Safari中打开,然后查看来源,并在Firebug或其等效文件中查看。

你会看到这样的东西,来自Firefox:

<table>
  <tbody><tr>
    <td>
      foo
    </td>
  </tr>
</tbody></table>

要解决此问题,请不要依赖浏览器生成的XPath,并通过在文本编辑器中仅查看 RAW HTML来确认表的结构。 “查看源代码”选项对某些内容非常有用,但如果您发现任何<tbody>个代码是可疑的,请转而使用编辑器进行检查。

此外,您不需要整个标记链来到达内部标记。相反,在路上寻找一些有助于找到目标节点的地标。如今,大多数HTML网页都在重要标记中包含classid个参数。 ID参数特别好,因为它们必须是唯一的。如果存在唯一的其他参数,那么这些参数也可以工作。

有时您不会在您想要的标签之前找到识别标签,但其中嵌入了一些内容。然后,找到该嵌入式标签并逐步升级链,直到找到所需内容。使用XPath你可以使用..(父),但是使用CSS你必须依赖Nokogiri :: XML :: Node的parent方法,因为Nokogiri和CSS不支持父选择器(尚未)。