Ruby on rails 如何将表解析为有意义的块?

Ruby on rails 如何将表解析为有意义的块?,ruby-on-rails,ruby,xpath,screen-scraping,nokogiri,Ruby On Rails,Ruby,Xpath,Screen Scraping,Nokogiri,我需要在一组页面上提取一个数据表。我已经可以很好地浏览页面了 如何提取表的数据?我使用的是Ruby和Nokogiri,但我认为这是一个相当普遍的问题 我在中的每一行中标出了所需的数据点 html的一个示例是: 我如何通过Nokogiri将这个表解析成一个散列,并将其分解成有意义的块 该表的xpath是: /html/body/table/tbody/tr/td[2]/table/tbody/tr[2]/td/table/tbody/tr/td[2]/table/tbody/tr/td/table

我需要在一组页面上提取一个数据表。我已经可以很好地浏览页面了

如何提取表的数据?我使用的是Ruby和Nokogiri,但我认为这是一个相当普遍的问题

我在中的每一行中标出了所需的数据点

html的一个示例是:

我如何通过Nokogiri将这个表解析成一个散列,并将其分解成有意义的块

该表的xpath是:

/html/body/table/tbody/tr/td[2]/table/tbody/tr[2]/td/table/tbody/tr/td[2]/table/tbody/tr/td/table/tbody/tr/td[2]/table
该表具有可变数量的数据行和格式化行。我只想收集包含有意义数据的行,但我不想通过XPath来区分这一点,除非第二列中可靠地包含“
关键字”
”。这些行中的每一行都有一个XPath:

1st meaningful row is: /html/body/table/tbody/tr/td[2]/table/tbody/tr[2]/td/table/tbody/tr/td[2]/table/tbody/tr/td/table/tbody/tr/td[2]/table/tbody/tr[2]
...
Last meaningful row: /html/body/table/tbody/tr/td[2]/table/tbody/tr[2]/td/table/tbody/tr/td[2]/table/tbody/tr/td/table/tbody/tr/td[2]/table/tbody/tr[N]
需要匹配“关键字”上文本内容的第一个有意义的列是:

第一行数据的最后一列是:

/html/body/table/tbody/tr/td[2]/table/tbody/tr[2]/td/table/tbody/tr/td[2]/table/tbody/tr/td/table/tbody/tr/td[2]/table/tbody/tr[2]/td[6]
每一行都是一条记录,有一个时间戳,该列/
td
是时间戳中的时间;年、月和日都在各自的变量中,可以附加为完整的时间戳:

/html/body/table/tbody/tr/td[2]/table/tbody/tr[2]/td/table/tbody/tr/td[2]/table/tbody/tr/td/table/tbody/tr/td[2]/table/tbody/tr[2]/td[5]

XPath的第一条规则是:永远不要使用Firebug或其他浏览器工具自动生成的XPath。这就创建了脆弱的XPath,它将所有页面元素视为同等重要和必需的元素,甚至是您不关心的部分。例如,如果一个通知出现在页面顶部,而它恰好位于一个表中,那么它可能会中断您的解析

相反,想想人类是如何识别它的。在本例中,您需要“标题下的第一个表,其中包含单词'today'。下面是XPath:

//table[preceding-sibling::h2[contains(text(), "today")]][1]
也就是说,以前面有
h2
的表为例(换句话说,在
h2
之后),其中
h2
包含单词“今天”。那就拿第一张这样的桌子

然后,您需要确定感兴趣的行。请注意,有些行只是包含单个
td
的分隔符,因此您需要确保只解析具有多个
td
标记的行。在XPath中,即:

//tr[td[2]]
然后,您只需获取所有列的内容。在第一种方法中,您可以删除单词“数量级”之前的所有内容,以获得值。总而言之:

doc = Nokogiri::HTML.parse(html)

events = []

doc.xpath('//table[preceding-sibling::h2[contains(text(), "today")]][1]//tr[td[2]]').each do |row|
  cols = row.search('td/text()').map(&:to_s)
  events << {
    :magnitude   => cols[0].gsub(/^.*of magnitude /,''),
    :temp_area   => cols[1],
    :time_start  => cols[2],
    :time_middle => cols[3],
    :time_end    => cols[4]
  }
end

XPath的第一条规则是:永远不要使用Firebug或其他浏览器工具自动生成的XPath。这就创建了脆弱的XPath,它将所有页面元素视为同等重要和必需的元素,甚至是您不关心的部分。例如,如果一个通知出现在页面顶部,而它恰好位于一个表中,那么它可能会中断您的解析

相反,想想人类是如何识别它的。在本例中,您需要“标题下的第一个表,其中包含单词'today'。下面是XPath:

//table[preceding-sibling::h2[contains(text(), "today")]][1]
也就是说,以前面有
h2
的表为例(换句话说,在
h2
之后),其中
h2
包含单词“今天”。那就拿第一张这样的桌子

然后,您需要确定感兴趣的行。请注意,有些行只是包含单个
td
的分隔符,因此您需要确保只解析具有多个
td
标记的行。在XPath中,即:

//tr[td[2]]
然后,您只需获取所有列的内容。在第一种方法中,您可以删除单词“数量级”之前的所有内容,以获得值。总而言之:

doc = Nokogiri::HTML.parse(html)

events = []

doc.xpath('//table[preceding-sibling::h2[contains(text(), "today")]][1]//tr[td[2]]').each do |row|
  cols = row.search('td/text()').map(&:to_s)
  events << {
    :magnitude   => cols[0].gsub(/^.*of magnitude /,''),
    :temp_area   => cols[1],
    :time_start  => cols[2],
    :time_middle => cols[3],
    :time_end    => cols[4]
  }
end

最好发布html。那些XPath不容易看。谢谢@pguardiario。是的,昨晚没有时间添加样本,所以我希望最后一次编辑会有所帮助!最好发布html。那些XPath不容易看。谢谢@pguardiario。是的,昨晚没有时间添加样本,所以我希望最后一次编辑会有所帮助!