[python][selenium][web自動化]webdriver的元素定位方式

老常什么都想学發表於2024-09-02

簡單的加個前置知識:

元素定位的方法find_element(),是selenium中WebDriver類的方法。

webdriver.Chrome()這句話,透過WebDriver的構造方法,拿到瀏覽器驅動的物件,然後透過這個物件,就可以呼叫一系列操作瀏覽器的方法。

因為原理就是透過瀏覽器驅動做橋樑實現兩端通訊的。

8種方式:
1、id
2、class_name
3、name
4、link_text
5、partial_link_text
6、tag_name
7、css_selector
8、XPath


我概括下:

1、2、3:元素屬性,不是所有元素都有,還有可能是動態的,通常跟7、8去組合使用比較多。
4、5:是用可點選的連結的文字去定位。
6:是根據元素標籤去定位。
7、8:最常用的方式,能結合前面6種方式組合去定位,我個人覺得理解後並不複雜,並且定位準確。
用什麼定位方式,需要根據實際情況去選擇,才是最合適的,

注意:大家應該都知道網頁F12的開發者工具裡右鍵複製,雖然快捷,但是很多時候並不好用,比如有動態值的時候,你只能手寫,而且它生成的值很長看著臃腫。

下面我用百度搜尋來做demo,直接用程式碼+註釋演示說明,學無止境,大家有什麼看法或細節需要補充的可以告訴我把內容做得更好。


1、id

元素的id屬性定位,id在當前頁面是唯一的,但不是所有元素都有,有些頁面值是動態的

from selenium import webdriver
from selenium.webdriver.common.by import By
from time import sleep


driver = webdriver.Chrome()
driver.maximize_window()
driver.implicitly_wait(10)
driver.get("https://www.baidu.com")

# 操作:輸入框輸入"日曆",點選搜尋
driver.find_element(By.ID, "kw").send_keys("日曆")
driver.find_element(By.ID, "su").click()
sleep(5)
driver.quit()

2、class_name

元素的class屬性定位,大部分都有,但也有些沒有,有些頁面值是動態的

from selenium import webdriver
from selenium.webdriver.common.by import By
from time import sleep


driver = webdriver.Chrome()
driver.maximize_window()
driver.implicitly_wait(10)
driver.get("https://www.baidu.com")

# 操作:輸入框輸入"日曆",點選搜尋,點開年份下拉選單,把年份選擇1903年
driver.find_element(By.CLASS_NAME, "s_ipt").send_keys("日曆")

# 注意這裡:有不少元素有多個class,它們之間會用空格隔開,但是程式碼裡不能用空格,有兩種方式
# 方法一:用.代替,比如:百度的這個搜尋按鈕"bg s_btn",寫成"bg.s_btn"
driver.find_element(By.CLASS_NAME, "bg.s_btn").click()
sleep(2)
# 方法二:使用最後一個class,比如:年份下拉選單的class是:sc-icon cu-icon _toggle-icon_9e3yq_71 toggle-icon_1tMxP,用最後一個
driver.find_element(By.CLASS_NAME, "toggle-icon_1tMxP").click()

# 年份class是"_selectItem_9e3yq_23  ",用網頁F12檢查有152個,要拿到想要的資料:
# 1:在網頁F12的elements視窗搜尋查詢到資料位於152條中的哪個位置,找到後回到程式碼裡用find_elements方法直接加角標獲取
# 2:用下面的方法,用elements獲取所有年份資料再用if判斷我要的年份
elms = driver.find_elements(By.CLASS_NAME, "_selectItem_9e3yq_23  ")
# 先判斷列表是否為空,因為有時候卡頓或者載入慢是可能導致獲取元素失敗的
if elms:
    for e in elms:
        if e.text == "1903年":
            e.click()
            break
            # 這裡做了點選操作後一定要結束迴圈,不然會報異常StaleElementReferenceException。
            # 透過反覆嘗試和根據程式碼流程看,大致就是你迴圈過程中操作了元素,但是還繼續迴圈操作就有可能因為元素髮生變化找不到了,
            #   因為這裡是點開下拉選單然後F12原始碼才會顯示出年份元素,做了點選操作後下拉選單就會隱藏,然後元素也沒了,操作自然報錯。
            # 奇怪的是正常跑沒問題,我自己把for、if、click3行打斷點debug去看,跑到click就怎樣都會出異常,手速點再快也不行。
            # 有大佬懂的話,不介意可以評論區指導下在下。

