Selenium find element by class breaking code - python

My program checks a login page for available combinations. Upon first opening up the page, there is a "check availability" button, which has an ID which Selenium is able to find/use to click.
If the username is taken, a new button pops up which says "check another combination", however the DOM inspector only gives the following information about the second button:
<a class="btn btn-outline-primary btn-block mt-4" href="" role="button" data-ng-click="combination.reset()">
Check another combination
</a>
I have tried finding this button by CLASS, CLASSNAME, copying and pasting the XPATH from the inspector and all these have lead to not only the button clicking not working, but the entering and submitting of the intial combination also ceasing to work.
Hoping someone can suggest how to identify this button from the given information. For reference, here is one of the lines I tried:
check_another_combo_button = driver.find_element(By.CLASS, "btn btn-outline-primary btn-block mt-4")
Here is my full code:
from selenium import webdriver
from selenium.webdriver.common.by import By
from webdriver_manager.firefox import GeckoDriverManager
import time
driver = webdriver.Firefox(executable_path=GeckoDriverManager().install())
driver.maximize_window()
site = "https://www......"
driver.get(site)
combination_input_field = driver.find_element(By.ID, "userCombination")
check_availability_button = driver.find_element(By.ID, "btn_fQPAC_submit")
combination_input_field.send_keys(77777) #77777 is one of the unavailable combos
check_availability_button.click()
time.sleep(2)
check_another_combo_button = driver.find_element(By.CLASS_NAME, "btn btn-outline-primary btn-block mt-4")
check_another_combo_button.click()

I suspect you want to check for inputs say inputs in a loop. Here is the solution using both chrome and firefox.
Solution using chrome driver :
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
chrome_path = r"C:\Users\hpoddar\Desktop\Tools\chromedriver_win32\chromedriver.exe"
s = Service(chrome_path)
url = 'https://www......'
driver = webdriver.Chrome(service=s)
driver.get(url)
inputs = ['77777', '88888', '99999', '11111']
for plate in inputs:
combination_input_field = driver.find_element(By.ID, "qPlateCombination")
check_availability_button = driver.find_element(By.ID, "btn_fQPAC_submit")
combination_input_field.send_keys(plate)
check_availability_button.click()
element = WebDriverWait(driver, 10).until(EC.visibility_of_element_located((By.CSS_SELECTOR, ".btn.btn-outline-primary.btn-block.mt-4")))
check_another_combo_button = driver.find_element(By.CSS_SELECTOR, ".btn.btn-outline-primary.btn-block.mt-4")
check_another_combo_button.click()
Solution using Geckodriver :
To use Geckodriver, all you need to add is
from webdriver_manager.firefox import GeckoDriverManager
from selenium.webdriver.chrome.service import Service
and change driver initialization line to
s = Service(executable_path=GeckoDriverManager().install())
webdriver.Firefox(service=s)
driver.maximize_window()

when you have common classes or dynamically generated classes for elements you wish to interact, the next approach is to be fixed by text.
Try with xpath, that matches the text:
//a[normalize-space(.)='Check another combination']
normalize-space(.) - will trim the whitespace and match the text inside the element.
Yu can include #role="button" as additional matcher inside the a tag.

Related

Message: element not interactable Python send keys

I'm trying to send keys to the Youtube search box with Selenium, I've tried search ID and Xpath and consistently get errors. These errors include "Message: element not interactable", where am I going wrong?
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
PATH = "C:\Program Files (x86)\chromedriver.exe"
driver = webdriver.Chrome(PATH)
driver.get("https://youtube.com")
searchbox = driver.find_element("xpath", '//*[#id="search-input"]')
searchbox.send_keys('Jack West')
There are two problems:
First:
Your xpath gives <div> but you can't send keys to <div>
You have to get <input> which is inside <div>
'//*[#id="search-input"]//input'
And later it needs to click button to start searching.
Second:
When I run code browser displays popup window and asks to accept cookies, etc. And this popup blocks access to search field. It needs to add code which will accept it.
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from webdriver_manager.chrome import ChromeDriverManager
#from webdriver_manager.firefox import GeckoDriverManager
import time
driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()))
#driver = webdriver.Firefox(service=Service(GeckoDriverManager().install()))
driver.get("https://youtube.com")
time.sleep(5)
print('cookies')
cookies = driver.find_elements(By.XPATH, '//div[contains(#class,"eom-button-row")]//a')
cookies[1].click()
time.sleep(5)
print('searchbox')
searchbox = driver.find_element(By.XPATH, '//*[#id="search-input"]//input')
searchbox.send_keys('Jack West')
print('searchbox button')
searchbox_button = driver.find_element(By.XPATH, '//button[#id="search-icon-legacy"]')
searchbox_button.click()
But it could be simpler to use url
https://www.youtube.com/results?search_query=Jack+West
and it doesn't need to click any keys or buttons.
YouTube has API for developers/programmers and this should be preferred method.

