find_element_by_* commands are deprecated in Selenium
Asked Answered
R

4

92

When starting the function

def run(driver_path):
    driver = webdriver.Chrome(executable_path=driver_path)
    driver.get('https://tproger.ru/quiz/real-programmer/')
    button = driver.find_element_by_class_name("quiz_button")
    button.click()
run(driver_path)

I'm getting errors like these:

<ipython-input-27-c5a7960e105f>:6: DeprecationWarning: executable_path has been deprecated, please pass in a Service object
  driver = webdriver.Chrome(executable_path=driver_path)
<ipython-input-27-c5a7960e105f>:10: DeprecationWarning: find_element_by_* commands are deprecated. Please use find_element() instead
  button = driver.find_element_by_class_name("quiz_button")

... but I can't understand why.

I'm using WebDriver at the latest version for my Chrome's version. I don't why I get

find_element_by_* commands are deprecated

... when it's in the documentation that the command exists.

Raimes answered 7/11, 2021 at 17:53 Comment(1)
Try checking this one. Matches your query. #61309299Disloyal
D
204

This error message...

DeprecationWarning: find_element_by_* commands are deprecated. Please use find_element() instead

...implies that the find_element_by_* commands are deprecated in the latest Selenium Python libraries.

As AutomatedTester mentions: This DeprecationWarning was the reflection of the changes made with respect to the decision to simplify the APIs across the languages and this does that.


Solution

Instead you have to use find_element(). As an example:

You have to include the following imports

from selenium.webdriver.common.by import By
  • Using class_name:

    button = driver.find_element_by_class_name("quiz_button")
    

    Needs be replaced with:

    button = driver.find_element(By.CLASS_NAME, "quiz_button")
    

Along the lines of, you also have to change the following:

  • Using id:

    element = find_element_by_id("element_id")
    

    Needs be replaced with:

    element = driver.find_element(By.ID, "element_id")
    
  • Using name:

    element = find_element_by_name("element_name")
    

    Needs be replaced with:

    element = driver.find_element(By.NAME, "element_name")
    
  • Using link_text:

    element = find_element_by_link_text("element_link_text")
    

    Needs be replaced with:

    element = driver.find_element(By.LINK_TEXT, "element_link_text")
    
  • Using partial_link_text:

    element = find_element_by_partial_link_text("element_partial_link_text")
    

    Needs be replaced with:

    element = driver.find_element(By.PARTIAL_LINK_TEXT, "element_partial_link_text")
    
  • Using tag_name:

    element = find_element_by_tag_name("element_tag_name")
    

    Needs be replaced with:

    element = driver.find_element(By.TAG_NAME, "element_tag_name")
    
  • Using css_selector:

    element = find_element_by_css_selector("element_css_selector")
    

    Needs be replaced with:

    element = driver.find_element(By.CSS_SELECTOR, "element_css_selector")
    
  • Using xpath:

    element = find_element_by_xpath("element_xpath")
    

    Needs be replaced with:

    element = driver.find_element(By.XPATH, "element_xpath")
    

Note: If you are searching and replacing to implement the above changes, you will need to do the same thing for find_elements_*, i.e., the plural forms of find_element_*.

You may also find this upgrade guide useful as it covers some other unrelated changes you may need to make when upgrading: Upgrade to Selenium 4

Declassify answered 7/11, 2021 at 19:46 Comment(5)
NameError: name 'By' is not definedClareta
from selenium.webdriver.common.by import ByMichelmichelangelo
This is great, this is alot of the commands in the recent new slightly different syntax. But what i see missing is the "send_keys". also on the Selenium website, they don't have an example yet for the "Send_Keys" but invite anyone to contribute an example. selenium.dev/documentation/webdriver/actions_api/keyboard/… , also if you can put a send_keys example here in your answer . currently i'm attempting the send_keys with driver.find_element(By.ID, 'element_name') example. if you can put that there, that would be great. Thanks,Reinhart
What about this - emailaddress_input = driver.find_elements_by_xpath(x_path)[index], how can I provide index if I replace find_elements_by_xpath with find_element* function.Rohn
Vim users can use this quick-and-dirty substitution to capture all of this: :%s/find_element([s]*)_by_([^(]*)(/find_element\1(By.\U\2, /gMatty
L
10

@DebanjanB mentioned and explained the new structure. Also, it's better use these lines:

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.chrome.service import Service

s = Service('C:/Users/.../chromedriver.exe')
driver = webdriver.Chrome(service=s)
Leavitt answered 9/11, 2021 at 6:1 Comment(4)
What are keys for in this example?Lenard
@Arete, By and Key will be used to detect target and input data! , these lines are the main structure .Leavitt
Why is it better? Please respond by editing (changing) your answer, not here in comments (************** without ************** "Edit:", "Update:", or similar - the answer should appear as if it was written today).Brushwork
Who is DebanjanB? What does it refer to? An answer to this question? A comment to this question? In some other Stack Overflow question? Something else?Brushwork
D
4

As others mentioned, you should use find_element() or find_elements() instead of find_element_by_*() or find_elements_by_*().

I wrote the regex pattern to replace the deprecated methods to new ones, so try this if you need.

# from - e.g. find_element_by_id("test")

find_element(s?)_by_([a-z]+)\((.*)

# to - e.g. find_element(By.ID, "test")

find_element$1(By.\U$2\E, $3

Note: you need the import line to use the new methods

from selenium.webdriver.common.by import By
Deel answered 5/1, 2022 at 0:57 Comment(2)
Here's a couple handy one liners to run before and after running the regex replace egrep 'find_element(s?)_by_([a-z]+)\((.*)' -R . | grep -v venv | cut -f1 -d: | sort -u | tee -a update-these.txt | xargs -I{} bash -c 'echo -e "from selenium.webdriver.common.by import By\n$(cat {})" > {}' AND to check that the imports were added to the files to update cat update-these.txt | xargs head -n 1Kalimantan
Re "regex pattern to replace the deprecated methods": Applied in what context? A Perl script? In a text editor?Brushwork
R
0

Thank you @Stephen and undetected Selenium for your answers. After some time reading on how where to find an example of send_key, I found an amazing gist of examples.

The send_keys below example worked for me:

browser = webdriver.Chrome()

 

def test_key_down(driver):
    driver.get('https://www.selenium.dev/selenium/web/single_text_input.html?#')

    ActionChains(driver) \
        .send_keys("abc") \
        .perform()

 

test_key_down(browser)

Rickey answered 13/10, 2022 at 11:54 Comment(1)
There isn't anybody here with the name "Stephen". What answer does it refer to?Brushwork

© 2022 - 2024 — McMap. All rights reserved.