2

我在只找到我发现的 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:in block in <main>': undefined methodxpath' for # (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 循环内获取节点,那也可以。

谢谢....

4

3 回答 3

1

您可以修复它而不是使用name = row_html.xpath("/td[1]").text,use 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
于 2013-06-19T14:41:16.217 回答
1

...我注意到 Firebug 产生的一些 xpath 表达式不适用于 Nokogiri(或其依赖项)。我对 Chrome 的 Debug XPath 输出有更好的运气。

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

我们将原始 HTML 与错误的 XPath 一起传递给 Nokogiri 进行解析,但 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 不支持父选择器(目前)。

于 2013-06-21T06:37:01.717 回答
1

The problem is that row_html, obtained by Nokogiri::XML::Node#inner_html, is just a String. To call xpath on it again, you must first parse the string again with Nokogiri using Nokogiri::HTML(row_html).

A better way though would be to never call inner_html in the first place, leave row as a Nokogiri::XML::Node, and then call row.xpath(...).

For example, with a table like you provided and output you wanted:

page1.xpath('//html/body/form/div[2]/span/table/tbody/tr').each do |row|
    puts "#{row.children[0].text} #{row.children[1].text}"
end
于 2013-06-19T14:50:08.533 回答