yll*_*ate 0 ruby xpath screen-scraping ruby-on-rails nokogiri
我需要在一组页面上提取数据表.我已经可以遍历页面了.
如何提取表格的数据?我正在使用Ruby和Nokogiri,但我认为这是一个相当普遍的问题.
我在下图中的每一行中加下了所需的数据点.
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
Run Code Online (Sandbox Code Playgroud)
该表具有可变数量的数据行和格式化行.我只想收集包含有意义数据的行,但是我不容易看到通过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]
Run Code Online (Sandbox Code Playgroud)
需要匹配"关键字"上的文本内容的第一个有意义的列是:
/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]
Run Code Online (Sandbox Code Playgroud)
第一行数据的最后一列是:
/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]
Run Code Online (Sandbox Code Playgroud)
每行都是一条记录,并且该列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]
Run Code Online (Sandbox Code Playgroud)
XPath的第一条规则是:永远不要使用Firebug或其他浏览器工具中的自动生成的XPath.这会创建脆弱的XPath,将所有页面元素视为同等重要且必需的,甚至是您不关心的部分.例如,如果页面顶部的通知出现并且恰好位于表中,则可能会导致解析失败.
相反,想想一个人如何识别它.在这种情况下,您需要"标题下的第一个表格,其中包含'今天'字样".这是XPath:
//table[preceding-sibling::h2[contains(text(), "today")]][1]
Run Code Online (Sandbox Code Playgroud)
这表示采用具有前面的表h2(换句话说,在其后面h2),其中h2包含单词"today".然后拿第一个这样的表.
然后,您需要确定您感兴趣的行.请注意,某些行只是包含单个行的分隔符td,因此您需要确保只解析具有多个td标记的行.在XPath中,即:
//tr[td[2]]
Run Code Online (Sandbox Code Playgroud)
然后你只需抓住所有列的内容.在第一个中,您可以删除"大小"之前的所有内容,以获得唯一的值.把它们放在一起:
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
Run Code Online (Sandbox Code Playgroud)
输出是:
[
{: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"}
]
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1816 次 |
| 最近记录: |