I used selenium and pyautogui to download pictures from a website. The logic of my code works by using selenium to navigate through the pages of my desired links. And by using pyautogui, I am able to combine them to work together to automatically right-click and download the image(not perfectly though) and enter it's file name. The problem I now face is, if the dialogue box to save the image takes too long to pop out. Pyautogui doesn't have the ability to wait for it to pop up and just inputs the text it was supposed to blindly. I'm having difficulty looking this up and figuring out a way to detect the dialogue pop up. And I'm currently stuck with this issue. Is there any real way I can tell my program to wait for it to pop up in selenium itself? Or do I have to use another module for that matter? In that case what module can I use?
Code to reproduce the problem:
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import pyautogui as auto
driver = webdriver.Chrome()
urls = [ # Sample urls.
'https://unsplash.com/photos/MAqmEdUCq4k',
'https://unsplash.com/photos/s7PhRjUJNeA',
]
# Declaring img_xpath and x for loop counting.
img_xpath = '//*[@id="app"]/div/div[2]/div/div[1]/div[3]/div/div/button/div[2]/img'
x = 0
for url in urls: # Loops through urls.
x += 1
time.sleep(2)
driver.get(url)
# Waits for the image element of the site to load.
WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.XPATH, img_xpath))
)
# Calculates current browser center relative to screen position.
win_pos = driver.get_window_position()
win_size = driver.get_window_size()
bcs = [ # bcs stands for Browser Center on Screen.
win_pos['x'] + int(win_size['width'] / 2),
win_pos['y'] + int(win_size['height'] / 2),
]
# Using pyautogui to save image.
auto.moveTo(bcs[0], bcs[1])
auto.click()
time.sleep(1)
auto.rightClick()
auto.moveTo(bcs[0] + 25, bcs[1] + 35)
auto.click()
time.sleep(2) # Comment out this line to reproduce the problem if your system is too fast.
auto.typewrite(f'Sample_{str(x)}')
auto.press('enter')
time.sleep(3)
driver.close()
Extra notes.The code uses a Chrome browser with default settings.
Versions:
Python → 3.8.5
PyAutoGUI → 0.9.50
selenium → 3.141.0
I apologize if there's anything I did wrong in asking. This is my first question here in the site. Also I'm pretty new to python.
I've solved the problem. I used a module called "pywinauto" and used the Application module. Then we go to a loop, and use the connect() method to connect to the browser and use exists() method to tell whether or not the dialog box exists. I put both methods in the loop to update it every second or so. And then we continue the rest of the process once the dialog's been detected. There are other methods of this module to tell if the dialog box exists and is on top of the screen. But this solution worked for me.
The Code:
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import pyautogui as auto
from pywinauto.application import Application as App
import warnings # Import module to remove warnings
driver = webdriver.Chrome()
urls = [ # Sample urls.
'https://unsplash.com/photos/MAqmEdUCq4k',
'https://unsplash.com/photos/s7PhRjUJNeA',
]
# Declaring img_xpath and x for loop counting.
img_xpath = '//*[@id="app"]/div/div[2]/div/div[1]/div[3]/div/div/button/div[2]/img'
x = 0
# Ignore UserWarning.
warnings.simplefilter('ignore', category=UserWarning)
for url in urls: # Loops through urls.
x += 1
time.sleep(2)
driver.get(url)
# Waits for the image element of the site to load.
WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.XPATH, img_xpath))
)
# Declaring program path.
chrome = r'C:\Program Files\Google\Chrome\Application\chrome.exe'
# Calculates current browser center relative to screen position.
win_pos = driver.get_window_position()
win_size = driver.get_window_size()
bcs = [ # bcs stands for Browser Center on Screen.
win_pos['x'] + int(win_size['width'] / 2),
win_pos['y'] + int(win_size['height'] / 2),
]
# Using pyautogui to save image.
auto.moveTo(bcs[0], bcs[1])
auto.click()
time.sleep(1)
auto.moveTo(bcs[0], bcs[1])
auto.rightClick()
auto.moveTo(bcs[0] + 25, bcs[1] + 35)
auto.click()
y = 0
while y != 10:
y += 1
time.sleep(1)
app = App().connect(path=chrome) # Connects script to Chrome.
if app['Save As'].exists(): # Checks dialog box 'Save As' existence.
auto.typewrite(f'Sample_{str(x)}')
auto.press('enter')
break
time.sleep(3)
driver.close()
Extra notes. I've refactored the code a tiny bit to work more fluently. And the all the presets and settings are pretty much the same.
pywinauto version → 0.6.8