がむしゃらの画像を取りまくるRubyスクリプト
がむしゃら画像をひたすら集めまくるRubyスクリプトを書いたので、何となく公開。
使い方
- 基本的にWindows用(なのでアウトプットはSJIS)
- 適当なフォルダにスクリプトをコピーして
> ruby gamuget.rb
- つらつらとログが流れるのをボケッと眺めていると、カレントディレクト配下に板名のフォルダができて、画像がひたすら落ちてきている。
特徴
- 画像ファイルはまずheaderをゲットして、ファイルサイズが既にあるものと同じかどうかチェックする。
- 取得する板の一覧は最後の方のfor文のところで、板名を入れて指定する。
- 取得する処理は板毎のスレッドに分けているので、早い(?)
- 板一覧はカレントディレクトリ配下に、board_list.txt として作成する。
- 板一覧ファイルがないときは、トップページに板一覧を取りに行く。
- 超適当なリンク先取得処理。
=begin 画像掲示板がむしゃらから、画像を取りまくるスクリプト。 todo ・同じ名前のファイルが既にローカルにあったときに、ファイルサイズを見て既存ファイルを待避する。その際、すでに待避されているファイルと同じものが無ければ、新規に待避する。同一判定の基準は、とりあえずファイルサイズ。 一応実装しているけど、検証していないのであやしい。。 =end $KCODE = 'utf8' require 'uri' require 'net/http' require 'kconv' require 'fileutils' Net::HTTP.version_1_2 # おまじない def printsjis(str) print str.tosjis end def fetch( uri_str, limit = 10 ) # 適切な例外クラスに変えるべき raise ArgumentError, 'http redirect too deep' if limit == 0 response = Net::HTTP.get_response(URI.parse(uri_str)) case response when Net::HTTPSuccess then response when Net::HTTPRedirection then fetch(response['location'], limit - 1) else response.error! end end def normal_uri(now_uri, new_uri) if /^.+:\/\// =~ new_uri then new_uri else URI.join(now_uri, new_uri).encode end end top_url = 'http://gamushara.net/index.html' board_list_file = 'board_list.txt' # 板一覧ハッシュ { 名前(UTF-8) => URL, ... } board_list = Hash.new # 板一覧ファイルがあるときは、そこから板一覧を得る。 # たまに板一覧ファイルを削除する必要あり。 if FileTest.writable?(board_list_file) open(board_list_file) {|f| while line = f.gets parts = line.chomp!.split(/\t/) board_list[parts[0]] = parts[1] end } else # 板一覧を得る printsjis "トップページから左フレームのURLを取得中..." top_page = fetch(top_url).body left_frame_url = top_page.scan(/<FRAME SRC="([^"]*)"/)[0][0] left_frame_url = normal_uri(top_url, left_frame_url) printsjis "完了\n" printsjis "左フレームの内容を取得中..." left_page = fetch(left_frame_url).body.toutf8 #puts left_page.tosjis printsjis "完了\n" printsjis "板一覧を取得中..." left_page.scan(/<A HREF="([^>]+)"><font size=.>([^<]+)<\/font><\/A>/).each {|s| board_list[s[1]] = s[0] } printsjis "完了\n" # 板一覧を名前でソートしてファイル書き込み & 画面表示 open(board_list_file, "w") {|f| board_list.keys.sort.each{|a| f.puts a + "\t" + board_list[a.toutf8] + "\n" print a.tosjis + "\t\t=> " + board_list[a] + "\n" } } puts end # file_nameのファイルが存在していれば、ファイル名に_1とか_2とか付けて待避する。 def rename_file(file_name) file_size = FileTest.size?(file_name) return unless file_size dirname = File.dirname(file_name) extname = File.extname(file_name) basename = File.basename(file_name, extname) + '_1' i = 2 while this_file_size = FileTest.size?(dirname + "/" + basename + extname) # 自分と同じファイルサイズのファイルがいれば、既に待避済みと見なして復帰する。 return if file_size == this_file_size basename = File.basename(basename, '_' + (i - 1).to_s) + "_" + i.to_s i += 1 end FileUtils.mv(file_name, dirname + "/" + basename + extname) end def get_all_pictures(board_name, board_url) # スレ一覧 { URL, ... } thread_list = Array.new now_board = board_name printsjis "「#{now_board}」(#{board_url})の画像を全取得します。\n\n" printsjis "「#{now_board}」のスレ一覧を取得中..." main_url = board_url now_page = 1 begin printsjis now_page.to_s + "枚目..." # スレの内容をゲット main_page = fetch(main_url).body.toutf8 #puts main_page.tosjis # 次ページURLを得る next_url = main_page.scan(/<a href="([^"]*)">次→<\/a>/).flatten[0] if next_url then next_url = URI.join(main_url, next_url).to_s end # スレ一覧を得る thread_list |= main_page.scan(/<a href="(.+?)">/).flatten.grep(/^\.\/html/).map{|url| URI.join(main_url, url).to_s } main_url = next_url now_page += 1 end while next_url printsjis "完了\n" # スレッドURL一覧を表示 #p thread_list # 画像一覧 { URL, ... } picture_list = Array.new res_url_list = Array.new printsjis "スレッドから画像URL一覧を取得中..." thread_list.each{ |thread_url| begin thread_main = fetch(thread_url).body.toutf8 picture_list |= thread_main.scan(/<img src="([^"]+\.(?:jpe?g|gif))"/).flatten.reject{|item| item =~ /__s.(jpe?g|gif)/}.map{|url| URI.join(thread_url, url).to_s} res_url_list |= thread_main.scan(/<a href="([^"]+imgview\.php[^"]+)"/).flatten.map{|url| URI.join(thread_url, url).to_s} rescue printsjis "#{board_name}のスレ(#{thread_url})が読み込めません。\n" end } printsjis "完了\n" printsjis "レスから、画像URL一覧を取得中..." res_url_list.each{ |res_url| begin res_main = fetch(res_url).body.toutf8 picture_list |= res_main.scan(/<img src="([^"]+\.(?:jpe?g|gif))"/).flatten.map{|url| URI.join(res_url, url).to_s} rescue printsjis "「#{board_name}」のレス(#{res_url})が読み込めません。\n" end } printsjis "完了\n" # 画像URL一覧を表示 #p picture_list FileUtils.mkdir(now_board.tosjis) rescue "ディレクトリが既に存在します。" printsjis "画像取得を開始します。\n" picture_list.each {|picture_url| printsjis picture_url + "..." #ヘッダーを取得して、ファイルサイズを検査する。 pict_uri = URI.parse(picture_url) file_name = now_board.tosjis + "/" + File.basename(picture_url) file_size = FileTest.size?(file_name) || 0 begin Net::HTTP.start(pict_uri.host, pict_uri.port) do |http| res = http.head(pict_uri.path) if file_size == res['Content-Length'].to_i print "Already gotton!" else rename_file(file_name) if file_size != 0 res = http.get(pict_uri.path) open(file_name, "w") {|f| f.binmode f.write res.body } end end rescue ; end printsjis "done.\n" } printsjis "画像取得が完了しました。\n" end threads = Array.new for board_name in %w( ゲーム 本 美術デザイン 風景 ここどこ? 芸能 テレビ スポーツ 爆笑画像 いろいろ おっぱい おしり まんすじ 脚 パンチラ 下着 水着 コス制服ユニ 二次元 キャンギャル お姉さん SM 外国人 [特集]透け透け デスクトップ 映画 1960年代 1970年代 1980年代 1990年代 gif エロ全般 ) #for board_name in %w( gif ) t = Thread.new do get_all_pictures(board_name, board_list[board_name]) end threads.push(t) end puts "Waiting for thread." threads.each {|t| t.join} puts "done."