sleep(5)
driver.quit()

3、name

元素的name屬性定位,也是不是所有都有,有些頁面值是動態的

from selenium import webdriver
from selenium.webdriver.common.by import By
from time import sleep


driver = webdriver.Chrome()
driver.maximize_window()
driver.implicitly_wait(10)
driver.get("https://www.baidu.com")

# 操作:輸入框輸入"日曆"
driver.find_element(By.NAME, "wd").send_keys("日曆")

sleep(5)
driver.quit()

4、link_text

根據可點選的連結的文字去定位

from selenium import webdriver
from selenium.webdriver.common.by import By
from time import sleep


driver = webdriver.Chrome()
driver.maximize_window()
driver.implicitly_wait(10)
driver.get("https://www.baidu.com")

# 操作:點選頁面上的"關於百度"和"更多"
driver.find_element(By.LINK_TEXT, "關於百度").click()
driver.find_element(By.LINK_TEXT, "更多").click()

sleep(5)
driver.quit()

5、partial_link_text

也是根據可點選的連結的文字去定位,但這是文字的模糊匹配,只要包含有關鍵字就可以匹配

from selenium import webdriver
from selenium.webdriver.common.by import By
from time import sleep


driver = webdriver.Chrome()
driver.maximize_window()
driver.implicitly_wait(10)
driver.get("https://www.baidu.com")

# 操作:點選頁面上的"關於百度"和"更多"
driver.find_element(By.PARTIAL_LINK_TEXT, "於百").click()
driver.find_element(By.PARTIAL_LINK_TEXT, "更").click()

sleep(5)
driver.quit()

6、tag_name

根據元素標籤名定位

from selenium import webdriver
from selenium.webdriver.common.by import By
from time import sleep


driver = webdriver.Chrome()
driver.maximize_window()
driver.implicitly_wait(10)
driver.get("https://www.baidu.com")

# 操作:輸入框輸入"日曆"
elem = driver.find_elements(By.TAG_NAME, "input")
for e in elem:
    if e.get_attribute("name") == "wd":
        e.send_keys("日曆")

sleep(5)
driver.quit()

7、css_selector

根據css選擇器定位元素

7.1 常用屬性

from selenium import webdriver
from selenium.webdriver.common.by import By
from time import sleep


driver = webdriver.Chrome()
driver.maximize_window()
driver.implicitly_wait(10)
driver.get("https://www.baidu.com")

# 一:先看常用的屬性格式寫法,下面操作:輸入“日曆”,點選搜尋,等待3秒,在日曆上點選上個月,輸入"1993"
# html標籤:頁面上一般都有多個相同標籤,所以需要再加上父級標籤指明是哪個標籤下的,父級標籤也有多個就再往上找父級,如此類推
driver.find_element(By.CSS_SELECTOR, "span>input").send_keys("日")
# name:[屬性名],例:[name='wd']
driver.find_element(By.CSS_SELECTOR, "[name='wd']").send_keys("歷")
# id:#id,例:#su
driver.find_element(By.CSS_SELECTOR, "#su").click()
sleep(3)
# class:.class,例:".calendar-prev-month_mlSD9 OP_LOG_BTN"
driver.find_element(By.CSS_SELECTOR, ".calendar-prev-month_mlSD9.OP_LOG_BTN").click()
# 組合使用:用標籤+屬性,下面是 input標籤 + class_name + name的組合
driver.find_element(By.CSS_SELECTOR, "input.s_ipt[name='wd']").send_keys("1993")

sleep(4)
driver.quit()

7.2 模糊匹配定位

from selenium import webdriver
from selenium.webdriver.common.by import By
from time import sleep


driver = webdriver.Chrome()
driver.maximize_window()
driver.implicitly_wait(10)
driver.get("https://www.baidu.com")

# 二:模糊匹配
# 這次用a標籤和href屬性來試,開啟百度貼吧,下面程式碼一共會開啟6個百度貼吧頁面
driver.find_element(By.CSS_SELECTOR, "a[href='http://tieba.baidu.com/']").click()
# 模糊匹配-包含,只給出值的中間部分,可以匹配到開頭和結尾
driver.find_element(By.CSS_SELECTOR, "a[href*='tieba.bai']").click()
# 模糊匹配-匹配開頭,只給出值的開頭部分內容,可以匹配到後面
driver.find_element(By.CSS_SELECTOR, "a[href^='http://tie']").click()
# 模糊匹配-匹配結尾,只給出值的後面結尾內容,可以匹配到前面
driver.find_element(By.CSS_SELECTOR, "a[href$='ba.baidu.com/']").click()
# 模糊匹配-標籤,只給出值,可以匹配到標籤
driver.find_element(By.CSS_SELECTOR, "*[href='http://tieba.baidu.com/']").click()
# 娛樂一下,超級模糊。。
driver.find_element(By.CSS_SELECTOR, "*[href*='tieba']").click()

