Ruby on rails 如何将表解析为有意义的块?
我需要在一组页面上提取一个数据表。我已经可以很好地浏览页面了 如何提取表的数据?我使用的是Ruby和Nokogiri,但我认为这是一个相当普遍的问题 我在中的每一行中标出了所需的数据点 html的一个示例是: 我如何通过Nokogiri将这个表解析成一个散列,并将其分解成有意义的块 该表的xpath是: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
/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。是的,昨晚没有时间添加样本,所以我希望最后一次编辑会有所帮助!