2

Ruby スクレイパーを作成して、カリフォルニア州上院から選挙資金データを取得し、各個人をハッシュとして保存しました。これまでのコードは次のとおりです。

メインのウェブサイトはこちら: 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 アプリに移動することです。しかし、以前は、機能するスクレーパーが欲しいだけでした。

アドバイスやガイダンスはありますか?コードが優れていない場合は申し訳ありません。プログラミング超初心者。

4

1 に答える 1

1

あなたはうまくやっています。スタンドアローンのサンプルを提供してくれました。多くの人がそうしないことに驚くでしょう。

2 つの問題があります。

1 つ目は、探している統計情報がすべてのページにあるわけではないということです。これにより、解析ルーチンが少し混乱します。それを防ぐために、これを次のように入れることができますget_summary

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

呼び出し元は、nil が表示されたときにインテリジェントな処理を行う必要があります。

もう 1 つの問題は、サーバーがタイムリーに応答しないことがあるため、スクリプトがタイムアウトになることです。スクリプトがリクエストを行う速度でサーバーが動揺していると思われる場合は、スリープを追加して速度を落とすことができます。または、再試行ループを追加することもできます。または、スクリプトがタイムアウトするまでの時間を長くすることもできます。

にはロジックの重複もあり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
于 2012-06-23T03:26:18.093 に答える