測試工程師必備!Selenium自動化測試全攻略 | 手寫POM框架+數據驅動,輕松搞定UI自動化!
簡單的加個前置知識:
第一:webdriver.Chrome()這句話,通過WebDriver的構造方法,拿到瀏覽器驅動的對象,然后通過這個對象,就可以調用一系列操作瀏覽器的方法。
因為原理就是通過瀏覽器驅動做橋梁實現兩端通訊的。
第二:元素定位的方法find_element,是selenium中WebDriver類的方法。
find_element:返回的是單個元素對象。
find_elements:返回的是存放有多個元素對象的一個list。
定位頁面元素的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的開發者工具里右鍵復制,雖然快捷,但在復雜的頁面并不好用,不準確,有時生成的值還很長看著臃腫。
???我發現右鍵復制生成的路徑,根節點都是用 id,所以 id 動態的話就只能手寫定位了。
下面我用百度搜索來做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(3) |
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(3) |
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(3) |
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(3) |
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(3) |
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(3) |
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" |
# 1、html標簽:頁面上一般都有多個相同標簽,所以需要再加上父級標簽指明是哪個標簽下的,父級標簽也有多個就再往上找父級,如此類推 |
driver.find_element(By.CSS_SELECTOR, "span>input").send_keys("日") |
# 2、name:[屬性名],例:[name='wd'] |
driver.find_element(By.CSS_SELECTOR, "[name='wd']").send_keys("歷") |
# 3、id:#id,例:#su |
driver.find_element(By.CSS_SELECTOR, "#su").click() |
sleep(3) |
# 4、class:.class,例:".calendar-prev-month_mlSD9 OP_LOG_BTN" |
driver.find_element(By.CSS_SELECTOR, ".calendar-prev-month_mlSD9.OP_LOG_BTN").click() |
# 5、組合使用:用標簽+屬性,下面是 input標簽 + class_name + name的組合 |
driver.find_element(By.CSS_SELECTOR, "input.s_ipt[name='wd']").send_keys("1993") |
sleep(3) |
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() |
# 1、模糊匹配-包含,只給出值的中間部分,可以匹配到開頭和結尾 |
driver.find_element(By.CSS_SELECTOR, "a[href*='tieba.bai']").click() |
# 2、模糊匹配-匹配開頭,只給出值的開頭部分內容,可以匹配到后面 |
driver.find_element(By.CSS_SELECTOR, "a[href^='http://tie']").click() |
# 3、模糊匹配-匹配結尾,只給出值的后面結尾內容,可以匹配到前面 |
driver.find_element(By.CSS_SELECTOR, "a[href$='ba.baidu.com/']").click() |
# 4、模糊匹配-標簽,只給出值,可以匹配到標簽 |
driver.find_element(By.CSS_SELECTOR, "*[href='http://tieba.baidu.com/']").click() |
# 娛樂一下,超級模糊。。 |
driver.find_element(By.CSS_SELECTOR, "*[href*='tieba']").click() |
sleep(3) |
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") |
# 三、通過父元素定位子元素的方法,這里用百度首頁左上角的一堆鏈接演示 |
# 1、定位某標簽下的第一個子元素::first-child,例:a:first-child,下面定位點擊的是新聞 |
driver.find_element(By.CSS_SELECTOR, "div#s-top-left>a:first-child").click() |
# 2、定位某標簽下的指定位置的子元素::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() |
# 3、定位某標簽下的最后一個子元素::last-child,例:a:last-child |
# 注意:last-child它是只匹配父元素下的所有元素的最后一個子元素,如果最后一個子元素不是你要的那個標簽類型,那這個方法就沒用了 |
# 比如:現在演示的百度這里,在<div>下,第1個<a>新聞,第2個<a>hao123,第3個<a>地圖,最后一個標簽不是<a>,是<div>;那就不能用a:last-child定位到,但是可以用div:last-child定位到 |
# 結論:父元素下最后一個標簽是 x 就 x:last-child。可以在百度首頁,用網頁F12在Elements窗口,把那個<div>刪除或者移到其他位置去試試 |
driver.find_element(By.CSS_SELECTOR, "div#s-top-left>div:last-child").click() |
sleep(3) |
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(3) |
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(3) |
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() |
# 使用索引定位第幾個標簽,例:百度首頁點擊貼吧 |
driver.find_element(By.XPATH, '//div[@id="s-top-left"]/a[4]').click() |
sleep(3) |
driver.quit() |
測試工程師必備!Selenium自動化測試全攻略 | 手寫POM框架+數據驅動,輕松搞定UI自動化!
?