Googleの検索結果から画像をまとめてダウンロードする時に少し工夫が必要だった話

きくち
アドベントカレンダーのトップバッターを任せられました。がんばります
UEQareer Advent Calender 2016

今回はseleniumを使って見ようと思います
最近、画像の機械学習をしていて、画像が大量に必要になるんですが

これが結構めんどくさいです
前はgoogleの画像検索APIで大量に取得できたと思いますが
有料になったりして、無料だと一日に使える数が制限されていたりします

そこで、seleniumを使ってブラウザを操作して画像の検索結果から直接画像を手に入れようと思います

今回はrubyで書いていきます

画像の検索

渡されたキーワードから、検索を行う部分です
引数で渡されたキーワードで検索した結果を表示します

require 'selenium-webdriver'
require 'uri'
require 'open-uri

uery = ARGV[0]
driver = Selenium::WebDriver.for :chrom
driver.navigate.to 'https://www.google.co.jp/search?q='+
    query +
    '&source=lnms&tbm=isch&
    sa=X&ved=0ahUKEwjQvbuzs77QAhXLabwKHRoICHgQ_AUICCgB&
    biw=1600&bih=805'/h2

画像URLの取得

そのあと、検索結果に並んでいる画像をひとつ、ひとつダウンロードしていきます
並んでいるサムネイルでは画像サイズが小さくて使いもんぽにならないので
リンクを辿って、元の画像を取得しようと思います

画像をクリックして表示される詳細画面の要素の中から
元画像らしきURLを取得してリストに格納していきます

  #リストを取得    
list = driver.find_elements(:class, "rg_di")
list = driver.find_elements(:class, "rg_di")
url_list = []
for i in list do
    i.click
    link = driver.find_elements(:xpath, '//div[@id="irc_cc"]/div[2]/div[3]/div/div[2]/table/tbody/tr/td[2]/a')
    url_list.push link[0].attribute("href")
end

 

あとはリストに格納したURLから画像をダウンロードしていく

def fetch_image(url,file_name,dir)
    if file_name.nil?
        file_name = File.basename(url)
    end
    save_image_name = dir + '/' + file_name + '.jpg'
    p save_image_name
    open(save_image_name, 'wb') do |file|
        open url do |data|
            file.write(data.read)
        end
    end
end


for url in url_list do
    fetch_image(url,query,"img")
end

 

終わりかと思ったら、そうじゃない

実はこれだけだと、50枚ぐらいしか画像を手に入れることができません><
googleの画像検索の検索結果はスクロールするたびに新しい画像が読み込まれて
要素が増えていきます。

ですので、先にスクロールさせて要素を表示させた状態で
要素の取得を行ってリストに格納していくのです。

また、画面に収まっていない要素をクリックしようとすると
エラーが出るので
クリックする前に要素の位置までスクロールさせる処理が必要です

def scroll(driver,el)
    el.location_once_scrolled_into_view
endrequire 'selenium-webdriver'
require 'uri'
require 'open-uri

#取得して最後の要素までスクロールを何回か
10.each do
    list = driver.find_elements(:class, "rg_di")
    scroll(driver,list.last)
end

list = driver.find_elements(:class, "rg_di")
url_list = []
p list.size
for i in list do
    scroll(driver,i) #要素の位置までスクロール
    sleep 0.5
    i.click
    link = driver.find_elements(:xpath, '//div[@id="irc_cc"]/div[2]/div[3]/div/div[2]/table/tbody/tr/td[2]/a')
    url_list.push link[0].attribute("href")
end

 

更に改良するには

検索結果をスクロールしていくと

「検索をもっと表示」というボタンが現れるので
ボタンが表示されたら、クリックして
またスクロールするという処理を加えれば
もっと多くの画像をダウンロードできるはずです