Pixivのタイトル、タグ検索から一定数以上のブックマークがある画像だけを保存するスクリプト

これは何?

  1. スクリプトがある場所に検索ワード名のディレクトリを作成します
  2. 最後のページまで保存対象となる画像(一定ブックマーク数以上)を保存し続けます
  • 構成物
    • pixiv.rb
    • config.yaml

pixiv.rb

#! ruby -Ku
require 'net/http'
require 'uri'
require 'yaml'
require 'kconv'

class AccessPixiv
  #InitializeでCookieを取得しHeaderも構築する
  #成功:Trueを返す
  #失敗:Falseを返す
  def initialize(pixiv_id, pixiv_pass, user_agent, referer)
    get_cookie(pixiv_id, pixiv_pass, user_agent, referer)
  end

  #uriで指定されたページ内容を取得する
  #成功:対象URIの内容を返す
  #失敗:Falseを返す
  def get_file(uri)
    sleep 3 * (rand(5) + 1)
    puts "get #{uri}"
    site = URI.parse(uri)
    begin
      Net::HTTP.start(site.host, 80) do |http|
        response = http.get(site.request_uri, @header)
        if disp_error(response) == true
          return response.body
        else
          return false
        end
      end
    rescue Errno::ETIMEDOUT, TimeoutError
      puts 'Timeout Error. Retry.'
      retry
    end
  end

  #word  : 検索語
  #s_mode: 検索モード
  #users : ユーザ数閾値
  def search(word, s_mode, users)
    save_dir = make_dir(word)

    /検索結果:(\d+)/ =~ get_file("http://www.pixiv.net/search.php?word=#{URI.encode(word)}&s_mode=#{s_mode}")
    start_p = 1
    goal_p = $1.to_i / 20 + 1
    puts "Total Images: #{$1}"
    puts "Total Pages : #{goal_p}"

    for p in start_p..goal_p
      page = get_file("http://www.pixiv.net/search.php?word=#{URI.encode(word)}&s_mode=#{s_mode}&p=#{p}")
      page.scan(/"(http:\/\/.+\.pixiv\.net\/img\/.+\/(\d+_s\..{3}))".+?\s.+?\s.+?(\d+) users/) do |uri, id, user|
        if user.to_i >= users
          uri.sub!(/_s/, ''); id.sub!(/_s/, '')
          if data = get_file(uri)
            save_file(data, "#{save_dir}/#{user}_#{id}")
          end
        end
      end
    end
  end

  #タグ検索
  def search_tag(word, users)
    search(word, 's_tag', users)
  end

  #タイトル・キャプション検索
  def search_title(word, users)
    search(word, 's_tc', users)
  end

  #ファイル保存
  def save_file(data, filename)
    puts "save #{filename}"
    open(filename, 'wb') do |f|
      f.puts data
    end
  end

  #ディレクトリ作成
  def make_dir(name)
    if /mswin(?!ce)|mingw|cygwin|bccwin/ =~ RUBY_PLATFORM.downcase
      save_dir = "./#{name.tosjis}"
    else
      save_dir = "./#{name}"
    end
    if File.exist?(save_dir)
      puts "Directory exist"
    else
      Dir.mkdir(save_dir)
    end
    return save_dir
  end


  private
  #Cookie取得
  def get_cookie(pixiv_id, pixiv_pass, user_agent, referer)
    begin
      Net::HTTP.start('www.pixiv.net', 80) do |http|
        response = http.post('/index.php',
                             "mode=login&pixiv_id=#{pixiv_id}&pass=#{pixiv_pass}",
                             'User-Agent' => user_agent
                            )
        if disp_error(response) == true
          cookie = response['Set-Cookie'].split(',')
          @header = {
            'User-Agent' => user_agent,
            'Referer'    => referer,
            'Cookie'     => cookie[1]
          }
          return true
        else
          return false
        end
      end
    rescue Errno::ETIMEDOUT, TimeoutError
      puts 'Timeout Error. Retry.'
      retry
    end
  end

  #Error表示
  def disp_error(response)
    case response
    when Net::HTTPBadRequest
      puts 'Error 400'
    when Net::HTTPUnauthorized
      puts 'Error 401'
    when Net::HTTPForbidden
      puts 'Error 403'
    when Net::HTTPNotFound
      puts 'Error 404'
    when Net::HTTPInternalServerError
      puts 'Error 500'
    when Net::HTTPServiceUnavailable
      puts 'Error 503'
    else
      return true
    end
    return false
  end
end

def example
  config = YAML::load_file(ARGV[0])
  pixiv = AccessPixiv.new(config['pixiv']['id'], config['pixiv']['pass'],
                          config['pixiv']['user_agent'], config['pixiv']['referer'])
  pixiv.search_tag(ARGV[1].toutf8, ARGV[2].to_i)
end
example()

config.yaml

pixiv:
  id  : 'UserID'
  pass: 'PassWord'
  user_agent: 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)'
  referer: 'http://www.pixiv.net/mypage.php'

How to use

C:\pixiv>pixiv.rb config.yaml test 50
第1引数: 設定ファイル
第2引数: 検索ワード
第3引数: 保存対象とする画像のブックマークユーザ数(この例の場合、"users 50"以上の画像が対象となる)

Other

負荷対策としてSleepを長く入れてあります。
自分用に作ったものなので、使っていて気になった部分は直していきます。

Thanks

Search部分の着想は下記記事から得ました。
pixivのデータを拾ってくるRubyのコードを書きました - 下林明正の日記