青空文庫の閲覧数ランキングを集計してみた
RubyのWebスクレイピングライブラリNokogiriを使って、
青空文庫が月ごとに発表している閲覧数ランキングを集計してみました。
ランキングページには、
2009年1月〜現在まで、各月閲覧ファイル種別(XHTML版,TEXT版)に2つずつリンクが並んでいるので、
そのページを元に各ランキングをCSVにして、集計という手順で処理しました。
上位10作品はこんな感じでした。漱石多いなあ。
"1","こころ","夏目 漱石","473813"
"2","銀河鉄道の夜","宮沢 賢治","440443"
"3","人間失格","太宰 治","384592"
"4","吾輩は猫である","夏目 漱石","362631"
"5","坊っちゃん","夏目 漱石","348445"
"6","ドグラ・マグラ","夢野 久作","303008"
"7","羅生門","芥川 竜之介","280554"
"8","蟹工船","小林 多喜二","239553"
"9","注文の多い料理店","宮沢 賢治","217020"
"10","学問のすすめ","福沢 諭吉","209673"
ソースはこちら。
年月指定やファイル種別指定できるようにした方がよかったな。
require 'nokogiri' require 'kconv' require 'open-uri' class Aozora def csv_nizer(item="", isEOL=false, brachets='"', separater=',' ) brachets + item + brachets + (isEOL ? "\n" : separater ) end def parseHtmlFileAndEncodeUtf8(url) Nokogiri::HTML.parse((open(url, "r:binary").read.toutf8.encode("UTF-8"))) end RankingListURL="http://www.aozora.gr.jp/access_ranking/" CSV = ".csv" def getRankingAsCsv(url, outputPath, filename:"out.csv") begin path = File.directory?(outputPath) ? File.expand_path(outputPath) : Dir.pwd doc = parseHtmlFileAndEncodeUtf8(url) results= "" ; i=1 doc.xpath("//td").each do |item| results += item.content.to_s.delete("\n ").strip + (i%4!=0 ? "," : "\n") #class属性等無かったので項目数で改行箇所を判断 i+=1 end File.open("#{path}/#{filename}", "w:utf-8") { |f| f.write(results) } rescue OpenURI::HTTPError => e puts "#{e.to_s}(#{url})" end return nil end def getRankingLinkList(url) doc = parseHtmlFileAndEncodeUtf8(url) results = [] doc.xpath("//td/a").each do |item| results << item["href"] end return results end def getWholeRanking(outputPath) getRankingLinkList(RankingListURL).each do |link| if link.count("0-9")>=5 then #年別の集計ランキングを除外 getRankingAsCsv(RankingListURL + link, outputPath, filename:link.delete("^0-9")+CSV) end end end def totalRankingCsv(csvPath, outputPath:Dir.pwd, filename:"total.csv") ranking = {} Dir.glob("#{csvPath}/*").each { |file| File.open(file, "r:utf-8") { |f| f.each { |line| array = line.split(",") key = array[1]+"_ "+array[2] #作品名_作家名 value = array[3].to_i if ranking.has_key?(key) then ranking[key] = ranking[key].to_i + value else ranking[key] = value end } } } results=""; i=1 begin ranking.sort {|a,b| b[1]<=>a[1]}.each do |e| results += csv_nizer(i.to_s) + csv_nizer(e[0].split("_")[0]) + csv_nizer(e[0].split("_")[1].strip) + csv_nizer(e[1].to_s, true) i+=1 end rescue TypeError =>e p "#{e.to_s}(#{i})" p e.messsage end File.open("#{outputPath}/#{filename}", "w:utf-8") { |f| f.write(results) } return nil end end