Web scraping- Accept Cookies- SELENIUM - PYTHON - AIRBNB

I am trying to accept the cookies in airbnb home page. But I can't find the "key" to get it.
Find below my code:
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.by import By
from time import sleep
options = Options()
# options.add_argument('--headless')
options.add_argument('window-size=400,800')
navegador = webdriver.Chrome(options=options)
navegador.get('https://www.airbnb.com/')
# I tried this 02 ways
WebDriverWait(navegador, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, ""))).click()
WebDriverWait(navegador, 10).until(EC.element_to_be_clickable((By.XPATH, ""))).click()
Find below the HTML from Airbnb
<button class="optanon-allow-all accept-cookies-button" title="OK" aria-label="OK" onclick="Optanon.TriggerGoogleAnalyticsEvent('OneTrust Cookie Consent', 'Banner Accept Cookies');" tabindex="1">OK</button>
from my end I could see this HTML in airbnb :
<button data-testid="accept-btn" type="button" class="_1xiwgrva">OK</button>
you can click on the accept cookies button like this :
WebDriverWait(navegador, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "button[data-testid='accept-btn']"))).click()
But I see, you have shared this html :-
<button class="optanon-allow-all accept-cookies-button" title="OK" aria-label="OK" onclick="Optanon.TriggerGoogleAnalyticsEvent('OneTrust Cookie Consent', 'Banner Accept Cookies');" tabindex="1">OK</button>
in this case, you could use the below code :
WebDriverWait(navegador, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "button.optanon-allow-all.accept-cookies-button"))).click()
Try this:
WebDriverWait(navegador, 10).until(EC.visibility_of_element_located((By.CSS_SELECTOR, "button.accept-cookies-button"))).click()
Also, I don't understand why are you defining so small screen size?
We are normally use
options.add_argument('--window-size=1920,1080')
Also, it should be -- there as I used here

I'm trying to use the <button class= instead of using the whole XPATH as the id: changes on each product

from selenium import webdriver
import time
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver import ActionChains
PATH = "C:\Program Files (x86)\chromedriver.exe"
driver = webdriver.Chrome(PATH)
driver.maximize_window()
driver.get("https://accounts.ebuyer.com/customer/account/index.html?action=bG9naW4=")
title = driver.find_element_by_name("email")
title.clear()
title.send_keys("johnsmith#gmail.com")
password = driver.find_element_by_id("password")
password.send_keys("pass123")
driver.find_element_by_xpath('//*[#id="login"]/div[4]/input').click()
driver.find_element_by_xpath('/html/body/div[3]/div/button[2]').click()
#accepts cookies
driver.get("https://www.ebuyer.com/search?q=graphics+cards")
WebDriverWait(driver, 10)
try:
element = WebDriverWait(driver, 5).until(
EC.presence_of_element_located((By.XPATH,'//*[#id="grid-view"]/div[1]/div[4]/button'))
) #finds add to basket button
element.click()
driver.find_element_by_xpath('/html/body/header/div/div[3]/div/a[1]').click()
print("IN BASKET")
#adds to basket if found
except:
element = WebDriverWait(driver, 5).until(
EC.presence_of_element_located((By.XPATH,'//*[#id="main-
content"]/div/div[1]/div[2]/div[2]/div/div[2]/ul/li[2]/a'))
)
element.click()
#moves to next page
this is what I'm trying to click but the id changes on each product grid.
<button class="button button--mini-basket button--small js-add-to-mini-basket" data-product-
id="798879" data-ajax-basket-url="https://orders.ebuyer.com/customer/products/index.html?
action=YWpheF9jYXJ0X2FkZF9pdGVt" data-analytics-event="click" data-event-category="Search Listings - Grid" data-event-action="Product Click" data-event-label="Add to Basket Button">Add to
Basket</button>
I want to take <button class="button button--mini-basket button--small js-add-to-mini-basket" and
use this instead of By.XPATH,'//*[#id="grid-view"]/div[1]/div[4]/button'
I'm trying to scan the full page to find the Add to Basket Button and if it can't find that then it
will move on to the next page and repeat until it is found.
I have just built my first pc and I cannot get a graphics card anywhere so I want to use this grab
one.
I've recently found a love for coding so I'm quite new to this, I hope I've explained myself properly
and any help would be appreciated.
Use following xpath to identify. Use element_to_be_clickable() instead presence_of_element_located()
element =WebDriverWait(driver, 5).until(EC.element_to_be_clickable((By.XPATH,"//button[text()='Add to Basket']"))
Try following xpath
//button[#class='button button--mini-basket button--small js-add-to-mini-basket' and contains(text(),'Add to Basket')]

How can we click on the links after new page reload using python?

Basically I want to automate google search engine which basically search and click on the first link that is populated after search button is clicked so i am using python do this. i am successfully able to search the things but not able to click on the link after page reload
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
url = "https://www.google.com"
driver = webdriver.Chrome("C:/Users/User/Python/AllCodes/chromedriver.exe")
driver.get(url)
insert = driver.find_element_by_name("q")
insert.send_keys("K.J.Somaiya")
button = driver.find_element_by_name("btnK")
button.submit()
# after this new page reload and link are poluated
linktext = driver.find_element_by_link_text("K. J. Somaiya Institute of Management")
linktext.submit()
This input class i used name which is q
<input class="gLFyf gsfi" jsaction="paste:puy29d;" maxlength="2048" name="q" type="text" aria-autocomplete="both" aria-haspopup="false" autocapitalize="off" autocomplete="off" autocorrect="off" autofocus="" role="combobox" spellcheck="false" title="Search" value="" aria-label="Search" data-ved="0ahUKEwj9qOfEmLzvAhWSj-YKHZUYDngQ39UDCAQ">
This the html code from i target linktext which is K.J.Somaiya Inst.....
you need to wait until that element becomes visible in dom. Read about selenium waits here
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
url = "https://www.google.com"
driver = webdriver.Chrome("C:/Users/User/Python/AllCodes/chromedriver.exe")
driver.get(url)
insert = driver.find_element_by_name("q")
insert.send_keys("K.J.Somaiya")
button = driver.find_element_by_name("btnK")
button.submit()
# after this new page reload and link are poluated
linktext = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.PARTIAL_LINK_TEXT, "K. J. Somaiya"))
) # Waits 10 second before element loads.
linktext.click()

