2ã¡ããããBOTã®ä½ãæ¹ å®è£ ç·¨1
2ちゃんねるBOTの作り方 準備編 - GIOの日記
2ちゃんねるBOTの作り方 設計編 - GIOの日記
å¿ è¦ãªæ©è½ãæãã ãã
1.æ²ç¤ºæ¿ä¸è¦§ãããã¥ã¼éVIPã®URLãåå¾
2.ãã¥ã¼éVIPã®å
¨ã¦ã®ã¹ã¬ããæ
å ±ãåå¾
3.å
¨ã¦ã®ã¹ã¬ããããå
¨ã¦ã®ç»åURLãåå¾
4.å
¨ã¦ã®ç»åããã¦ã³ãã¼ã
5.åãç»åããã¦ã³ãã¼ãããªãããã«ã¹ã¬ããæ
å ±ãä¿å
æåã«APIã決ããã
æåã«APIã決ããã®ã¯ãã¹ãé§åéçºãé²ããããç¾ããã³ã¼ããæ¸ãä¸ã§æå©ã§ããã¾ãã¯ã¹ã±ã«ãã³ã³ã¼ãã£ã½ãå®è£
module Bot2ch class Menu def get_board(subdir) end end class Board def get_threads end end class Thread def get_images end end class NormalImageDownloader def download end end class App def execute(subdir) menu = Menu.new board = menu.get_board(subdir) threads = board.get_threads threads.each do |thread| images = thread.get_images images.each do |image| image.download end end end end end Bot2ch::App.new.execute('news4vip')
ããã§ã¯æ©è½ãã¹ã±ã«ãã³ã³ã¼ãã«èä»ããã¦ããã¾ãããã
1.æ²ç¤ºæ¿ä¸è¦§ãããã¥ã¼éVIPã®URLãåå¾
æ²ç¤ºæ¿ã®ãã¹ãã¯é »ç¹ã«å¤æ´ãããã®ã§ãæãå¤æ´ãå°ãªãã§ããããµããã£ã¬ã¯ããªããURLãåå¾ãããããã¥ã¼éVIPã®ãµããã£ã¬ã¯ããªã¯news4vipã§ãã
require 'open-uri' class Menu def initialize @bbsmenu = 'http://menu.2ch.net/bbsmenu.html' end def get_board(subdir) reg = Regexp.new("href=(.+#{subdir})", Regexp::IGNORECASE) open(@bbsmenu) do |f| f.each do |line| return Board.new($1) if line =~ reg end end end end
2.ãã¥ã¼éVIPã®å ¨ã¦ã®ã¹ã¬ããæ å ±ãåå¾
æ²ç¤ºæ¿URL/subject.txtããã¹ã¬ããæ
å ±ãåå¾ãããããDATãã¡ã¤ã«å<>ã¿ã¤ãã«ãã¨ãªã£ã¦ã¾ãã
â»2chã®ãã¼ã¿ã¯å
¨ã¦SJISãªã®ã§ç°å¢ã«åããã¦å¤æãã¾ãããã
class Board def initialize(url) @url = url @subject = "#{url}/subject.txt" end def get_threads threads = [] open(@subject) do |f| lines = f.read.toutf8 lines.each do |line| dat, title = line.split('<>') threads << Thread.new("#{@url}/dat/#{dat}", title) end end threads end end
3.å ¨ã¦ã®ã¹ã¬ããããå ¨ã¦ã®ç»åURLãåå¾
次ã«DATããç»åã®URLãåå¾ãã¾ããDATã¯<>ã§è¦ç´ ãåºåããã¦ããã
4ã¤ãã®å
容ãå®éã®æ¸ãè¾¼ã¿å
容ã«ãªã£ã¦ããã®ã§ãããããç»åURLãæ¢ãã°è¯ãã®ã§ããã¾ãã
ã¾ããè²ã
ãªã¢ãããã¼ãã¼ã«å¯¾å¿ã§ãããããªä»çµã¿ã«ãã¾ãããã
URLããããã®å
¨ã¦ã«å¯¾ãã¦ã対å¿ãããã¦ã³ãã¼ãã¼ã¯ã©ã¹ã§ãã¦ã³ãã¼ãããæãã§ãã
class Thread attr_accessor :title def initialize(url, title) @dat = url @title = title.strip end def get_images images = [] downloaders = [NormalImageDownloader] open(@dat) do |f| lines = f.read.toutf8 lines.each do |line| contents = line.split('<>')[3] while contents =~ /\/\/[-_.!~*\'()a-zA-Z0-9;\/?:\@&=+\$,%#]+/i url = "http:#{$&}" contents = $' image_downloader = downloaders.find { |d| d.match(url) } next unless image_downloader images << image_downloader.new(url) end end end images end def dat_no File.basename(@dat, '.dat') end end
4.å ¨ã¦ã®ç»åããã¦ã³ãã¼ã
ã¨ããããé常ç»åã®ãã¦ã³ãã¼ãã¼ãå®è£ ãã¾ããããURLã®æ¡å¼µåãjpgãªãã°ãã¦ã³ãã¼ãã§ããã¯ã©ã¹ã§ãã
class NormalImageDownloader def initialize(url) @url = url end def download(saveTo) puts "download: #{@url}" open(saveTo, 'wb') do |f| open(@url) do |img| f.write img.read end end end def self.match(url) url =~ /.jpg$/i end end
ã¤ãã¤ã¾ããã
ä¸éãå®è£ ã§ããã®ã§APPã¯ã©ã¹ã®è¾»è¤åããããã¾ãã
class App def execute(board) image_root_dir = File.dirname(__FILE__) + '/images' menu = Menu.new board = menu.get_board(board) threads = board.get_threads puts "total: #{threads.length} threads" threads.each do |thread| images = thread.get_images next if images.empty? parent_dir = "#{image_root_dir}/#{thread.dat_no}" Dir.mkdir(parent_dir) unless File.exists?(parent_dir) puts "#{thread.title}: #{images.length} pics" images.each_with_index do |image, index| image.download("#{parent_dir}/#{index}.jpg") rescue next sleep(0.2) end end end end
以ä¸ã®ããã«ãåå決ãããã£ã¬ã¯ããªæ§æã«æ²¿ã£ã¦ã¹ã¬ããæ¯é£çªã§ç»åãä¿åããããã«å¤æ´ãã¾ããã
ここまでのコードはコチラ
å®è¡
ruby bot2ch.rb
ããã¾ã§æ¸ãã¦æ°ã¥ããã®ã§ããã5.ã®å®è£
ãå¿ãã¦ãã
èµ·åæ¯ã«åãç»åããã¦ã³ãã¼ãããã¦ãã¾ãã®ã§å¯¾çããªããã°ããã¾ããã
ç²ããã®ã§ãææ¥ã«ã§ãã
ã¡ãªã¿ã«å®èµ°ããã¦ã¾ãããå®è¡ããã¨é¬¼ã®ããã«ãã¦ã³ãã¼ããã¦ããã¯ãã§ãã
å®è£ ç·¨1ããã¾ãï¼