コンテンツへスキップ

いかにしておっぱい画像をダウンロードするかをRubyで試してみた2013

OverView

  1. 元ネタ:いかにしておっぱい画像をダウンロードするか〜2012 をRubyで書いた
  2. crawlerを作ってみたい
  3. Rubyなら手軽にできるかもしれない
  4. 元ネタサイトの作成時と2013/7現在のBingサービスが変わっており
    元ネタそのままでは動かないっぽい
  5. おっぱい

環境

Rubyが動作する環境であること。

環境構築手順は後日まとめる(つもり)

準備

gemインストール

JSON/SSL/paralelあたりを使うのでgem installしておく。

gem install json
gem install ssl
gem install parallel

bing search APIのサインアップ

ここにアクセスしてbing search APIを利用できるようにする。

この記事を書いている時のサービスだとサインアップすると5000リクエスト/月が無料で使えた。

うまく登録できると以下の画面で「プライマリアカウントキー」が取得できるのでメモしておく

無題

ソースコード

元ネタから方針を継承して解説しすぎるよりもコードを見てもらう方式で。

ずいぶんと適当なソースになってしまったが、ご愛嬌。

bingがSSLになったことへの対応や、コマンド引数で検索ワードを受けるなど

ちょっとアレンジしてます。

ソース上のAPP_IDに上述のプライマリアカウントキーを。

# coding:UTF-8
require 'rubygems'
require 'open-uri'
require 'json'
require 'digest/md5'
require 'uri'
require 'kconv'
require 'openssl'
require 'parallel'

#--------------------------------------
#  define
#--------------------------------------
## SSL check off
module OpenSSL
  module SSL
    remove_const :VERIFY_PEER
  end
end
OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE

#--------------------------------------
#  define
#--------------------------------------
$loop_count = 0
$dl_count = 0
$params = {}
$subParams = {}

#--------------------------------------
#  define
#--------------------------------------
APP_ID = '*******************************' ## https://ssl.bing.com/webmaster/developers/appids.aspx
API_URI = 'https://api.datamarket.azure.com/Bing/Search/Image' ## Web/Image/Video/Newsがある
OUT_DIR = './data'

#--------------------------------------
#  init
#--------------------------------------
def init

  ## making save directory
  Dir.mkdir OUT_DIR unless File.exists? OUT_DIR
  puts "save to ==>#{File.expand_path(OUT_DIR)}"

  $subParams = {
    :Adult => '%27off%27',
    :Query => '%27' + URI.encode(ARGV[0].toutf8) + '%27'
  }

end

#--------------------------------------
#  main
#--------------------------------------
def main
  loop do
    if $dl_count >= 1000 or $loop_count >= 100 then
      puts "DownLoad End---------"
      finish
    end

    $params = {
      :format => 'json',
      :top => 50, # max count per request(max 50)
      :skip => $loop_count * 50 # cursor
    }

    url = API_URI + '?' + $params.map{|k,v| "$#{k.to_s}=#{v.to_s}"}.join('&')+ '&' + $subParams.map{|k,v| "#{k.to_s}=#{v.to_s}"}.join('&')
    puts "==>Request URL is #{url}"

    certs =  [APP_ID, APP_ID]
    data = JSON.parse open(url, {:http_basic_authentication => certs}).read.toutf8

    if data['d']['results'].size == 0 then
      puts "DownLoad End(Find No More Data)---------"
      finish
    end

    ## Windows not support parallel
    if RUBY_PLATFORM.downcase =~ /mswin(?!ce)|mingw|cygwin|bccwin/
      downloadTarget(data)
    else
      downloadTargetParallel(data)
    end

    $loop_count += 1
  end
end

#--------------------------------------
#  finish
#--------------------------------------
def finish
  exit
end

#--------------------------------------
#  downloadTarget
#--------------------------------------
def downloadTarget(data)

  ## pop from ResponseData
  data['d']['results'].each do |entry|

    next unless entry['MediaUrl'] =~ /\.jpe?g$/i

    ## entry['Width']とかentry['Height'] entry['FileSize'] なんかも使えそう

    ## when same file exists skip
    fname = Digest::MD5.hexdigest(entry['MediaUrl'])+'.jpg'
    fpath = "#{OUT_DIR}/#{fname}"
    if File.exists? fpath then
      puts "---already downloaded #{entry['MediaUrl']}"
      next
    end

    ## Image Download
    $dl_count += 1
    puts "#{$dl_count} : Download... #{entry['MediaUrl']}"
    img = open(URI.encode entry['MediaUrl']) rescue next
    img.close
    next unless img.content_type =~ /^image\/.+/i
    img.path rescue next
    next if img.path.to_s.size < 1
    File.rename(img.path, fpath)
  end
end

#--------------------------------------
#  downloadTargetParallel
#--------------------------------------
def downloadTargetParallel(data)

  ## pop from ResponseData
   Parallel.each(data['d']['results'], :in_thread => 10) do |entry|

    next unless entry['MediaUrl'] =~ /\.jpe?g$/i

    ## entry['Width']とかentry['Height'] entry['FileSize'] なんかも使えそう

    ## when same file exists skip
    fname = Digest::MD5.hexdigest(entry['MediaUrl'])+'.jpg'
    fpath = "#{OUT_DIR}/#{fname}"
    if File.exists? fpath then
      puts "---already downloaded #{entry['MediaUrl']}"
      next
    end

    ## Image Download
    $dl_count += 1
    puts "#{$dl_count} : Download... #{entry['MediaUrl']}"
    img = open(URI.encode entry['MediaUrl']) rescue next
    img.close
    next unless img.content_type =~ /^image\/.+/i
    img.path rescue next
    next if img.path.to_s.size < 1
    File.rename(img.path, fpath)
  end
end

#--------------------------------------
#  handler
#--------------------------------------
init

main

finish

 

いくつかのキーワードで実行したところ、あっちゅーまに5000ファイルくらいダウンロードしてました。

おためしあれ。

 

 

 

 

コメントを残す

メールアドレスが公開されることはありません。