✏️

ログインするサイトをスクレイピングするときseleniumでよく使うコード

2023/07/12に公開

社内の定形業務を自動化するときによく使うコードを自分用にまとめました。
RPAプログラムを作るときにこのページだけ見れば大体作れるようにしたいと思って書いてます。

環境

  • Windows10
  • VSCode

構築した仮想環境

  • venv
  • python3.7

よく入れてるモジュール

pip install selenium
pip install pyperclip
pip install openpyxl

想定してること

  • 特定のサイトにログインして中のテキスト、画像を取得したい

よくインポートするモジュール

import os
import time

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import Select
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import NoSuchElementException

import requests
from PIL import Image
from io import BytesIO
import subprocess

ポートを指定してブラウザを起動する

メインファイルとは別ファイルで作成して実行するとうまく動きます。

  1. run_remote_debugging.py実行
  2. main.py実行
import subprocess
def run_remote_debugging():
    command = r'"C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe" --remote-debugging-port=9222'
    subprocess.run(command, shell=True)

run_remote_debugging()

iframe切り替え

テキスト入力欄などはiframeで作られていることがあります。
iframe要素はselenium側で読み込むウィンドウを切り替える必要があります。
iframeにウィンドウを切り替えるとiframe内の要素を取得できるようになります。
処理が終わったら元のウィンドウに戻します。

# テキスト入力欄の要素を取得
iframe = driver.find_element(By.CLASS_NAME, "[クラス名]")
# テキスト入力欄にウィンドウを切り替え
driver.switch_to.frame(iframe)

# 何かしらの処理を書く

# 元のウィンドウに戻す
driver.switch_to.default_content()

別ウィンドウが立ち上がったときそのウィンドウにフォーカスする

current_window_handle = driver.current_window_handle

all_window_handles = driver.window_handles
for handle in all_window_handles:
    if handle != current_window_handle:
        new_window_handle = handle
        break
driver.switch_to.window(new_window_handle

〇秒待つ

1は1秒のこと。
ページの読み込みが遅いときや動作確認をするときに使っています。

time.sleep(1)

読み込み10秒

'WebDriverWait(driver, 10)'で取得したい要素を最大10秒間探し続けてくれます。

element = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.[取得要素タグ名], "[タグ情報]")))
element.click()

特定の文字が入ったリンクテキストを要素取得

ページ内に[特定の文字]を探し出し、要素を取得します。

element = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.LINK_TEXT, "[特定の文字]")))
element.click()

IDから要素取得

element = wait.until(EC.element_to_be_clickable((By.ID, "[ID名]")))
element.click()

CSSから要素取得

insert_html = driver.find_element(By.CSS_SELECTOR, 'li[editor-command="[タグ情報]"] svg')
insert_html.click()

子要素も含めたCSSの要素取得

find_elementsは子要素を含めた要素を取得できます。

elements = driver.find_elements(By.CSS_SELECTOR, ".custom_text[data-id='text']")

画像情報をリストに格納する

# 画像URLを入れる箱
content_list = []
# ページ内のすべての要素を取得してfor文で回す
for element in content_elements.find_elements(By.XPATH, "./*"):
    # imgタグの要素を探す
    if element.tag_name == "img":
	# imgタグの画像URL情報を取り出す
	image_info = element.get_attribute("src")
	# 取り出した画像URLをリストに格納
        content_list.append(image_info)
print(content_list)

取得した画像をダウンロードする

取得した画像URLを使って画像をjpg形式でダウンロードします。

import requests
from PIL import Image
for url in content_list:
    response = requests.get(url)
    image = Image.open(BytesIO(response.content))
    filename = os.path.splitext(os.path.basename(url))[0] + ".jpg"
    image.save(output_dir + filename, format="JPEG")

取得した要素の文字を取り出す

取得した要素の引数に.textをつけると、その要素内の文字を取得できます。

printでどんな要素が取得できたか確認する時に使っています。

element.text

テキスト欄にフォーカスして特定の文字をペースト

テキスト入力欄に自動でなにか文字を入力します。

text = "[ペーストしたい文字]"
# テキスト欄の要素を取得
element = driver.find_element(By.CSS_SELECTOR, "input[data-id='textbox']")
# テキスト欄をクリア
element.clear()
# テキスト欄に指定の文字をペースト
element.send_keys(text)

特定の文字が見つかるまで探し続ける

ページ内にあるリンク要素をすべて取得して、それをfor文で回しながら探している文字が見つかるまで回しています。

# [クラス名]の要素を取得
element = driver.find_element(By.CLASS_NAME, "[クラス名]")
# [クラス名]の子要素からaタグを取得
elements = element.find_elements(By.TAG_NAME, "a")

title = "[特定の文字]"

found = False

for element in elements:
	# 要素内の文字を取得
	text = element.text
	# 要素内の文字と[特定の文字]が同じかどうか
	if title == text:
		# 要素内の文字と[特定の文字]が同じだったらfoundをTrueにしてfor文を抜ける
		found = True
		break

if not found:
    print("要素内にtitleと同じ文字列は含まれていません。")

取得した要素のHTMLを確認する

print(element.get_attribute('innerHTML'))

ページ内のaタグを取得する

element = target_element.find_element(By.TAG_NAME, "a")

複数のリンクをリストで格納し別ウィンドウが立ち上がったら落とす

# ページ内のリンクをすべて取得し、リストに格納
element = WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, 'span.[要素情報]')))
while True:
	try:
		# 何かしらの処理を書く
		# ウィンドウを閉じる
		driver.close()
		# ウィンドウのフォーカスを元に戻す
		driver.switch_to.window(current_window_handle)
		time.sleep(10)
	except:
		break

終わり

ログインしてSeleniumで自動化させるときによく使うコード集でした。
これらのコードをコピーしたり少し書き換えれば大体自動化できるはず...!

ここまで読んでくださりありがとうございました。

Discussion