🦍

pythonで yahoo 画像検索結果のプレビュー画像(ゴリラ)をかき集める

2021/11/19に公開

yahooでゴリラの画像検索した際のプレビュー画像を集めたくなり
ウホウホしてみました。

python version

python 3.7

やりたいこと

  • yahoo で「ゴリラ」の画像を検索
  • 全てのプレビュー画像を「gorira_images」というディレクトリに保存

事前確認

1. 検索結果のURLを確認

ブラウザでyahooにアクセスして「ゴリラ」の画像を検索し、検索結果のURLを確認。
※今回はchrome使ってます

↓URL↓

2. 検索結果の画面を確認

画面を下にスクロールしていくと、次の画像が表示されていく仕様でした。
さらに画像がある場合は「もっと見る」というボタンが出現し、
「もっと見る」を押下するとさらにスクロールできるようでした。

「もっと見る」というボタンが出現しなくなるまでスクロールを続ければ
全てのプレビュー画像を表示できそうです。

3. 必要な要素の格納場所を探す

Chromeのデベロッパーツールを使い、探索していきます。

  • プレビュー画像のリンク

div.sw-Thumbnail.sw-Thumbnail--tile > figure > a > img' の中の’src’にあるようです。

  • 「もっと見る」ボタン

'div.sw-MoreButton > div > button' のようです。

愚直にコードを書いていく

使用するモジュール

事前確認の結果を踏まえ、以下を使用することにしました。

import os
import urllib.request
from selenium import webdriver
from time import sleep
module 用途
os 保存先ディレクトリの作成やファイル名の取得で使用
urllib.request リンクの画像を保存
selenium 検索結果をスクロールする必要があったので使用
time スクロール中にsleep関数で待たせるために使用

画像の保存先ディレクトリがなければ作成する

save_dir = 'gorira_images'
if not os.path.exists(save_dir):
    os.makedirs(save_dir)

selenium webdriver で検索結果画面にアクセス

#### 検索結果のURL
url = 'https://search.yahoo.co.jp/image/search?ei=UTF-8&fr=mcafeess1&p=%E3%82%B4%E3%83%AA%E3%83%A9'
options = webdriver.ChromeOptions()
options.add_argument('--headless')
driver = webdriver.Chrome(
    executable_path='/Users/ireba-pc/webdriver/chromedriver',
    options=options)

driver.get(url)
driver.implicitly_wait(2)

検索結果画面をスクロール

事前確認の通り、「「もっと見る」というボタンが出現しなくなるまでスクロールを続ければ全てのプレビュー画像を表示できそう」なので、その通り動かします。

### while True でスクロールを続ける
while True:
    #### execute_script メソッドを使用すると、ロードしたページ上でjavascriptを実行できます。
    #### return document.body.scrollHeight でページ全体の高さを取得
    height = driver.execute_script('return document.body.scrollHeight')
    #### scrollTo で取得した高さまでスクロール
    driver.execute_script(f'window.scrollTo(0, {height})')
    sleep(2)

#### try exceptで「もっと見る」ボタンが無い場合の処理を書きます
    try:
        more_button = driver.find_element_by_css_selector('div.sw-MoreButton > div > button')
        more_button.click()
    except:
#### 先に取得した「height(ページ全体の高さ)」が現在の値と変わっていなければ、スクロール完了と見なし、whileを抜けます
        new_height = driver.execute_script('return document.body.scrollHeight')
        if height == new_height:
            break

画像を保存

#### 全てのimgタグを取得
img_tags = driver.find_elements_by_css_selector('div.sw-Thumbnail.sw-Thumbnail--tile > figure > a > img')
#### 取得した img タグをインデックス付きでforで回す
for idx, img_tag in enumerate(img_tags):
    #### src を取り出す
    img_url = img_tag.get_attribute('src')
    #### basenameでファイル名を取得
    img_name = os.path.basename(img_url)
    #### urlopenでリンク先の画像を読み込む
    img_data = urllib.request.urlopen(img_url).read()

#### 定番のファイル保存処理
    #### ファイル名が異常に長いのがあるよーと、エラーが出たのでexceptしておきました
    try:
        with open(f'{save_dir}/{idx}_{img_name}', mode="wb") as f:
            f.write(img_data)

    except OSError as e:
        if e.errno == 63:
            #### ファイル名が~とエラーが出たら、ファイル名を「インデック番号.拡張子」として保存
            _, img_ex = os.path.splitext(img_name)
            with open(f'{save_dir}/{idx}{img_ex}', mode="wb") as f:
                f.write(img_data)
        else:
            pass

こんな感じになりました

import os
import urllib.request
from selenium import webdriver
from time import sleep

save_dir = 'gorira_images'
if not os.path.exists(save_dir):
    os.makedirs(save_dir)

url = 'https://search.yahoo.co.jp/image/search?ei=UTF-8&fr=mcafeess1&p=%E3%82%B4%E3%83%AA%E3%83%A9'
options = webdriver.ChromeOptions()
options.add_argument('--headless')
driver = webdriver.Chrome(
    executable_path='/Users/ireba-pc/webdriver/chromedriver',
    options=options)

driver.get(url)
driver.implicitly_wait(2)

while True:
    height = driver.execute_script('return document.body.scrollHeight')
    driver.execute_script(f'window.scrollTo(0, {height})')
    sleep(2)

    try:
        more_button = driver.find_element_by_css_selector('div.sw-MoreButton > div > button')
        more_button.click()
    except:
        new_height = driver.execute_script('return document.body.scrollHeight')
        if height == new_height:
            break

img_tags = driver.find_elements_by_css_selector('div.sw-Thumbnail.sw-Thumbnail--tile > figure > a > img')
for idx, img_tag in enumerate(img_tags):
    img_url = img_tag.get_attribute('src')
    img_name = os.path.basename(img_url)
    img_data = urllib.request.urlopen(img_url).read()
    try:
        with open(f'{save_dir}/{idx}_{img_name}', mode="wb") as f:
            f.write(img_data)
    except OSError as e:
        if e.errno == 63:
            _, img_ex = os.path.splitext(img_name)
            with open(f'{save_dir}/{idx}{img_ex}', mode="wb") as f:
                f.write(img_data)
        else:
            pass

driver.quit()

実行すると、プレビューゴリラが605体、保存されました。

$ find ./gorira_images/ -size +0 -type f | wc -l
605

中身も見ておきます。
壮観です。神々しいです。

Discussion