ちょっとスクレイピングの練習と,narou.rb

ちょっと最近Kindle PaperWhiteを書い直しまして,それと
小説家になろうをちらちらと読むようになった.
私はもともとしたらば掲示板にあるやる夫スレなどを読んでおり,それからすると小説家になろうの小説もまあまあ馴染みやすかったのでつい読んでしまう.

そこで,Kindleで素敵な組版で読めるといいなとおもったところ,
narou.rbの存在を知った.

しかしながら,(当然だが)既に商業化などに付き削除されてしまったものはnarou.rbじゃダウンロードも電子書籍化も不可能である.
だが,Web Archiveに生きている事は多々あり,これをEPUB3にして手元に保持しておきたいなあとか考え,次のスクリプトでnarou.rbで管理できる形に目次と小説本文をyaml形式で保存するスクレイピングスクリプトをつくった.

ぶっちゃけていうとこの素晴らしい世界に祝福を!のWeb版のEPUBをコレクションしておきたかったというわけです.

以下,成果.
#!/usr/bin/env ruby
# encoding: utf-8
#
# Web Archiveからスクレイピングして小説家になろうのテキストダウンロードと同じ形式でテキストパクってくるヤツ
#
require 'nokogiri'
require 'open-uri'
for i in 1..124 do
ans = []
title = nil
begin
if 10 <= i and i <= 12 then
url = "http://web.archive.org/web/20130708184241/http://ncode.syosetu.com/n7145bl/#{i}"
else
url = "http://web.archive.org/web/20131127132412/http://ncode.syosetu.com/n7145bl/#{i}"
end
x = ""
open(url).each{ |d|
x += d.clone
}
doc = Nokogiri.HTML(x)
rescue
doc = Nokogiri.HTML("<html><body><p>abort</p></body></html>")
ans[ans.length] = "Nokogiri aborted"
end
begin
title_element = doc.xpath("//title").inner_text
title = title_element.sub(/^.* - /,"")
rescue
title = "Unknown"
end
begin
ans.push("#{title}\n\n")
doc.xpath("//div[@class='novel_view']").each do |node|
next if node.children.inner_text == nil
node.search('rb').each do |rb| rb.replace('|' + rb.inner_text) end
node.search('rt').each do |rt| rt.replace(rt.inner_text) end
node.search('rp').each do |rp|
rp.replace("《") if rp.inner_text == "("
rp.replace("》") if rp.inner_text == ")"
end
node.search('ruby').each do |ruby| ruby.replace(ruby.inner_text) end
aa = node.inner_text.clone
ans.push(aa.clone)
end
File.open("#{i} #{title}.txt", 'w') { |file|
file.write ans.join("")
}
rescue
p "something wrong"
end
end
view raw get.rb hosted with ❤ by GitHub
#!/usr/bin/env ruby
# encoding: utf-8
#
# Web Archiveからスクレイピングして小説家になろうの目次ページをnarou.rbのtoc.yamlと同じ形式で出力するやつ
#
require 'yaml'
require 'nokogiri'
require 'open-uri'
begin
url = "http://web.archive.org/web/20131127132412/http://ncode.syosetu.com/n7145bl/"
x = ""
open(url).each{ |d|
x += d.clone
}
doc = Nokogiri.HTML(x)
rescue
doc = Nokogiri.HTML("<html><body><p>abort</p></body></html>")
ans[ans.length] = "Nokogiri aborted"
end
begin
title = doc.xpath("//div[@class='novel_title']/div/a").inner_text
author = doc.xpath("//div[@class='novel_writername']/a[@href]").inner_text
toc_url = "http://ncode.syosetu.com/n7145bl/"
story = doc.xpath("//div[@class='novel_ex']").inner_text
ans = []
idx = 1
chapter = ''
subchapter = ''
change_chapter = false
# change_subchapter = false
doc.xpath("//div[@class='novel_sublist']/table/tr").each do |node|
if node.at(".//td[@class='chapter']") then
chapter = node.xpath(".//td[@class='chapter']").inner_text
change_chapter = true
else
nsa = node.xpath(".//td[@class='period_subtitle']/a[@href]")[0]
href = nsa.get_attribute("href").sub(/\/web\/20131127132412\/http:\/\/ncode.syosetu.com(.*$)/, '\1')
subtitle = nsa.inner_text
file_subtitle = subtitle
long_update = node.xpath(".//td[@class='long_update']")[0]
if long_update.at(".//span") then
span = long_update.xpath(".//span[@title]")[0]
subupdate = span.get_attribute("title").sub(/(.*) 改稿/, '\1')
subdate = long_update.inner_text.sub(/^\r\n(.*)\r\n\r\n(改)\r\n/, '\1')
else
subdate = long_update.inner_text.sub(/\r\n(.*)\r\n/, '\1')
subupdate = subdate
end
if change_chapter then
ans.push({"index"=>idx, "href"=>href, "chapter"=>chapter, "subchapter"=>"", "subtitle"=>subtitle, "file_subtitle"=>file_subtitle, "subdate"=>subdate, "subupdate"=>subupdate, "download_time"=>Time.now})
change_chapter = false
else
ans.push({"index"=>idx, "href"=>href, "chapter"=>"", "subchapter"=>"", "subtitle"=>subtitle, "file_subtitle"=>file_subtitle, "subdate"=>subdate, "subupdate"=>subupdate, "download_time"=>Time.now})
end
idx += 1
end
File.open("toc.yaml", 'w') { |file|
YAML.dump({"title"=>title,"author"=>author,"toc_url"=>toc_url,"story"=>story,"subtitles"=>ans},file)
}
end
rescue
p "something wrong"
end
view raw get_toc.rb hosted with ❤ by GitHub
#!/usr/bin/env ruby
# encoding: utf-8
#
# Web Archiveからスクレイピングして小説家になろうのテキストダウンロードと同じ形式でテキストパクって,
# 更にそれをnarou.rbの本文のyaml形式で出力するやつ(実行場所の一階層上のディレクトリにtoc.yamlという目次があるものとする)
#
require 'yaml'
require 'nokogiri'
require 'open-uri'
toc = YAML.load_file('../toc.yaml')["subtitles"]
for i in 1..124 do
ans = []
title = nil
begin
if 10 <= i and i <= 12 then
url = "http://web.archive.org/web/20130708184241/http://ncode.syosetu.com/n7145bl/#{i}"
else
url = "http://web.archive.org/web/20131127132412/http://ncode.syosetu.com/n7145bl/#{i}"
end
x = ""
open(url).each{ |d|
x += d.clone
}
doc = Nokogiri.HTML(x)
rescue
doc = Nokogiri.HTML("<html><body><p>abort</p></body></html>")
ans[ans.length] = "Nokogiri aborted"
end
begin
title_element = doc.xpath("//title").inner_text
title = title_element.sub(/^.* - /,"")
rescue
title = "Unknown"
end
begin
doc.xpath("//div[@class='novel_view']").each do |node|
next if node.children.inner_text == nil
node.search('rb').each do |rb| rb.replace('|' + rb.inner_text) end
node.search('rt').each do |rt| rt.replace(rt.inner_text) end
node.search('rp').each do |rp|
rp.replace("《") if rp.inner_text == "("
rp.replace("》") if rp.inner_text == ")"
end
node.search('ruby').each do |ruby| ruby.replace(ruby.inner_text) end
aa = node.inner_text.clone
ans.push(aa.clone)
end
hash = toc[i-1]
File.open("#{i} #{title}.yaml", 'w') { |file|
hash.store("element", {"introduction"=>'',"body"=>ans.join(""),"postscript"=>'',"data_type"=>"text"})
YAML.dump(hash,file)
}
rescue
p "something wrong"
end
end
view raw get_yaml.rb hosted with ❤ by GitHub
RubyもNokogiriもあまりよくわかってないのでイテレーションが非効率な気がするが,まあそんなに問題ないとおもう.