“TypeError: 'str' object is not callable” using WebDriverWait for link_text in Selenium through Python

夙愿已清 提交于 2021-01-28 19:04:32

问题


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:

  1. 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.

  2. 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; both print(WebDriverWait(driver, 12).until("Mehr erfahren").click()) and print(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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!