LoginSignup
11
8

More than 5 years have passed since last update.

Rubyで画像を無限収集する

Last updated at Posted at 2017-12-11

はじめに

機械学習の教師データを集めるため大量の画像が必要だったので、Rubyでプログラムをかきました。
今回はsleniumを使いました。理由は画像検索結果の新規読み込みで動的なスクロールが必要になるからです。

また、今回初めて Google画像検索よりBingの方が、精度のいい画像がでてくることに気づきまして(個人の感覚かもしれません)、Bing画像検索でレッツゴーです。

(本来ならAPIを使うべきですが、Googleは制限が多い、BingAPIは使うまでのUIが変わってて使いづらかった、という経緯により、このような対応をとりました。サーバー負荷を忘れず必ずおとなしくやりましょう。自己責任でお願いします。)

手順

1.必要なライブラリを入れる
2.画像の保存先フォルダを作成
3.コードを書く
4.Run

1.必要なライブラリを入れる

ターミナルで

brew install chromedriver

gem install open_uri_redirections

....等々(以下のrequireを参照して下さい)

2.画像の保存先フォルダを作成

プログラムコードと同じ階層に任意フォルダを作る(ここではsakuramana_imgとしました)

3.コードを書く

infinite_crawl.rb

require 'selenium-webdriver'
require 'nokogiri'
require 'open-uri'
require 'addressable/uri'
require 'kconv'
require "uri"
require 'open_uri_redirections'

#文字対応増やすためStringクラスを拡張
class String  
 def sjisable  
  str = self  
  str = str.exchange("U+301C", "U+FF5E") # wave-dash  
  str = str.exchange("U+2212", "U+FF0D") # full-width minus  
  str = str.exchange("U+2013", "U+FF0D") # full-width minus  
  str = str.exchange("U+00A2", "U+FFE0") # cent as currency  
  str = str.exchange("U+00A3", "U+FFE1") # lb(pound) as currency  
  str = str.exchange("U+00AC", "U+FFE2") # not in boolean algebra  
  str = str.exchange("U+2014", "U+2015") # hyphen  
  str = str.exchange("U+2016", "U+2225") # double vertical lines  
 end  

 def exchange(before_str,after_str)  
  self.gsub( before_str.to_code.chr('UTF-8'),after_str.to_code.chr('UTF-8') )  
 end  

 def to_code  
  return $1.to_i(16) if self =~ /U\+(\w+)/  
  raise ArgumentError, "Invalid argument: #{self}"  
 end  
end  

def get_image
 driver = Selenium::WebDriver.for :chrome
 #q=の後に日本語でキーワード入れて下さい
 driver.navigate.to 'https://www.bing.com/images/search?q=さくらまな'

 10.times do
  driver.find_elements(:class,'iusc').last.location_once_scrolled_into_view
  current_count = driver.find_elements(:class, 'iusc').length
  until current_count < driver.find_elements(:class, 'iusc').length
   sleep(3)
  end
  sleep(5)
 end

 elements = driver.find_elements(:class, 'iusc')
 ary = []
 elements.each do |element| 
  ary << element.attribute('m').scan(/","murl\":"(.+)","turl":/)
 end

 @ary = []
 ary.flatten!
 ary.each do |img|
  if /\.(jpg|png)$/ =~ img.to_s 
   @ary << URI.escape(img.to_s.force_encoding('utf-8').sjisable.encode('UTF-8'))
  end
 end
 @ary.flatten!
 #ファイルの書き出しを行う
 @ary.each_with_index do |url,i|
  #ファイル名を決定
  begin
   if /\.(jpg)$/ =~ url 
    filename = "sakuramana#{i}.jpg"
   else 
    filename = "sakuramana#{i}.png"
   end

   #ファイルを保存するフォルダ名を指定
   p filename
   dirname = "./sakuramana_img/*" + filename
   open(dirname, 'wb') do |file|
    open(url.encode("utf-8", invalid: :replace, undef: :replace), :allow_redirections => :safe) do |data|
     sleep(1)
     file.write(data.read)
    end
   end
  rescue
   puts "とばしました"
  end
 end
end
get_image

4.Run

ターミナルで
ruby infinite_crawl.rb

(ファイル名は適宜合わせてください)

とすると、勝手にクロムが立ち上がり、先ほど指定したフォルダに画像が自動で保存されていくはずです。

尚、10.times do の数字をいじれば30件毎に画像の取得件数が増減します。

おわりに

ということで、以上になります。

エラーでたらそれはきっとsleniumドライバーのあれかBingの仕様変更です。
前者であればたくさんでてくるのでググってみて下さい。

だれかのためになれば幸いです。

それでは〜!

11
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
8