ブログ記事を収集する必要が生じてクローラ書いた.
最初は
wget -a ./wget.log -w 30 -r -np -m -k -erobots=off -np blog_url
とかやってたけど月別一覧やカテゴリ一覧,モバイル版URLを開こうとしてかなり重複してしまい一向に終わらないので,主要なブログサービスに合わせて書いた.
どこから辿るのが記事を網羅できるか考えたところ
- Livedoor: base_url/archives/year-month.html?p=pos
- 続きがあるかどうかの判定,ブログによってまちまちなのでキーワードマッチにした
- Ameblo: base_url/archive#{pos}-#{year}#{month}.html
- excite: base_url/page/#{pos}
- yaplog: base_url/#{pos}
- base_url/monthly/#{year}#{month}/ で辿る方法もあるけどブログによって記事が全表示されるものと記事タイトルだけが出るものがあったので面倒に見えた
でたどるのが一番良さそうだった.
year/monthに当たる部分は2003年から決め打ちで書いた.ここ二分探索とかして記事が書かれ始めた年月を特定するとかすればもっと賢くなると思う.
とりあえず全記事これで落ちてくるはずなのでダウンロード後に個別記事ごとに切り出すとかすればいいと思う.
# -*- coding: utf-8 -*- require 'nokogiri' require 'open-uri' WAIT_SEC = 30 UA = '' def get_ameblo(base_url, save_path) base_url.sub!(/\/$/, "") 2003.upto 2012 do |y| 1.upto 12 do |m| m = "0#{m}" if m < 10 pos = 1 loop do url = "#{base_url}/archive#{pos}-#{y}#{m}.html" sleep WAIT_SEC begin doc = Nokogiri::HTML(open(url, 'User-Agent' => UA).read) # save open("#{save_path}/archive#{pos}-#{y}#{m}.html", 'w'){|f| f.puts doc.inner_html } # 次が存在するかどうか end_flag = (doc/'a.nextPage').empty? break if end_flag rescue => e end pos += 1 end end end end def get_excite(base_url, save_path) base_url.sub!(/\/$/, "") pos = 1 loop do url = "#{base_url}/page/#{pos}" sleep WAIT_SEC begin doc = Nokogiri::HTML(open(url, 'User-Agent' => UA).read) # save open("#{save_path}/#{pos}.html", 'w'){|f| f.puts doc.inner_html } # 次があるかどうか end_flag = (doc/'a.older_page').empty? break if end_flag rescue => e end pos += 1 end end def get_livedoor(base_url, save_path) base_url.sub!(/\/$/, '') 2003.upto 2012 do |y| 1.upto 12 do |m| m = "0#{m}" if m < 10 pos = 1 loop do page_url = "#{base_url}/archives/#{y}-#{m}.html?p=#{pos}" sleep WAIT_SEC begin doc = Nokogiri::HTML(open(page_url, 'User-Agent' => UA).read) # 保存 open("#{save_path}/#{y}-#{m}.html_#{pos}", 'w'){|f| f.puts doc.inner_html } # テーマによって next 要素のあるなしが違うのでめんどくさいから # 次記事の URL があるかどうかのマッチで探す next_url = "#{base_url}/archives/#{y}-#{m}.html?p=#{pos + 1}\"" end_flag = !doc.inner_html.include?(next_url) break if end_flag rescue => e end pos += 1 end end end end def get_yaplog(base_url, save_path) base_url.sub!(/\/$/, "") pos = 1 loop do url = "#{base_url}/#{pos}" sleep WAIT_SEC # 恐らく不完全な HTML が返ってくることがあり, # そのために Nokogiri での parse が失敗する # なので, open(url).read の中身をそのまま見る begin doc = open(url, 'User-Agent' => UA).read # save open("#{save_path}/#{pos}.html", 'w'){|f| f.puts doc } # check next_link = base_url + '/' + (pos + 1).to_s + '"' end_flag = !doc.include?(next_link) break if end_flag rescue => e end pos += 1 end end