我需要在一组页面上提取数据表。我已经可以遍历页面了。
如何提取表格的数据?我正在使用Ruby和Nokogiri,但我认为这是一个相当普遍的问题。
我在the following image中的每一行中加下了所需的数据点。
html的示例是:http://pastebin.com/YYFPbFLC
我如何通过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区分它的方法,除非第二列可靠地包含“keyword
”。每个行都有一个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[2]
第一行数据的最后一列是:
/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]
答案 0 :(得分:6)
XPath的第一条规则是:永远不要使用来自Firebug或其他浏览器工具的自动生成的XPath。这会创建脆弱的XPath,将所有页面元素视为同等重要且必需的,甚至是您不关心的部分。例如,如果页面顶部的通知出现并且恰好位于表格中,则可能会导致解析失败。
相反,想一想人类如何识别它。在这种情况下,您需要“标题下的第一个表格,其中包含'今天'字样”。这是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
输出结果为:
[
{:magnitude=>"F1.7",
:temp_area=>"0",
:time_start=>"01:11:00",
:time_middle=>"01:24:00",
:time_end=>"01:32:00"},
{:magnitude=>"F3.1",
:temp_area=>"0",
:time_start=>"04:01:00",
:time_middle=>"04:10:00",
:time_end=>"04:26:00"},
{:magnitude=>"F3.5",
:temp_area=>"134F55",
:time_start=>"06:24:00",
:time_middle=>"06:42:00",
:time_end=>"06:53:00"},
{:magnitude=>"F1.4",
:temp_area=>"0",
:time_start=>"11:58:00",
:time_middle=>"12:06:00",
:time_end=>"12:16:00"},
{:magnitude=>"F1.0",
:temp_area=>"0",
:time_start=>"13:02:00",
:time_middle=>"13:05:00",
:time_end=>"13:09:00"},
{:magnitude=>"D53.7",
:temp_area=>"134F55",
:time_start=>"17:37:00",
:time_middle=>"18:37:00",
:time_end=>"18:56:00"}
]