2

I'm trying to extract some info from a table based website with hpricot. I get the XPath with FireBug.

/html/body/div/table/tbody/tr/td/table/tbody/tr[2]/td/table/tbody/tr/td[2]/table/tbody/tr[3]/td/table[3]/tbody/tr

This doesn't work... Apparently, the FireBug's XPath, is the path of the rendered HTML, and no the actual HTML from the site. I read that removing tbody may resolve the problem.

I try with:

/html/body/div/table/tr/td/table/tr[2]/td/table/tr/td[2]/table/tr[3]/td/table[3]/tr

And still doesn't work... I do a little more research, and some people report they get their XPath removing the numbers, so I try this:

/html/body/div/table/tr/td/table/tr/td/table/tr/td/table/tr/td/table/tr

Still no luck...

So I decide to do it step by step like this:

(doc/"html/body/div/table/tr").each do |aaa |
  (aaa/"td").each do | bbb|
        pp bbb
        (bbb/"table/tr").each do | ccc|
            pp ccc 
      end
  end
end

I find the info I need in bbb, but not in ccc.

What am I doing wrong, or is there better tool to scrap HTML with long/complex XPath.

4

5 回答 5

4

您的问题出在 XPather(或 firebug XPath)中。我认为 Firefox 正在内部修复格式错误的表格以具有 tbody 元素,即使在 HTML 中没有。Nokogiri 没有这样做,而是允许 tr 标签位于表格内。

所以很有可能你的路径看起来像这样的 nokogiri:

/html/body/div/table/tr/td/table/tr[2]/td/table/tr/td[2]/table/tr[3]/td/table[3]/tr

这就是nokogiri会接受它的方式:)

你可能想看看这个

require 'open-uri'
require 'nokogiri'

class String
  def relative_to(base)
    (base == self[0..base.length-1]) &&
      self[base.length..-1]
  end
end

module Importer
  module XUtils
    module_function

    def match(text, source)
      case text
      when String
        source.include? text
      when Regexp
        text.match(source)
      when Array
        text.all? {|tt| source.include?(tt)}
      else
        false
      end
    end

    def find_xpath (doc, start, texts)
      xpath = start
      found = true

      while(found)
        found = [:inner_html, :inner_text].any? do |m|
          doc.xpath(xpath+"/*").any? do |tag|
            tag_text = tag.send(m).strip.gsub(/[\302\240]+/, ' ')
            if tag_text && texts.all?{|text| match(text, tag_text)}
              xpath = tag.path.to_s
            end
          end
        end
      end

      (xpath != start) && xpath
    end

    def fetch(url)
      Nokogiri::HTML(open(url).read)
    end
  end
end

我写了这个小模块来帮助我在网络抓取和数据挖掘时使用 Nokogiri。

基本用法:

 include XUtils
 doc = fetch("http://some.url.here") # http:// is impotrtant!

 base = find_xpath(doc, '/html/body', ["what to find1", "What to find 2"]) # when you provide array, then it'll find element conaining ALL words

 precise = find_xpath(doc, base, "what to find1")
 precise.relative_to base

祝你好运

于 2009-06-09T12:21:38.840 回答
1

使用 hpricot 的 CSS 解析而不是 XPath 可能会更好。_why 曾经谈论过可能贬低 XPath。

你有更好的数据示例吗?他们是否使用易于引用的 css 标签?

像这样搜索要容易得多:

doc.search("#id_tag > table > tr.class_tag > td").each do |aaa|
    aaa.search("blah > blah").each do |bbb|
        bbb.inner_html

_why 的网站上有一个较旧的页面(我现在似乎找不到)正在讨论 hpricot,一些评论暗示在进行类似于你的嵌套搜索时,CSS 版本是如何比 XPath 更好的选择.

希望我能给出一个更好的答案,但我强烈建议先试一试 CSS 方法,看看它是如何进行的,然后再用 XPath 撕掉你的头发。

于 2009-04-10T06:43:09.350 回答
1

我现在正在使用 css,并用这个很棒的工具“计算”它:www.selectorgadget.com

于 2009-04-30T10:44:11.447 回答
1

值得注意的是,Nokogiri使用与 Hpricot 相同的 API,但也支持 XPath 表达式。

于 2009-05-11T05:21:50.797 回答
0

您的 HTML 代码中没有 TBODY 标记。Firebug 会自动生成它。

于 2010-08-22T00:43:44.117 回答