##はじめに
機械学習の教師データを集めるため大量の画像が必要だったので、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.コードを書く
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
ターミナルで
(ファイル名は適宜合わせてください)
とすると、勝手にクロムが立ち上がり、先ほど指定したフォルダに画像が自動で保存されていくはずです。
尚、10.times do の数字をいじれば30件毎に画像の取得件数が増減します。
##おわりに
ということで、以上になります。
エラーでたらそれはきっとsleniumドライバーのあれかBingの仕様変更です。
前者であればたくさんでてくるのでググってみて下さい。
だれかのためになれば幸いです。
それでは〜!