昨日上げたブログを修正してみました!
見やすくなってると思います。
こんちゃ!だみーです
卒研のために現在の進捗とかまとめ解こうと思ってブログに書くことにしました。
今回はトルコギキョウという花の画像をスクレイピングして集めたのでまとめます。
環境
Google Chrom(バージョン:114.0.5735.199)
chromedriver(バージョン:114.0.5735.90)
python(Python 3.10.11)
全コード
とりあえず全コード貼っときます。
適切なchromedriverインストールすればすぐに使えると思います!
import requests
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import os
import time
import datetime
from selenium.common.exceptions import NoSuchElementException
from selenium.common.exceptions import ElementClickInterceptedException
tm_sum = time.time()
dt_now = datetime.datetime.now()
dt_date_str = dt_now.strftime('%Y/%m/%d %H:%M')
print(dt_date_str)
QUERY = '〇〇〇'
LIMIT_DL_NUM = 400
SAVE_DIR = '---------'
FILE_NAME = 'trc'
TIMEOUT = 60
ACCESS_WAIT = 1
RETRY_NUM = 3
DRIVER_PATH = '-------'
options = Options()
options.add_argument('--headless')
options.add_argument('--no-sandbox')
options.add_argument('--disable-dev-shm-usage')
options.add_argument('--start-fullscreen')
options.add_argument('--disable-plugins')
options.add_argument('--disable-extensions')
driver = webdriver.Chrome(DRIVER_PATH, options=options)
driver.implicitly_wait(TIMEOUT)
tm_driver = time.time()
print('WebDriver起動完了', f'{tm_driver - tm_sum:.1f}s')
url = f'https://www.google.com/search?q={QUERY}&tbm=isch'
driver.get(url)
tm_geturl = time.time()
print('Google画像検索ページ取得', f'{tm_geturl - tm_driver:.1f}s')
tmb_elems = driver.find_elements_by_css_selector('#islmp img')
tmb_alts = [tmb.get_attribute('alt') for tmb in tmb_elems]
count = len(tmb_alts) - tmb_alts.count('')
print(count)
while count < LIMIT_DL_NUM:
driver.execute_script('window.scrollTo(0, document.body.scrollHeight);')
time.sleep(4)
tmb_elems = driver.find_elements_by_css_selector('#islmp img')
tmb_alts = [tmb.get_attribute('alt') for tmb in tmb_elems]
count = len(tmb_alts) - tmb_alts.count('')
print(count)
imgframe_elem = driver.find_element_by_id('islsp')
os.makedirs(SAVE_DIR, exist_ok=True)
HTTP_HEADERS = {'User-Agent': driver.execute_script('return navigator.userAgent;')}
print(HTTP_HEADERS)
IMG_EXTS = ('.jpg', '.jpeg', '.png', '.gif')
def get_extension(url):
url_lower = url.lower()
for img_ext in IMG_EXTS:
if img_ext in url_lower:
extension = '.jpg' if img_ext == '.jpeg' else img_ext
break
else:
extension = ''
return extension
def download_image(url, path, loop):
result = False
for i in range(loop):
try:
r = requests.get(url, headers=HTTP_HEADERS, stream=True, timeout=10)
r.raise_for_status()
with open(path, 'wb') as f:
f.write(r.content)
except requests.exceptions.SSLError:
print('***** SSL エラー')
break
except requests.exceptions.RequestException as e:
print(f'***** requests エラー({e}): {i + 1}/{RETRY_NUM}')
time.sleep(1)
else:
result = True
break
return result
tm_thumbnails = time.time()
print('画像取得', f'{tm_thumbnails - tm_geturl:.1f}s')
EXCLUSION_URL = 'https://lh3.googleusercontent.com/'
count = 0
url_list =
for tmb_elem, tmb_alt in zip(tmb_elems, tmb_alts):
if tmb_alt == '':
continue
print(f'{count}: {tmb_alt}')
for i in range(RETRY_NUM):
try:
tmb_elem.click()
except ElementClickInterceptedException:
print(f'***** click エラー: {i + 1}/{RETRY_NUM}')
driver.execute_script('arguments[0].scrollIntoView(true);', tmb_elem)
time.sleep(1)
else:
break
else:
print('***** キャンセル')
continue
time.sleep(ACCESS_WAIT)
alt = tmb_alt.replace("'", "\\'")
try:
img_elem = imgframe_elem.find_element_by_css_selector(f'img[alt=\'{alt}\']')
except NoSuchElementException:
print('***** img要素検索エラー')
print('***** キャンセル')
continue
tmb_url = tmb_elem.get_attribute('src')
for i in range(RETRY_NUM):
url = img_elem.get_attribute('src')
if EXCLUSION_URL in url:
print('***** 除外対象url')
url = ''
break
elif url == tmb_url:
print(f'***** urlチェック: {i + 1}/{RETRY_NUM}')
time.sleep(1)
url = ''
else:
break
if url == '':
print('***** キャンセル')
continue
ext = get_extension(url)
if ext == '':
print(f'***** urlに拡張子が含まれていないのでキャンセル')
print(f'{url}')
continue
filename = f'{FILE_NAME}{count}{ext}'
path = SAVE_DIR + '/' + filename
result = download_image(url, path, RETRY_NUM)
if result == False:
print('***** キャンセル')
continue
url_list.append(f'{filename}: {url}')
count += 1
if count >= LIMIT_DL_NUM:
break
tm_end = time.time()
print('ダウンロード', f'{tm_end - tm_thumbnails:.1f}s')
print('------------------------------------')
total = tm_end - tm_sum
total_str = f'トータル時間: {total:.1f}s({total/60:.2f}min)'
count_str = f'ダウンロード数: {count}'
print(total_str)
print(count_str)
path = SAVE_DIR + '/' + '_url.txt'
with open(path, 'w', encoding='utf-8') as f:
f.write(dt_date_str + '\n')
f.write(total_str + '\n')
f.write(count_str + '\n')
f.write('\n'.join(url_list))
driver.quit()
ここから詳しくコードを解説します。
使用ライブラリ宣言
import requests
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import os
import time
import datetime
from selenium.common.exceptions import NoSuchElementException
from selenium.common.exceptions import ElementClickInterceptedException
今回使用したライブラリは大まかに5つ。
requestsはメソッドを操作しやすくしたもの
import requests
webスクレイピングやwebAPIを使いwebからデータを取得したいときに使う。
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.common.exceptions import NoSuchElementException
from selenium.common.exceptions import ElementClickInterceptedException
seleniumはブラウザを自動的に操作するライブラリです。
seleniumの使い方は以下のサイトにわかりやすくまとまっていたので参考にしてください。
【Python】Seleniumとは?Webブラウザ操作の自動化方法を徹底解説
os
import os
osに存在している様々な機能を利用するためのモジュールです。
主にファイルやディレクトリのを操作する際に用います。
time
import time
timeはプログラム内で現在時刻を確認したり処理を一時停止できるモジュールです。
datetime
import datetime
datetimeは日付をプログラムから取得でき、日付や時間の表示を可能にするモジュールです。
プログラムの実行状況を記録
tm_sum = time.time()
dt_now = datetime.datetime.now()
dt_date_str = dt_now.strftime('%Y/%m/%d %H:%M')
print(dt_date_str)
プログラムの処理時間と現在日時を表示します。
検索内容の指定
QUERY = '〇〇〇'
LIMIT_DL_NUM = 400
SAVE_DIR = '---------'
FILE_NAME = 'trc'
TIMEOUT = 60
ACCESS_WAIT = 1
RETRY_NUM = 3
DRIVER_PATH = '-------'
検索キーワードや画像のダウンロード枚数の指定をします。
出力フォルダへのパスと、chromedriver.exeのパスはご自身の環境のパスを指定してください。
options = Options()
options.add_argument('--headless')
options.add_argument('--no-sandbox')
options.add_argument('--disable-dev-shm-usage')
options.add_argument('--start-fullscreen')
options.add_argument('--disable-plugins')
options.add_argument('--disable-extensions')
driver = webdriver.Chrome(DRIVER_PATH, options=options)
ここではoptionにchromeの起動条件を追加していきchromeを起動します。今回はヘッドレスモードで起動します。(ここは個人の好みで調節してください。)
起動条件などは以下のサイトでまとめてくれています。
【Python3】SeleniumのChrome起動オプションについて | せなブログ
残りのプログラムコードの大まかな処理の流れ
while count < LIMIT_DL_NUM:
driver.execute_script('window.scrollTo(0, document.body.scrollHeight);')
time.sleep(4)
tmb_elems = driver.find_elements_by_css_selector('#islmp img')
tmb_alts = [tmb.get_attribute('alt') for tmb in tmb_elems]
count = len(tmb_alts) - tmb_alts.count('')
print(count)
ページをスクロールして画像を取得する。
IMG_EXTS = ('.jpg', '.jpeg', '.png', '.gif')
ダウンロードする画像の拡張子を指定する。
def get_extension(url):
url_lower = url.lower()
for img_ext in IMG_EXTS:
if img_ext in url_lower:
extension = '.jpg' if img_ext == '.jpeg' else img_ext
break
else:
extension = ''
return extension
web上の拡張子を取得する。
EXCLUSION_URL = 'https://lh3.googleusercontent.com/'
count = 0
url_list = []
for tmb_elem, tmb_alt in zip(tmb_elems, tmb_alts):
if tmb_alt == '':
continue
print(f'{count}: {tmb_alt}')
for i in range(RETRY_NUM):
try:
tmb_elem.click()
except ElementClickInterceptedException:
print(f'***** click エラー: {i + 1}/{RETRY_NUM}')
driver.execute_script('arguments[0].scrollIntoView(true);', tmb_elem)
time.sleep(1)
else:
break
else:
print('***** キャンセル')
continue
time.sleep(ACCESS_WAIT)
alt = tmb_alt.replace("'", "\\'")
try:
img_elem = imgframe_elem.find_element_by_css_selector(f'img[alt=\'{alt}\']')
except NoSuchElementException:
print('***** img要素検索エラー')
print('***** キャンセル')
continue
tmb_url = tmb_elem.get_attribute('src')
for i in range(RETRY_NUM):
url = img_elem.get_attribute('src')
if EXCLUSION_URL in url:
print('***** 除外対象url')
url = ''
break
elif url == tmb_url:
print(f'***** urlチェック: {i + 1}/{RETRY_NUM}')
time.sleep(1)
url = ''
else:
break
if url == '':
print('***** キャンセル')
continue
ext = get_extension(url)
if ext == '':
print(f'***** urlに拡張子が含まれていないのでキャンセル')
print(f'{url}')
continue
filename = f'{FILE_NAME}{count}{ext}'
path = SAVE_DIR + '/' + filename
result = download_image(url, path, RETRY_NUM)
if result == False:
print('***** キャンセル')
continue
url_list.append(f'{filename}: {url}')
count += 1
if count >= LIMIT_DL_NUM:
break
画像をクリックし、URLを取得してリスト化する。
URLから画像を保存する。この際に、後で扱いやすいようにファイル名を整える。
まとめ
今回はgoogle chromeを使って画像スクレイピングを行った。
500枚ほど画像が欲しかったのだが、どうしても400枚画像を読み込んだところで処理がフリーズしていまった。
断念して今回は400枚の画像をダウンロードした。
今後より多くの画像を保存できるようにプログラムを変える必要がある。
また、画像判別のモデルを作る予定なので画像の水増しが必要だ。
今回ダウンロードした画像をクラスタリングしてどのくらい分類できるか調べるのが今後の課題だ。
進捗あったらまた書きます。
んじゃ!!