[Python] Save images drawn in canvas using Selenium (ActionChains, PyAutoGUI, base64, etc.)

When retrieving an image by scraping, I had a hard time saving the image of the case drawn in canvas instead of the general img tag format.

qiita用_グラフ1.png

I want to save the image displayed in this way.

The image is drawn in canvas as the title suggests.

Try saving with right click

After researching the page, I found that I could save the image by right-clicking.

qiita用_グラフ2.png

So, I tried various things to realize the flow of "right-click the image → save" programmatically.

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

#Chrome Driver settings
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)
#Waiting time for screen drawing
wait = WebDriverWait(driver, 10)
driver.implicitly_wait(10)
#Access page
url = 'URL of the target page'
driver.get(url)
#Wait for the page to load
wait.until(EC.presence_of_all_elements_located)
#Image location
xpath = 'XPATH of the image you want to save'
img = driver.find_element_by_xpath(xpath)
#Move the mouse to the location of the image and then right-click
actions = ActionChains(driver)
actions.move_to_element(img).context_click(img).perform()
#Enter the "↓" key 5 times
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 Enter
actions.send_keys(Keys.ENTER).perform()

Access the target page with Selenium ↓ Use Action Chains to move the mouse to the location of the image + right click to display the context menu ↓ Operate the context menu by keyboard input ("↓" key x 5 times + press Enter key)

I tried to save the image, but ... no.

It works fine until right-clicking, but I can't operate the context menu.

When I checked the processing movement, the browser screen moved down a little after right-clicking.

Apparently, I'm typing on the browser instead of the context menu ...

So I tried another method.


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

#Chrome Driver settings
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)
#Waiting time for screen drawing
wait = WebDriverWait(driver, 10)
driver.implicitly_wait(10)
#Access page
url = 'URL of the target page'
driver.get(url)
#Wait for the page to load
wait.until(EC.presence_of_all_elements_located)
#Image location
xpath = 'XPATH of the image you want to save'
img = driver.find_element_by_xpath(xpath)
#Move the mouse to the location of the image and then right-click
actions = ActionChains(driver)
actions.move_to_element(img).context_click(img).perform()
#Save image
pyautogui.typewrite('v')

Access the target page with Selenium ↓ Use Action Chains to move the mouse to the location of the image + right click to display the context menu ↓ Keyboard input with PyAutoGUI (enter "v")

When I changed it to the flow, this worked well!

qiita用_グラフ保存.png

The result of image saving that you are familiar with in this way.

It doesn't work if it's headless

That's it for making the Chrome Driver headless and writing the file renaming process!

I thought ... I couldn't save it when I made it headless lol

Apparently PyAutoGUI is sending instructions to operate on the active window. (It's written as GUI, so that's right lol)

Therefore, even if you move it in a non-headless state, if you move it while performing another operation, saving will naturally fail.

This is very inconvenient, so I want to save it headless.

I could be headless

As a result of various investigations, I was able to go headless.

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

#Chrome Driver settings
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)
#Waiting time for screen drawing
wait = WebDriverWait(driver, 10)
driver.implicitly_wait(10)
#Access page
url = 'URL of the target page'
driver.get(url)
#Wait for the page to load
wait.until(EC.presence_of_all_elements_located)
#Image location
xpath = 'XPATH of the image you want to save'
img = driver.find_element_by_xpath(xpath)
#Get canvas as Base64 string
canvas_base64 = driver.execute_script("return arguments[0].toDataURL('image/png').substring(21);", img)
#Decode
canvas_png = base64.b64decode(canvas_base64)
#file name
file_name = 'Arbitrary file name.png'
#File output
with open(file_name, 'wb') as f:
    f.write(canvas_png)

I was able to save the canvas as a character string in Base64 in the flow of → decoding → file output!

Finally

Thanks to my addiction (?), I learned about ActionChains, PyAutoGUI, and base64 all at once. Automation is fun.

Reference link

How to perform right click using Selenium ChromeDriver? Let Python do iterative work with PyAutoGui How to save a canvas as PNG in Selenium?

Recommended Posts

[Python] Save images drawn in canvas using Selenium (ActionChains, PyAutoGUI, base64, etc.)
Save images using python3 requests
Base64 encoding images in Python 3
Load images from URLs using Pillow in Python 3
Create a data collection bot in Python using Selenium
Collect tweets using tweepy in Python and save them in MongoDB
Scraping with selenium in Python
[Python] Try using Tkinter's canvas
Scraping with Selenium in Python
Start to Selenium using python
Translate using googletrans in Python
Using Python mode in Processing
Object extraction in images by pattern matching using OpenCV with Python