How do you use EC.presence_of_element_located((By.ID, myDynamicElement )) except to specify class not ID
The relevant HTML would have helped us to construct a more canonical answer. However to start with your first line of code:
element = WebDriverWait(driver,100).until(EC.presence_of_element_located(
(By.ID, "tabla_evolucion")))
is pretty much legitimate where as the second line of code:
element = WebDriverWait(driver,100).until(EC.presence_of_element_located(
(By.class, "ng-binding ng-scope")))
Will raise an error as:
Message: invalid selector: Compound class names not permitted
as you can't pass multiple classes through By.class
.
You can find a detailed discussion in Invalid selector: Compound class names not permitted using find_element_by_class_name with Webdriver and Python
Solution
You need to take care of a couple of things as follows:
- Without any visibility to your usecase, functionally inducing WebDriverWait in association with EC as
presence_of_element_located()
merely confirms the presence of the element within the DOM Tree. Presumably moving ahead either you need to get the attributes e.g.value
,innerText
, etc or you would interact with the element. So instead ofpresence_of_element_located()
you need to use eithervisibility_of_element_located()
orelement_to_be_clickable()
You can find a detailed discussion in WebDriverWait not working as expected
For an optimum result you can club up the
ID
andCLASS
attributes and you can use either of the following Locator Strategies:Using
CSS_SELECTOR
:
element = WebDriverWait(driver, 20).until(EC.visibility_of_element_located(
(By.CSS_SELECTOR, ".ng-binding.ng-scope#tabla_evolucion")))
- Using
XPATH
:
element = WebDriverWait(driver, 20).until(EC.visibility_of_element_located(
(By.XPATH, "//*[@class='ng-binding ng-scope' and @id='tabla_evolucion']")))
How to locate the email address element with a Facebook page using Selenium
The Email Address field within the webpage contains dynamic elements.
To locate the Email Address field instead of presence_of_element_located() you need to induce WebDriverWait for the visibility_of_element_located() and you can use either of the following locator strategies:
Using XPATH and the text
@
:print(WebDriverWait(driver, 20).until(EC.visibility_of_element_located((By.XPATH, "//span[contains(., '@')]"))).text)
Using XPATH and the texts
@
&com
:print(WebDriverWait(driver, 20).until(EC.visibility_of_element_located((By.XPATH, "//span[contains(., '@') and contains(., 'com')]"))).text)
Note : You have to add the following imports :
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
How to scrape the Current Holdings table
To scrape the data from the current holdings_table as the <table>
is present with the HTML DOM but not visible within the webpage, you need to induce WebDriverWait for the presence_of_element_located() for the <table>
element, extract the outerHTML, read the outerHTML using read_html()
and you can use the following locator strategy:
Code Block:
driver.execute("get", {'url': 'https://whalewisdom.com/filer/berkshire-hathaway-inc#tabholdings_tab_link'})
# data = driver.find_element(By.CSS_SELECTOR, "table#current_holdings_table").get_attribute("outerHTML")
data = WebDriverWait(driver, 20).until(EC.presence_of_element_located((By.CSS_SELECTOR, "table#current_holdings_table"))).get_attribute("outerHTML")
df = pd.read_html(data)
print(df)Console Output:
[ Stock Unnamed: 1 Sector ... Source Source Date Date Reported
0 AAPL NaN INFORMATION TECHNOLOGY ... 13F 2022-03-31 2022-05-16
1 BAC NaN FINANCE ... 13F 2022-03-31 2022-05-16
2 AXP NaN FINANCE ... 13F 2022-03-31 2022-05-16
3 CVX NaN ENERGY ... 13F 2022-03-31 2022-05-16
4 KO NaN CONSUMER STAPLES ... 13F 2022-03-31 2022-05-16
5 OXY NaN ENERGY ... 4 2022-05-02 2022-05-04
6 KHC NaN CONSUMER STAPLES ... 13F 2022-03-31 2022-05-16
7 MCO NaN FINANCE ... 13F 2022-03-31 2022-05-16
8 USB NaN FINANCE ... 13F 2022-03-31 2022-05-16
9 ATVI NaN INFORMATION TECHNOLOGY ... 13F 2022-03-31 2022-05-16
10 HPQ NaN INFORMATION TECHNOLOGY ... 13G 2022-04-30 2022-04-30
11 BK NaN FINANCE ... 13F 2022-03-31 2022-05-16
12 KR NaN CONSUMER STAPLES ... 13F 2022-03-31 2022-05-16
13 DVA NaN HEALTH CARE ... 13D 2022-08-01 2022-08-01
14 C NaN FINANCE ... 13F 2022-03-31 2022-05-16
15 VRSN NaN COMMUNICATIONS ... 13F 2022-03-31 2022-05-16
16 GM NaN CONSUMER DISCRETIONARY ... 13F 2022-03-31 2022-05-16
17 PARA NaN COMMUNICATIONS ... 13F 2022-03-31 2022-05-16
18 CHTR NaN COMMUNICATIONS ... 13F 2022-03-31 2022-05-16
19 LSXMK NaN COMMUNICATIONS ... 13F 2022-03-31 2022-05-16
20 V NaN FINANCE ... 13F 2022-03-31 2022-05-16
21 AMZN NaN CONSUMER DISCRETIONARY ... 13F 2022-03-31 2022-05-16
22 AON NaN FINANCE ... 13F 2022-03-31 2022-05-16
23 MA NaN FINANCE ... 13F 2022-03-31 2022-05-16
24 SNOW NaN INFORMATION TECHNOLOGY ... 13F 2022-03-31 2022-05-16
__init__() takes 2 positional arguments but 3 were given trying to wait for an element using presence_of_element_located()
You need to take care of a couple of things:
presence_of_element_located()
should be called within atuple
as it is not a function but a class, where the initializer expects just 1 argument beyond the implicit selfpresence_of_element_located()
doesn't ensures that the element is interactable. Instead you need to useelement_to_be_clickable()
Solution
You need to induce WebDriverWait for the element_to_be_clickable()
and you can use the following Locator Strategy:
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//*[@id='menu-item-9145']/a"))).click()
Note: You have to add the following imports :
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
Reference
You can find a couple of relevant detailed discussions in:
- init() takes 2 positional arguments but 3 were given using WebDriverWait and expected_conditions as element_to_be_clickable with Selenium Python
How to find the product name and price using the python scraper?
It appears that website will automatically redirect visitor according to the country determined from visitor's IP, and it will also change the classes for item name and price accordingly. Here is a more robust solution, which will account for such changes, and will also wait for the element to load in page:
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
chrome_options = Options()
chrome_options.add_argument("--no-sandbox")
webdriver_service = Service("chromedriver/chromedriver") ## path to where you saved chromedriver binary
browser = webdriver.Chrome(service=webdriver_service, options=chrome_options)
url='https://www.neimanmarcus.com/en-jp/p/givenchy-g-chain-ring-prod250190244?childItemId=NMY5X1R_&navpath=cat000000_cat4870731_cat50910737_cat2650734&page=0&position=11'
browser.get(url)
try:
WebDriverWait(browser, 20).until(EC.element_to_be_clickable((By.ID, "closeButton"))).click()
except Exception as e:
print('no pop-up, moving on')
title = WebDriverWait(browser, 20).until(EC.element_to_be_clickable((By.XPATH, "//span[@data-test='pdp-title']")))
price = WebDriverWait(browser, 20).until(EC.element_to_be_clickable((By.XPATH, "//div[@data-test='pdp-pricing']")))
print(title.text.strip(), price.text.strip())
Result:
G-Chain Ring JPY 46709
Which expected_conditions to use?
As you are not expanding the items and sublist being invisible you are invoking click() on multiple buttons, WebDriverWait for visibility_of_element_located() and element_to_be_clickable() will always fail.
Solution
In such cases, your best bet would be to induce WebDriverWait for the presence_of_element_located() as follows:
element = WebDriverWait(driver, 20).until(expected_conditions.presence_of_element_located((By.XPATH, "element_xpath']")))
driver.execute_script(""arguments[0].click();", element)
In a single line:
driver.execute_script(""arguments[0].click();", WebDriverWait(driver, 20).until(expected_conditions.presence_of_element_located((By.XPATH, "element_xpath']"))))
Another JavaScript based alternative would be:
driver.execute_script("document.getElementsByClassName('theClassName')[0].click()")
Related Topics
Can't Start Foreman in Heroku Tutorial Using Python
Does Python Do Variable Interpolation Similar to "String #{Var}" in Ruby
How to Open (Read-Write) or Create a File with Truncation Allowed
Request Uac Elevation from Within a Python Script
Instance Variables VS. Class Variables in Python
Apply Function to Each Element of a List
Integer Division in Python 2 and Python 3
Getting an "Invalid Syntax" When Trying to Perform String Interpolation
How to Subtract a Day from a Date
Which Is the Preferred Way to Concatenate a String in Python
Differencebetween "Is None" and "== None"
How to Redirect the Stdout into Some Sort of String Buffer
How to Run Script with Elevated Privilege on Windows
Select Iframe Using Python + Selenium
Match a Whole Word in a String Using Dynamic Regex