selenium.common.exceptions.NoSuchElementException: Message: {"errorMessage":"Unable to find element with id 'search-facet-city'"

I am trying to scrape the following website using Python 3, Selenium, and PhantomJS:
https://health.usnews.com/best-hospitals/search
I need to locate a search field and enter text into it, and then press enter to generate the search results. Below is the HTML that corresponds to the search field I am trying to locate:
<div class="search-field-view">
<div class="block-tight">
<label class="" for="search-facet-city">
<input id="search-facet-city" autocomplete="off" name="city"
type="text" data-field-type="text" placeholder="City, State or ZIP"
value="" />
</label>
</div>
</div>
Below is my Python 3 code that attempts to locate this search field using the id "search-facet-city."
def scrape(self):
url = 'https://health.usnews.com/best-hospitals/search'
location = 'Massachusetts'
# Instantiate the driver
driver = webdriver.PhantomJS()
driver.get(url)
driver.maximize_window()
driver.implicitly_wait(10)
elem = driver.find_element_by_id("search-facet-city")
elem.send_keys(self.location)
driver.close()
I need to scrape some results from the page once the text is entered into the search field. However, I keep getting a NoSuchElementException error; it is not able to locate the search box element despite the fact that it exists. How can I fix this?
I tried this with Chrome:
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
from selenium.webdriver.common.keys import Keys
url = 'https://health.usnews.com/best-hospitals/search'
location = 'Massachusetts'
# Instantiate the driver
driver = webdriver.Chrome(executable_path=r'/pathTo/chromedriver')
#driver = webdriver.PhantomJS(executable_path=r'/pathTo/phantomjs')
driver.get(url)
driver.maximize_window()
wait = WebDriverWait(driver, 20)
driver.save_screenshot('out.png');
elem=wait.until(EC.element_to_be_clickable((By.XPATH,"//div[#class='search-field-view']")))
span = elem.find_element_by_xpath("//span[#class='twitter-typeahead']")
input=span.find_element_by_xpath("//input[#class='tt-input' and #name='city']");
input.send_keys(location)
driver.save_screenshot('out2.png');
and it works.
But if I try with phantomJS, in driver.save_screenshot('out.png'); I obtain:
As #JonhGordon said in the comments, the website make some checks. If you want to use phantomJS, you could try to change the desired_capabilities or the service_args.

Categories

Resources