sleep(4)
driver.quit()

7.3 透過父元素定位子元素的方法

from selenium import webdriver
from selenium.webdriver.common.by import By
from time import sleep


driver = webdriver.Chrome()
driver.maximize_window()
driver.implicitly_wait(10)
driver.get("https://www.baidu.com")

# 三、透過父元素定位子元素的方法,這裡用百度首頁左上角的一堆連結演示
# 定位某標籤下的第一個子元素::first-child,例:a:first-child,下面定位點選的是新聞
driver.find_element(By.CSS_SELECTOR, "div#s-top-left>a:first-child").click()
# 定位某標籤下的指定位置的子元素::nth-child(n),例:a:nth-child(5),下面定位點選的是影片
driver.find_element(By.CSS_SELECTOR, "div#s-top-left>a:nth-child(5)").click()
# 還是定位點選影片,用elements拿到所有子元素,再用角標去獲取元素,結果也是一樣
driver.find_elements(By.CSS_SELECTOR, "div#s-top-left>a")[4].click()
# 定位某標籤下的最後一個子元素::first-child,例:a:first-child
# 注意:僅匹配其父元素的最後一個子元素。如果最後一個子元素不是你想要定位的具體型別(比如,在一個<div>中包含了一個<p>和一個<span>,而<span>是最後一個子元素),
#      但你想要定位的是最後一個<p>元素,:last-child就不適用了
# 現在定位百度首頁左上角的連結,F12開啟看,div下子元素有一些a標籤和一個div,div在最後,所以不能用來定位最後一個a標籤,只能定位到div
driver.find_element(By.CSS_SELECTOR, "div#s-top-left>div:last-child").click()

sleep(4)
driver.quit()

8、XPath

根據元素路徑定位,css方式看完後,看XPath應該就很好理解了,這裡暫時列舉出常用的

8.1 路徑

from selenium import webdriver
from selenium.webdriver.common.by import By
from time import sleep


driver = webdriver.Chrome()
driver.maximize_window()
driver.implicitly_wait(10)
driver.get("https://www.baidu.com")

# 一:路徑
# 路徑寫法,相對路徑://
driver.find_element(By.XPATH, "//span/input").send_keys("日曆")
# 路徑寫法,絕對路徑:/
driver.find_element(By.XPATH, "/html/body/div/div/div[5]/div/div/form/span/input").send_keys("日曆")

sleep(4)
driver.quit()

8.2 屬性

from selenium import webdriver
from selenium.webdriver.common.by import By
from time import sleep


driver = webdriver.Chrome()
driver.maximize_window()
driver.implicitly_wait(10)
driver.get("https://www.baidu.com")

# 二:屬性
# 根據屬性id、name、class定位,注意:class定位,class值有多個時,值需要全部填寫
# 格式://標籤名[@屬性名='屬性值']
driver.find_element(By.XPATH, "//input[@id='kw']").send_keys("日")
driver.find_element(By.XPATH, "//input[@name='wd']").send_keys("歷")
driver.find_element(By.XPATH, "//input[@class='bg s_btn']").click()
# 多個屬性定位
driver.find_element(By.XPATH, "//input[@name='wd' and @class='s_ipt']").send_keys("日曆")

sleep(4)
driver.quit()

8.3 其他

from selenium import webdriver
from selenium.webdriver.common.by import By
from time import sleep


driver = webdriver.Chrome()
driver.maximize_window()
driver.implicitly_wait(10)
driver.get("https://www.baidu.com")

# 三:其他
# 匹配標籤內的文字
driver.find_element(By.XPATH, "//a[text()='新聞']").click()
# 模糊匹配標籤內的文字
driver.find_element(By.XPATH, "//a[contains(text(),'新')]").click()
# 指定標籤內的屬性匹配標籤,例:百度首頁點選貼吧
driver.find_element(By.XPATH, "//*[@href='http://tieba.baidu.com/']").click()

sleep(4)
driver.quit()

相關文章