I am using action chain to drop down in selenium webdriver, here is my code, can anyone help me to figure out what's wrong. I'm not using the page object pattern this time, so there is no "self" argument here.
from selenium import webdriver
from behave import given, when, then
from selenium.webdriver.common.by import By
from selenium.webdriver import ActionChains
#given('Open RF page')
def open_website(context):
context.driver.get('https://www.raymourflanigan.com/')
#when('Select Living Room')
def select_living_room(context):
driver = webdriver.Chrome()
actions = ActionChains(driver)
menu = context.driver.find_element(By.XPATH, "//*[#id='Container']/div[1]/div[3]/div[1]/a")
sofa = context.driver.find_element(By.XPATH, "//*[#id='Container']/div[1]/div[3]/div[1]/div/div[1]/ul/li[2]/a")
actions.move_to_element(menu).move_to_element(sofa).click()
#then("Verify {product} are available")
def verify(context, product):
result = context.driver.find_element(By.CSS_SELECTOR, "h1.Category_Bnr_Title").text
assert 'Sofas & Couches' in result, f"Expected text is: {result}."
Also, I removed perform(), because for some reason the second function isn't working with perform() in it. Seems like it does not work properly without it either, so if anyone knows why and can help me, it'll be great! I am just learning) Thank you in advance!
There are a few problems, but nothing too big. Seems all changes need to be done in select_living_room.
select_living_room is taking a context object in it's arguments, but then the first thing it does is create a whole new webDriver. But then it accesses a completely different webDriver that is a member of context. I am guessing you are trying to do one of these:
accept context, which has a driver already included. If that is the case, get rid of this: driver = webdriver.Chrome()
create a new driver as an attribute of context. In that case, change to this: context.driver = webdriver.Chrome()
In either case, I don't see anywhere where get is being called on the driver to open the page. In select_living_room it is necesary to call open_website.
The ActionChain is not running. Need to add a perform() call on the end.
I change select_living_room to work like this (assumes that the webDriver is already set up inside of context):
#when('Select Living Room')
def select_living_room(context):
open_website(context)
menu = context.driver.find_element(By.XPATH, "//*[#id='Container']/div[1]/div[3]/div[1]/a")
sofa = context.driver.find_element(By.XPATH, "//*[#id='Container']/div[1]/div[3]/div[1]/div/div[1]/ul/li[2]/a")
actions = ActionChains(context.driver)
actions.move_to_element(menu).move_to_element(sofa).click().perform()
Then running like this works:
opts = webdriver.ChromeOptions()
ctx = Context(webdriver.Chrome('path/to/chromedriver', options=opts))
select_living_room(ctx)
verify(ctx, None)
Note that you don't mention what Context is. I stubbed it out:
class Context:
def __init__(self, ctx):
self.driver = ctx
Related
I got a Python Selenium project that does what I want (yay!) but for every instance it opens a new browser window. Is there any way to prevent that?
I've went through the documentation of Selenium but they refer to driver.get(url). It's most likely because it's in the for...loop but I can't seem to get the URL to change with the queries and params if it's outside of the for...loop.
So, for example, I want to open these URLs:
https://www.google.com/search?q=site%3AParameter1+%22Query1%22
https://www.google.com/search?q=site%3AParameter2+%22Query1%22
https://www.google.com/search?q=site%3AParameter3+%22Query1%22
etc..
from selenium import webdriver
import time
from itertools import product
params = ['Parameter1', 'Parameter2', 'Parameter3', 'Parameter4']
queries = ['Query1', 'Query2', 'Query3', 'Query4',]
for (param, query) in product(params,queries):
url = f'https://www.google.com/search?q=site%3A{param}+%22{query}%22' # google as an example
driver = webdriver.Chrome('G:/Python Projects/venv/Lib/site-packages/chromedriver.exe')
driver.get(url)
#does stuff
You are declaring your path to Chrome in the loop. Declare it once and reuse:
from itertools import product
from selenium import webdriver
params = ['Parameter1', 'Parameter2', 'Parameter3', 'Parameter4']
queries = ['Query1', 'Query2', 'Query3', 'Query4',]
driver = webdriver.Chrome(executable_path='/snap/bin/chromium.chromedriver')
for (param, query) in product(params,queries):
url = f'https://www.google.com/search?q=site%3A{param}+%22{query}%22'
driver.get(url)
# driver.close()
As title,
I want to practice encapsulation of programing, and I have a problem about the code I write.
The browser always automatically opens when I call the class(CrawlerSetting), and I guess which code causes the situation (browser = wb.Chrome(options=options)), but I have no idea how to avoid this situation.
Here is my code:
from selenium import webdriver as wb
class CrawlerSetting:
'''
Description:
chrome 84 version
'''
options = wb.ChromeOptions()
options.add_experimental_option('excludeSwitches', ["enable-automation"])
global browser
browser = wb.Chrome(options=options)
def __init__(self, target):
self.target = target
def open(self):
return browser.get(self.target)
def click_xpath(self, x_path):
submit_element = browser.find_element_by_xpath(x_path)
return submit_element.click()
It's my first time to ask question, if I have any format error . Plz tell me!
I have been trying for the past couple of days to select a dropdown and at least print out the options available, but I just cannot get it to work.
I am getting the this error when I run the module.
Traceback (most recent call last):
File "sel_test_elements2.py", line 20, in
print ([o.text for o in select_element.options])
AttributeError: 'FirefoxWebElement' object has no attribute 'options'
Currently my code looks like this.
from selenium.webdriver.support.ui import Select
from selenium.webdriver.common.by import By
# Define Global Variables
url = "https://games.pcaha.ca/teams/4329"
csv_file = "game_schedule_4329.csv"
games = []
# create a new Firefox session
driver = webdriver.Firefox()
driver.get(url)
driver.implicitly_wait(30)
# Locate the Sector and create a Select object
select_element = driver.find_element_by_css_selector(".team-filters")
# this will print out strings available for selection on select_element, used in visible text below
print ([o.text for o in select_element.options])```
The issue you face is the fact that this website is using react and doesn't use default Select and Options. They have a custom dropdown implemented, so the way to interact with it is the same as interaction with regular web elements, Select and Options won't work in this case.
I modified your code and it works for me in Chrome:
from selenium.webdriver import Chrome
from time import sleep
# Define Global Variables
url = "https://games.pcaha.ca/teams/4329"
csv_file = "game_schedule_4329.csv"
games = []
# create a new Chrome session
driver = Chrome()
driver.get(url)
driver.implicitly_wait(30)
sleep(3) # make sure svgs load before interaction
# Click on arrow down
arrow = driver.find_elements_by_css_selector(".team-filters svg")[1].click()
# Collect options
options = driver.find_elements_by_xpath("//div[contains(#id, 'react-select-2')]")
# Print text from options
print([o.text for o in options])
Note: when manually opening the dropdown in your browser and trying to use web inspector, it closes, so in order to get the html inside a dropdown, you can use something like:
dropdown = driver.find_element_by_css_selector("div.css-kj6f9i-menu")
dropdown_html = dropdown.get_attribute('innerHTML')
I hope it helped. Good luck!
I have used something similar in a small script i have written, may be it can give you an hint on how to go about
Approach 1 This is to select the last of the options available
Variable options in the code below gets be the option available for the dropdown
select_datebox = driver.find_element_by_id('jrnyDateSrchTxt') # Drop down selection, you have to change the id appropriately
select_datebox.click()
time.sleep(2)
options = select_datebox.find_elements_by_tag_name('option')
options[len(options)-1].click() #selecting the last option
Approach 1 entering the option via a variable
select = Select(driver.find_element_by_id("jrnyDateSrchTxt")) # Drop down selection, you have to change the id appropriately
time.sleep(1)
select.select_by_value(datadate) # Date selection
time.sleep(2)
Set-up
I use selenium for a variety of things and found myself defining the same functions over and over again.
I decided to define the functions in a separate file, and import these to my work files.
Simple Example
If I define functions and execute all in one file, things work fine. See the simple full_script.py below,
# import webdriver
from selenium import webdriver
# create browser
browser = webdriver.Firefox(
executable_path='/mypath/geckodriver')
# define short xpath function
def el_xp(x):
return browser.find_element_by_xpath(x)
# navigate to url
browser.get('https://nos.nl')
# obtain title first article
el_xp('/html/body/main/section[1]/div/ul/li[1]/a/div[2]/h3').text
This successfully returns the title of the first article on this news website.
Problem
Now, when I split the script in a xpath_function.py and a run_text.py, and save them in a test folder on my desktop, things don't work fine.
xpath_function.py
# import webdriver
from selenium import webdriver
# create browser
browser = webdriver.Firefox(
executable_path='/mypath/geckodriver')
# define short xpath function
def el_xp(x):
return browser.find_element_by_xpath(x)
run_test.py
import os
os.chdir('/my/Desktop/test')
import xpath_function as xf
# import webdriver
from selenium import webdriver
# create browser
browser = webdriver.Firefox(
executable_path='/Users/lucaspanjaard/Documents/RentIndicator/geckodriver')
browser.get('https://nos.nl')
xf.el_xp('/html/body/main/section[1]/div/ul/li[1]/a/div[2]/h3').text
Executing run_test.py results in 2 browsers opened, of which one navigates to the news website and the following error,
NoSuchElementException: Unable to locate element:
/html/body/main/section[1]/div/ul/li[1]/a/div[2]/h3
I suppose the issue is that in both xpath_function.py and run_test.py I'm defining a browser.
However, if I don't define a browser in xpath_function.py, I get an error in that file that no browser is defined.
How do I solve this?
You can easily fix it by changing the definition of el_exp to include the browser as an extra parameter:
def el_xp(browser, x):
return browser.find_element_by_xpath(x)
now in run_test.py you call it like this:
xf.el_xp(browser, '/html/body/main/section[1]/div/ul/li[1]/a/div[2]/h3').text
I'm working on making an automated web scraper run on Khan Academy to make offline backups of questions using selenium and a python scraper (to come later). I'm currently working on getting it to answer questions (right or wrong doesn't matter) to proceed through exercises. Unfortunately, selenium's .click() function doesn't actually select an answer. I think it has something to do with being pointed at the wrong object but I can't tell. It currently highlights the option, but doesn't select it.
HTML for a single option (out of 4)
I made some code to reproduce the error, and hooked it up to a test account for all your debugging needs. Thanks.
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
driver = webdriver.Firefox()
# gets us to the SAT Math Exercise page
driver.get('https://www.khanacademy.org/mission/sat/tasks/5505307403747328')
# these next lines just automate logging in. Nothing special.
login = driver.find_element_by_name('identifier')
login.send_keys('stackflowtest') # look, I made a new account just for you guys
passw = driver.find_element_by_name('password')
passw.send_keys('stackoverflow')
button = driver.find_elements_by_xpath("//*[contains(text(), 'Sign in')]")
button[1].click()
driver.implicitly_wait(5) # wait for things to become visible
radio = driver.find_element_by_class_name('perseus-radio-option')
radio.click()
check = driver.find_element_by_xpath("//*[contains(text(), 'Check answer')]")
check.click()
After a trial and error process, I found that the actual click selection can be accomplished by pointing to the element with class "description"
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
driver = webdriver.Firefox()
# gets us to the SAT Math Exercise page
driver.get('https://www.khanacademy.org/mission/sat/tasks/5505307403747328')
# these next lines just automate logging in. Nothing special.
login = driver.find_element_by_name('identifier')
login.send_keys('stackflowtest') # look, I made a new account just for you guys
passw = driver.find_element_by_name('password')
passw.send_keys('stackoverflow')
button = driver.find_elements_by_xpath("//*[contains(text(), 'Sign in')]")
button[1].click()
driver.implicitly_wait(5) # wait for things to become visible
radio = driver.find_element_by_class_name('description')
radio.click()
check = driver.find_element_by_xpath("//*[contains(text(), 'Check answer')]")
check.click()
For people dealing with similar issues, I would recommend clicking on the very edge of the space that allows you to select and inspecting the element there. This prevents you from accidentally using one of the innermost tags.