使用Ruby和Mechanize来制作新的奥运奖牌

时间:2012-08-03 22:40:44

标签: ruby mechanize

我想重拍伦敦2012年的奥运奖牌数,以更好地反映奖牌的价值。目前它只按金牌排序。我想用积分来重新计算,所以gold = 4,silver = 2和bronze = 1来制作一个更合理的新列表。我可能想记住之前的排名,然后添加一个新的排名列。

我想尝试机械化从站点获取原始数据,然后将数据解析为行和列,应用新计数,然后重新制作列表。

http://www.london2012.com/medals/medal-count/来源,每个国家/地区都有一个像这样的奖牌:

<span class="countryName">Canada</span></a></div></div></td><td class="gold c">0</td><td class="silver c">2</td><td class="bronze c">5</td>

如果我使用agent.get('http://www.london2012.com/medals/medal-count')它会显示整个列表。如何解析特定的跨度和表数据?

我还需要记住排名,然后当我创建新页面时,将新排名放在旁边。

任何有关机械化解析和记忆数据的提示都会非常有用。更重要的是你做这样的事情的思考过程,我很感激帮助我开始。这不一定是代码答案

由于

2 个答案:

答案 0 :(得分:2)

首先确定表格。在Chrome中加载页面并右键单击表格上的任何位置。去检查元素。沿着层面走,直到你在桌子上。现在选择它,你会看到它看起来像这样:

<table class="or-tbl overall_medals sortable" summary="Schedule">

overall_medals类看起来很独特,所以使用起来很好。现在启动irb并执行:

require 'mechanize'
agent = Mechanize.new
page = agent.get 'http://www.london2012.com/medals/medal-count/'

仔细检查表格是否唯一:

page.search('table.overall_medals').size 
#=> 1 (good, it is)

您可以将表中的所有数据都包含在一个数组中:

page.search('table.overall_medals tr').map{|tr| tr.search('td').map(&:text)}

请注意前两行是空的,让我们通过使用范围来消除它们:

data = page.search('table.overall_medals tr')[2..-1].map{|tr| tr.search('td').map(&:text)}

第二行不是真的空,它有列名(在th而不是td中)。你可以得到:

columns = page.search('table.overall_medals tr[2] th').map{|th| th.text.strip}

你可以用以下内容将它们变成哈希:

rows = data.map{|row| Hash[columns.zip row]}

现在你可以做到

rows[0]['Country']
#=> "United States of America"

甚至一个大哈希:

countries = rows.map{|row| {row['Country'] => row}}.reduce &:merge

现在:

countries['France']['Gold']
#=> "8"

答案 1 :(得分:1)

您可能会发现此Medals API很有用(假设您的问题并非专门针对Mechanize)

http://apify.heroku.com/resources/5014626da8cdbb0002000006

它使用Nokogiri来解析网站,输出可用作JSON:

http://apify.heroku.com/api/olympics2012_medals.json