使用 Ruby 抓取并存储在哈希中



我写了Ruby scraper,从加州参议院获取竞选财务数据,然后将每个人保存为哈希。这是到目前为止的代码:

这是主要网站: http://cal-access.sos.ca.gov/Campaign/Candidates/

以下是候选页面的示例: http://cal-access.sos.ca.gov/Campaign/Committees/Detail.aspx?id=1342974&session=2011&view=received

这是 github 存储库,以防您想在代码中看到我的评论:https://github.com/aboutaaron/Baugh-For-Senate-2012/blob/master/final-exam.rb

关于代码...

require 'nokogiri'
require 'open-uri'
campaign_data =  Nokogiri::HTML(open('http://cal-access.sos.ca.gov/Campaign/Candidates/'))
class Candidate
def initialize(url)
    @url = url
    @cal_access_url = "http://cal-access.sos.ca.gov"
    @nodes =  Nokogiri::HTML(open(@cal_access_url + @url))
end
def get_summary
    candidate_page = @nodes
    {
        :political_party => candidate_page.css('span.hdr15').text,
        :current_status => candidate_page.css('td tr:nth-child(2) td:nth-child(2) .txt7')[0].text,
        :last_report_date => candidate_page.css('td tr:nth-child(3) td:nth-child(2) .txt7')[0].text,
        :reporting_period => candidate_page.css('td tr:nth-child(4) td:nth-child(2) .txt7')[0].text,
        :contributions_this_period => candidate_page.css('td tr:nth-child(5) td:nth-child(2) .txt7')[0].text.gsub(/[$,](?=d)/, ''),
        :total_contributions_this_period => candidate_page.css('td tr:nth-child(6) td:nth-child(2) .txt7')[0].text.gsub(/[$,](?=d)/, ''),
        :expenditures_this_period => candidate_page.css('td tr:nth-child(7) td:nth-child(2) .txt7')[0].text.gsub(/[$,](?=d)/, ''),
        :total_expenditures_this_period => candidate_page.css('td tr:nth-child(8) td:nth-child(2) .txt7')[0].text.gsub(/[$,](?=d)/, ''),
        :ending_cash => candidate_page.css('td tr:nth-child(9) td:nth-child(2) .txt7')[0].text.gsub(/[$,](?=d)/, '')
    }
end
def get_contributors
    contributions_received = @nodes
    grab_contributor_page = @nodes.css("a.sublink6")[0]['href']
    contributor_page = Nokogiri::HTML(open(@cal_access_url + grab_contributor_page))
    grab_contributions_page = contributor_page.css("a")[25]["href"]
    contributions_received = Nokogiri::HTML(open(@cal_access_url + grab_contributions_page))
    puts
    puts "#{@cal_access_url}" + "#{grab_contributions_page}"
    puts
    contributions_received.css("table").reduce([]) do |memo, contributors|
        begin
            memo << {
                :name_of_contributor => contributions_received.css("table:nth-child(57) tr:nth-child(2) td:nth-child(1) .txt7").text
            }
        rescue NoMethodError => e
            puts e.message
            puts "Error on #{contributors}"
        end
        memo
    end
end
end
campaign_data.css('a.sublink2').each do |candidates|
puts "Just grabbed the page for " + candidates.text
candidate = Candidate.new(candidates["href"])
p candidate.get_summary
end

get_summary按计划工作。 get_contributors按计划存储第一个贡献者<td>,但会存储 20 多次。我只是选择暂时抓住这个名字,直到我弄清楚多重打印问题。

最终目标是拥有贡献者的所有必需信息的哈希值,并可能将它们移动到SQL数据库/Rails应用程序中。但是,以前,我只想要一个可以工作的刮刀。

有什么建议或指导吗?对不起,如果代码不是超级的。编程的超级新手。

你做得很好。 在提供独立示例方面做得很好。 你会惊讶于有多少人不这样做。

我看到两个问题。

首先,并非所有页面都有您要查找的统计信息。 这会导致您的解析例程有点不高兴。 为了防止这种情况,您可以将其放在get_summary

return nil if candidate_page.text =~ /has not electronically filed/i

然后,调用方在看到 nil 时应该执行一些智能操作。

另一个问题是服务器有时无法及时响应,因此脚本超时。如果您认为服务器对脚本发出请求的速度感到不安,您可以尝试添加一些睡眠来减慢它的速度。 或者,您可以添加重试循环。 或者,您可以增加脚本超时所需的时间。

get_summary中也有一些逻辑重复。 此函数可能受益于策略与逻辑的分离。 策略是要从页面检索哪些数据以及如何设置其格式:

FORMAT_MONEY = proc do |s|
  s.gsub(/[$,](?=d)/, '')
end
FIELDS = [
  [:political_party, 'span.hdr15'],
  [:current_status, 'td tr:nth-child(2) td:nth-child(2) .txt7'],
  [:last_report_date, 'td tr:nth-child(3) td:nth-child(2) .txt7'],
  [:reporting_period, 'td tr:nth-child(4) td:nth-child(2) .txt7'],
  [:contributions_this_period, 'td tr:nth-child(5) td:nth-child(2) .txt7', FORMAT_MONEY],
  [:total_contributions_this_period, 'td tr:nth-child(6) td:nth-child(2) .txt7', FORMAT_MONEY],
  [:expenditures_this_period, 'td tr:nth-child(7) td:nth-child(2) .txt7', FORMAT_MONEY],
  [:total_expenditures_this_period, 'td tr:nth-child(8) td:nth-child(2) .txt7', FORMAT_MONEY],
  [:ending_cash, 'td tr:nth-child(9) td:nth-child(2) .txt7', FORMAT_MONEY],
]

实现是如何将该策略应用于 HTML 页面:

def get_summary
  candidate_page = @nodes
  return nil if candidate_page.text =~ /has not electronically filed/i
  keys_and_values = FIELDS.map do |key, css_selector, format|
    value = candidate_page.css(css_selector)[0].text
    value = format[value] if format
    [key, value]
  end
  Hash[keys_and_values]
end

相关内容

  • 没有找到相关文章

最新更新