I am new to using python's selenium model and ran into a problem while trying to automate the checkout process for this store, https://bellevo.store/products/luna. I have python click buy now and fill out the information and it works well until it comes to the city field. I don't think it is seeing it as clickable and I am not sure why. Any help would be much appreciated. Here is my code
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 time
# Initialize a new browser instance
driver = webdriver.Chrome()
# Click "Buy It Now"
wait = WebDriverWait(driver, 10)
buy_now_button = wait.until(EC.element_to_be_clickable((By.XPATH, "//*[@id=\"product form-template--22164028883241__main\"]/div/div/dynamic-checkout")))
buy_now_button.click()
# Fill in contact and delivery fields
wait.until(EC.element_to_be_clickable((By.XPATH, "//*[@id=\"email\"]"))).send_keys(phone_number)
time.sleep(.5)
wait.until(EC.element_to_be_clickable((By.XPATH, "//*[@id=\"TextField0\"]"))).send_keys(first_name)
time.sleep(.5)
wait.until(EC.element_to_be_clickable((By.XPATH, "//*[@id=\"TextField1\"]"))).send_keys(last_name)
time.sleep(.5)
wait.until(EC.element_to_be_clickable((By.XPATH, "//*[@id=\"billing-address1\"]"))).send_keys(address + ", " + city + ", " + state + ", USA")
time.sleep(.5)
wait.until(EC.element_to_be_clickable((By.XPATH, "//label[@id=\"TextField6-label\"]"))).send_keys(city)
I have tried many different methods and have not been able to find a solution. As I said, I am new to selenium and probably don't have a great understanding of it.
You were pretty close. Your code is actually pretty good. I have some suggestions for improvement below.
This can be a tough scenario. I think the issue you were running into is you were trying to type in the City field but it wasn't visible at the time because the address suggestion dropdown was open. There are a couple ways to approach this...
I went with #2. I also cleaned up a few things...
If you are using an ID, use By.ID()
instead of By.XPATH()
.
I removed the time.sleep()
s. You don't need them since you have proper waits. You have WebDriverWait
s which is good... it's a best practice to use them and avoid time.sleep()
.
In the future, if you have nested double quotes ("
), alternate them with single quotes ('
), e.g. change "//*[@id=\"email\"]"
to "//*[@id='email']"
. It makes it easier to read and removes the escape chars.
If you are going to click an element, use EC.element_to_be_clickable()
. If you are going to otherwise interact with an element, e.g. send_keys(), use EC.visibility_of_element_located()
. Avoid EC.presence_of_element_located()
in most cases... it's just confirming the element is in the DOM, not that it's visible or ready to be clicked. I see a lot of people using that and then clicking, etc. the element... that' s just asking for intermittent issues that are hard to track down.
You don't have to but I prefer f
string literals to concatenate strings. I find them much easier to read and use. No more ensuring you have matching "
s each time you insert a new variable, etc. See the docs for more info.
s = address + ", " + city + ", " + state + ", USA"
becomes
s = f"{address}, {city}, {state}, USA"
Taking all my suggestions into account, the cleaned up code is below and working.
from selenium import webdriver
from selenium.webdriver import Keys
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
# Initialize a new browser instance
url = 'https://bellevo.store/products/luna'
driver = webdriver.Chrome()
driver.maximize_window()
driver.get(url)
wait = WebDriverWait(driver, 10)
# Click "Buy It Now"
wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR,"button.shopify-payment-button__button"))).click()
# Fill in contact and delivery fields
wait.until(EC.element_to_be_clickable((By.ID, "email"))).send_keys(phone_number)
wait.until(EC.element_to_be_clickable((By.ID, "TextField0"))).send_keys(first_name)
wait.until(EC.element_to_be_clickable((By.ID, "TextField1"))).send_keys(last_name)
e = wait.until(EC.visibility_of_element_located((By.ID, "billing-address1")))
e.send_keys(f"{address}, {city}, {state}, USA")
wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, "#billing-address1-options > li"))).click()
e.send_keys(Keys.ENTER)