Selenium can find element when run locally but can't find element when run on Heroku server

Viewed 417

When I run the following code locally, Selenium is able to find all elements and everything works well:

from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager
from twilio.rest import Client

account_sid = ACCOUNT_SID
auth_token = AUTH_TOKEN
client = Client(account_sid, auth_token)

def runAmazonXBot():
    driver = webdriver.Chrome(ChromeDriverManager().install())
    driver.get("https://www.amazon.com/Ticonderoga-Wood-Cased-Graphite-Pre-Sharpened-13818/dp/B002VL5IJO/ref=sr_1_5?dchild=1&keywords=pencil&qid=1610946344&sr=8-5")
    driver.find_element_by_xpath("/html//input[@id='buy-now-button']").click()
    driver.find_element_by_xpath("/html//input[@id='ap_email']").send_keys(EMAIL)
    driver.find_element_by_xpath("//span[@id='continue']//input[@id='continue']").click()
    driver.find_element_by_xpath("/html//input[@id='ap_password']").send_keys(PASSWORD)
    driver.find_element_by_xpath("/html//input[@id='signInSubmit']").click()
    driver.find_element_by_xpath("//span[@id='placeYourOrder']//input[@name='placeYourOrder1']").click()

runAmazonXBot()
message = client.messages \
    .create(
        body="Success!",
        from_=PHONE_NUMBER_1,
        to=PHONE_NUMBER_2
    )

but when I run that same code in a Heroku server (with Tweepy involved), like below:

import tweepy
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import Select
import os
from twilio.rest import Client
import traceback2 as traceback

chrome_options = webdriver.ChromeOptions()
chrome_options.binary_location = os.environ.get("GOOGLE_CHROME_BIN")
chrome_options.add_argument("--headless")
chrome_options.add_argument("--disable-dev-shm-usage")
chrome_options.add_argument("--no-sandbox")
driver = webdriver.Chrome(executable_path=os.environ.get("CHROMEDRIVER_PATH"), chrome_options=chrome_options)

consumer_key = CONSUMER_KEY
consumer_secret = CONSUMER_SECRET
access_token = ACCESS_TOKEN
access_token_secret = ACCESS_TOKEN_SECRET

auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
auth.set_access_token(access_token, access_token_secret)

api = tweepy.API(auth)

def copAmazon():
    chrome_options = webdriver.ChromeOptions()
    chrome_options.binary_location = os.environ.get("GOOGLE_CHROME_BIN")
    chrome_options.add_argument("--headless")
    chrome_options.add_argument("--disable-dev-shm-usage")
    chrome_options.add_argument("--no-sandbox")
    driver = webdriver.Chrome(executable_path=os.environ.get("CHROMEDRIVER_PATH"), chrome_options=chrome_options)
    driver.get("https://www.amazon.com/Ticonderoga-Wood-Cased-Graphite-Pre-Sharpened-13818/dp/B002VL5IJO/ref=sr_1_5?dchild=1&keywords=pencil&qid=1610946344&sr=8-5")
    driver.find_element_by_xpath("/html//input[@id='buy-now-button']").click()
    driver.find_element_by_xpath("/html//input[@id='ap_email']").send_keys(EMAIL)
    driver.find_element_by_xpath("//span[@id='continue']//input[@id='continue']").click()
    driver.find_element_by_xpath("/html//input[@id='ap_password']").send_keys(PASSWORD)
    driver.find_element_by_xpath("/html//input[@id='signInSubmit']").click()
    driver.find_element_by_xpath("//span[@id='placeYourOrder']//input[@name='placeYourOrder1']").click()

account_sid = ACCOUNT_SID
auth_token = AUTH_TOKEN
client = Client(account_sid, auth_token)
class MyStreamListener(tweepy.StreamListener):
    def on_status(self, status):
        if status.user.id_str == TWITTER_ID:
            try:
                copAmazon()
                message = client.messages \
                    .create(
                        body='Success!',
                        from_=PHONE_NUMBER_1,
                        to=PHONE_NUMBER_2
                    )
            except:
                message = client.messages \
                    .create(
                        body='Fail! ' + traceback.format_exc(),
                        from_=PHONE_NUMBER_1,
                        to=PHONE_NUMBER_2
                    )

myStreamListener = MyStreamListener()
myStream = tweepy.Stream(auth = api.auth, listener=myStreamListener)
myStream.filter(follow=[TWITTER_ID])

I am getting the following error: "selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {"method":"xpath","selector":"//span[@id='placeYourOrder']//input[@name='placeYourOrder1']"} (Session info: headless chrome=91.0.4472.164)"

Basically, Selenium is finding the element fine when I run the code locally, but when the code is run on a Heroku server, Selenium is not able to find the element. Why is this? I'm pretty sure I've set up all of the buildpacks properly. Also, in the two code blocks above, ACCOUNT_SID, AUTH_TOKEN, PHONE_NUMBER_1, PHONE_NUMBER_2, CONSUMER_KEY, CONSUMER_SECRET, ACCESS_TOKEN, ACCESS_TOKEN_SECRET, EMAIL, PASSWORD, and TWITTER_ID are all the proper values (the macros are just for privacy purposes). Any ideas? Thanks!

1 Answers

So I figured out why this is happening. I just noticed that every time the script is run on the Heroku server, I get a text from Amazon saying that there was a "sign-in attempt from VA, US" (which is where the Heroku server is located), which means that I have to approve it before the Selenium ChromeDriver can continue. That's why the ChromeDriver is unable to find the "place your order" button right after the sign-in occurs. I am going to try to find a way to have Amazon stop this validation process, so that the ChromeDriver doesn't stop after the sign-in and can then find the "place your order" button.

Related