[Python] Selenium을 사용하여 캔버스로 그려진 이미지 저장 (ActionChains, PyAutoGUI, base64 등)

스크래핑으로 이미지를 얻을 때, 일반적인 img 태그 형식이 아닌 캔버스로 그려진 케이스의 이미지 보존으로 고전했다.



이러한 형태로 표시된 이미지를 저장하고 싶습니다.

이미지는 제목대로 canvas로 그려져 있습니다.

마우스 오른쪽 버튼으로 저장 시도



페이지를 여러가지 조사하고 있었는데, 오른쪽 클릭으로 화상을 보존할 수 있다는 것을 알았다.



그래서 "이미지를 오른쪽 클릭 → 저장"의 흐름을 프로그램으로 실현하기 위해 다양한 시도했다.
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.action_chains import ActionChains

# ChromeDriver設定
options = Options()
options.add_argument('--disable-gpu')
options.add_argument('--disable-extensions')
options.add_argument('--proxy-server="direct://"')
options.add_argument('--proxy-bypass-list=*')
options.add_argument('--start-maximized')
driver = webdriver.Chrome(options=options)
# 画面描画の待ち時間
wait = WebDriverWait(driver, 10)
driver.implicitly_wait(10)
# ページへアクセス
url = '対象ページのURL'
driver.get(url)
# ページが読み込まれるまで待機
wait.until(EC.presence_of_all_elements_located)
# 画像の場所
xpath = '保存したい画像のXPATH'
img = driver.find_element_by_xpath(xpath)
# 画像の場所へマウス移動してから右クリック
actions = ActionChains(driver)
actions.move_to_element(img).context_click(img).perform()
# 「↓」キーを5回入力
actions.send_keys(Keys.ARROW_DOWN).send_keys(Keys.ARROW_DOWN).send_keys(Keys.ARROW_DOWN).send_keys(Keys.ARROW_DOWN).send_keys(Keys.ARROW_DOWN).perform()
# Enterキーを入力
actions.send_keys(Keys.ENTER).perform()

Selenium에서 대상 페이지에 액세스

ActionChains를 사용하여 이미지 위치로 마우스 이동 + 마우스 오른쪽 버튼으로 컨텍스트 메뉴 표시

키보드 입력으로 컨텍스트 메뉴를 조작(「↓」키×5회+Enter 키 누름)

라고 하는 흐름으로 화상을 보존하려고 했지만… 안 된다.

오른쪽 클릭까지는 능숙하지만 컨텍스트 메뉴의 조작을 할 수 없다.

처리의 움직임을 확인해 보았는데, 오른쪽 클릭 후에 브라우저의 화면이 조금 아래로 움직이고 있다.

아무래도 컨텍스트 메뉴가 아니라 브라우저를 향해 키보드 입력해 버리고 있는 것 같은….

그래서 다른 방법을 시도했다.

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.action_chains import ActionChains
import pyautogui

# ChromeDriver設定
options = Options()
options.add_argument('--disable-gpu')
options.add_argument('--disable-extensions')
options.add_argument('--proxy-server="direct://"')
options.add_argument('--proxy-bypass-list=*')
options.add_argument('--start-maximized')
driver = webdriver.Chrome(options=options)
# 画面描画の待ち時間
wait = WebDriverWait(driver, 10)
driver.implicitly_wait(10)
# ページへアクセス
url = '対象ページのURL'
driver.get(url)
# ページが読み込まれるまで待機
wait.until(EC.presence_of_all_elements_located)
# 画像の場所
xpath = '保存したい画像のXPATH'
img = driver.find_element_by_xpath(xpath)
# 画像の場所へマウス移動してから右クリック
actions = ActionChains(driver)
actions.move_to_element(img).context_click(img).perform()
# 画像を保存
pyautogui.typewrite('v')

Selenium에서 대상 페이지에 액세스

ActionChains를 사용하여 이미지 위치로 마우스 이동 + 마우스 오른쪽 버튼으로 컨텍스트 메뉴 표시

PyAutoGUI로 키보드 입력(``v'' 입력)

라고 하는 흐름으로 바꾸어 보았더니, 이것이 잘 동작했다!



이런 식으로 익숙한 이미지 보존의 결과가.

헤드리스라면 움직이지 않는다.



이것으로 나머지는 ChromeDriver를 헤드리스로 하거나 파일명 변경 처리를 써서 끝이다!

라고 생각하면 ... 헤드리스로하면 보존 할 수 없게 된 웃음

아무래도 PyAutoGUI는 활성화되어 있는 윈도우에 대해서 조작하는 명령을 보내고 있는 것 같다.
(GUI라고 쓰고 있으니까 그렇다 웃음)

그래서 헤드리스가 아닌 상태에서 움직여도 다른 조작을 하면서 움직이면 당연히 보존에 실패한다.

이것은 매우 불편하기 때문에 뭐니뭐니해도 헤드리스로 저장하고 싶다 ....

헤드리스에서도 갈 수 있었다.



여러가지 조사한 결과, 헤드리스라도 됐다.
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import base64

# ChromeDriver設定
options = Options()
options.add_argument('--disable-gpu')
options.add_argument('--disable-extensions')
options.add_argument('--proxy-server="direct://"')
options.add_argument('--proxy-bypass-list=*')
options.add_argument('--start-maximized')
options.add_argument('--headless')
driver = webdriver.Chrome(options=options)
# 画面描画の待ち時間
wait = WebDriverWait(driver, 10)
driver.implicitly_wait(10)
# ページへアクセス
url = '対象ページのURL'
driver.get(url)
# ページが読み込まれるまで待機
wait.until(EC.presence_of_all_elements_located)
# 画像の場所
xpath = '保存したい画像のXPATH'
img = driver.find_element_by_xpath(xpath)
# canvasをBase64文字列で取得
canvas_base64 = driver.execute_script("return arguments[0].toDataURL('image/png').substring(21);", img)
# デコード
canvas_png = base64.b64decode(canvas_base64)
# ファイル名
file_name = '任意のファイル名.png'
# ファイル出力
with open(file_name, 'wb') as f:
    f.write(canvas_png)

canvas를 Base64에서 문자열로 취득 → 디코드 → 파일 출력이라는 흐름으로 저장할 수 있었다!

마지막으로



빠진 덕분(?)으로 ActionChains,PyAutoGUI,base64에 대해 정리해 배울 수 있었다.
자동화 재미 있습니다.

참고 링크



How to perform right click using Selenium ChromeDriver?
PyAutoGui로 반복 작업을 Python에 보내자.
How to save a canvas as PNG in Selenium?

좋은 웹페이지 즐겨찾기