问题
This is my first post on Stack Overflow. I have been browsing and searching for every possible answer to this question on SO, and I figured at this point I should just ask a question, as I have been at this wall for days now. I am currently working on a web scraping project with Selenium in Python. I have already scraped one website and am currently on the second, and I have run into a seemingly intractable issue. The following code works perfectly fine with no errors on the page https://www.spd.de/standpunkte/:
try:
driver.find_element_by_link_text("Familien").click()
except NoSuchElementException:
WebDriverWait(driver, 12).until("Familien").click()
Meanwhile, the following code throws the error TypeError: 'str' object is not callable
on the page https://www.spd.de/standpunkte/familie/:
try:
driver.find_element_by_link_text("Mehr erfahren").click()
except NoSuchElementException:
WebDriverWait(driver, 12).until("Mehr erfahren").click()
The error occurs on the line WebDriverWait(driver, 12).until("Mehr erfahren").click()
. Based on my research up to now, I figure the specific issue is that something in this line is being interpreted as a str
object, and is therefore unable to be called. There are, as I see it, two issues:
I don't see any reason for this line to produce the error while the code on top, scraping the same website, but on a different page, works without issue. I checked and made sure there are no hidden elements on the page that are being clicked instead.
I don't know what in the line is being treated as a
str
object. The whole line? Only part of it? If so, which part? Exacerbating this is that I can't really break down the line to see anything about it; bothprint(WebDriverWait(driver, 12).until("Mehr erfahren").click())
andprint(type(WebDriverWait(driver, 12).until("Mehr erfahren").click()))
just end up giving the error. I was able to determine that the.click()
method is not the issue, as I tried setting the line to be equal to a variable, and then interacted with the variable, but that still produced the error on the same line as before; it never even got to the line with the.click()
method.
Is there any way I can determine which part of the line is being interpreted as a str
? Or is that even the issue at all?
This has been driving me crazy, so assistance would be greatly appreciated!
回答1:
Your research was in the right direction.
In your first usecase, the line within try
was successful:
driver.find_element_by_link_text("Familien").click()
So the line within except
was never called:
WebDriverWait(driver, 12).until("Familien").click()
Hence you don't see the error.
In your second use-case, the line within try
wasn't successful:
driver.find_element_by_link_text("Familien").click()
So the line within except
was called:
WebDriverWait(driver, 12).until("Mehr erfahren").click()
which results into the error:
TypeError: 'str' object is not callable
Deep Dive
WebDriverWait is invoked inconjunction with expected_conditions.
You can find a couple of detailed discussions in:
- How to sleep webdriver in python for milliseconds
- WebDriverWait not working as expected
Now, element_to_be_clickable() should be called within a tuple
as it is not a function but a class, where the initializer expects just 1 argument beyond the implicit self:
class element_to_be_clickable(object):
""" An Expectation for checking an element is visible and enabled such that you can click it."""
def __init__(self, locator):
self.locator = locator
def __call__(self, driver):
element = visibility_of_element_located(self.locator)(driver)
if element and element.is_enabled():
return element
else:
return False
So instead of:
WebDriverWait(driver, 12).until("Mehr erfahren").click()
You need to (add an extra parentheses):
WebDriverWait(driver, 12).until((EC.element_to_be_clickable(By.LINK_TEXT, "Mehr erfahren"))).click()
You can find a 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
回答2:
I think I found your problem here. From the source
def until(self, method, message=''):
...
until
takes a method (i.e. something callable). So, when driver.find_element_by_link_text("Mehr erfahren").click()
raises an exception, it will attempt to call ...until("Mehr erfahren")...
. Since until
expects a method it will try to call the string you gave it - raising the error that's been driving you crazy :)
回答3:
I think until expects a conditional (and WebDriverWait waits until that condition is true). You're just passing a string as your argument instead of a condition. You need a condition that checks if that element exists on the page.
回答4:
You can use this css selector: a[href*="familien"]
This can be used for both your URLs.
driver.get('yourURL')
try:
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.CSS_SELECTOR, 'a[href*="familien"]'))).click()
except NoSuchElementException:
# handle if the element not exist
print('element not exist')
See documentation here to know how to use WebDriverWait
来源:https://stackoverflow.com/questions/62946395/typeerror-str-object-is-not-callable-using-webdriverwait-for-link-text-in-s