Selenium庫
用于web應用程式的測試工具
模拟手工操作浏覽器,進行自動化測試
特點
- 開源免費
- 多浏覽器支援 —Chrome、IE、FireFox等
- 多平台支援 — Windows、Linux都支援
- 支援分布式測試(Grid)
- 支援錄制回放和腳本生成(IDE)
Selenium三劍客
- WebDriver
- IDE 支援錄制回放和腳本生成
- Grid 支援分布式測試
官方文檔
- https://selenium-python.readthedocs.io/index.html
- https://seleniumhq.github.io/selenium/docs/api/py/api.html
webdriver工作原理
通過浏覽器的driver與浏覽器進行通信.(傳令兵,把我們的指令通過webdriver傳遞給浏覽器,同時把浏覽器的傳回結果進行定位、操作、擷取屬性資訊等)
配置環境
pip install selenium
下載下傳webdriver(與浏覽器的種類和版本比對)
Chrome:http://chromedriver.storage.googleapis.com/index.html
Firefox:https://github.com/mozilla/geckodriver/releases/
下載下傳好後解壓
1.放置到python的安裝目錄
2.放置在項目中的專門目錄
使用selenium
進入網址,進入到網站後顯示5秒鐘,5秒之後關閉浏覽器
# 想操作浏覽器導入webdriver的包就可以,不用導入selenium中所有的包
from selenium import webdriver
from time import sleep
# 初始化一個driver(要加括号)
driver = webdriver.Chrome()
# 通路樂博商城的網址
driver.get("http://shop.pro.17lebo.com")
#這時我就可以控制浏覽器了,能控制浏覽器就可以操縱要測試的軟體了
#……
# 沉睡5秒鐘
sleep(5)
# 退出目前标簽頁
# driver.close()
# 退出整個浏覽器 不關閉浏覽器,浏覽器會越來越多
driver.quit()
webdriver的功能
- 能通路浏覽器
- 能設定浏覽器的視窗大小 無界面時也有效
# 最大化
driver.maximize_window()
# 最小化
driver.minimize_window()
# 設定視窗大小
driver.set_window_size(800, 600)
- 控制前進、後退
from selenium import webdriver
from time import sleep
# 初始化一個driver(要加括号)
driver = webdriver.Chrome()
# 通路樂博商城的網址
driver.get("http://shop.pro.17lebo.com")
# 設定浏覽器的大小
# 最大化
driver.maximize_window()
# 控制前進。後退
# 打開樂博官網
driver.get("http://www.17lebo.com")
sleep(3)
# 後退 去上一個頁面
driver.back()
sleep(3)
# 前進 去下一個頁面
driver.forward()
sleep(3)
- 截圖
# 浏覽器截圖
driver.get_screenshot_as_file("浏覽器截圖3.png")
- 重新整理頁面
# 重新整理頁面
driver.refresh()
- 關閉浏覽器
- 關閉目前頁面
- 擷取頁面屬性
浏覽器的無界面操作
每次運作的時候都會出現浏覽器,有的時候不想讓浏覽器出現,就用到無界面操作
無界面模式下預設不是全屏,預設大小是800*600
# 浏覽器的無界面操作
# 用來儲存各種webdriver的配置項
opt = webdriver.ChromeOptions()
opt.headless = True
# 初始化一個driver(要加括号)
driver = webdriver.Chrome(options=opt)
Selenium定位頁面元素
UI自動化測試,從定位頁面元素開始
8大定位方法
- id
- name
- class name:class的名
- tag name:标簽名
- link text:連結的文字内容
- partial link text:這個link text包含的一部分内容
- xpath
- css selector
find_element()和find_elements()
name定位
item = driver.find_element_by_name("wd")
item.send_keys("手機")
可以看到是定位成功并且已經輸入我想要搜尋的内容了
但是提示了最好不要使用find_element_by_*,selenium4.0以後就無法使用了
是以用find_element()代替
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
# 通路樂博商城的網址
driver.get("http://shop.pro.17lebo.com")
item = driver.find_element(By.NAME, "wd")
item.send_keys("手機")
By.name實際就是傳的name,同理,By.id就是傳的id
是以可以直接傳name
item = driver.find_element("name", "wd")
item.send_keys("手機")
id定位
item = driver.find_element("id", "search-input")
item.send_keys("手機")
class定位
我想定位百寶箱,然後點選
item = driver.find_element("class name", "navigation-main-quick")
item.click()
點選百寶箱後底部彈框,說明點選成功
tag name定位
多少有點不靠譜,因為重名的太多了
标簽名定位,需要确認這個頁面隻有一個這個标簽,才用标簽定位,否則定位出來的就不止一個了
item = driver.find_element("tag name", "input")
item.send_keys("手機")
如果目前頁面有多個同樣的标簽,就要用find_elements(),這時,傳回的就是一個清單了,如果要引用其中的一個元素,就要加索引
比如:
item = driver.find_elements("tag name", "input")
item[1].send_keys("手機")
link text定位
link是通過連結的文字定位,點一下會跳轉到另外的頁面
item = driver.find_element("link text", "登入")
item.click()
partial link text定位
和link text差不多,隻是這個是通過連結的文字内容的一部分進行定位,而不是全部内容
還是點選登入跳轉,我隻要連結中的“錄”字就可以定位到了
item = driver.find_element("partial link text", "錄")
item.click()
id、 name、 class name、tag name、 link text、partial link text這些定位方法都是理想的情況下,能通過這些定位,都是有要求的,有局限性。如果标簽中沒有這些屬性,就沒法通過這些來定位了。
xpath和css selector定位是萬能定位,功能強大,css selector比xpath的速度快
xpath定位
xpath就是XML path language
專門在xml文檔中對元素和屬性進行周遊
xpath是可以拷貝的
相對定位://*[@id=“search-input”]
絕對定位(嚴重不推薦):/html/body/div[3]/div/div[3]/form/div/input
xpath的文法結構:xpath = //tagname[@Attribute = ‘value’]
-
斜線/雙斜線 查找範圍或查找方式
/表示絕對定位
//表示相對定位
-
tagname 标簽名稱
*代表所有标簽
具體的标簽名稱:h、p、input、div、button、a…
當标簽名不足以唯一的選擇出來時,後面可以加條件[ ]
-
[ ]選擇條件
@Attribute 用屬性進行選擇 id、name、class…
用函數選擇
屬性+函數
隻用标簽名後面不跟選擇條件
# xpath的選擇條件隻用标簽名定位
items = driver.find_elements("xpath", "//p")
for i in items:
print(i.text)
xpath的選擇條件隻用标簽名定位的執行結果,隻用标簽名一般都會定位到很多東西
選擇條件用id
# 選擇條件用id
item = driver.find_element("xpath", "//input[@id='search-input']")
item.send_keys("找到一個//input[@id=search-input]")
選擇條件用name
# 選擇條件用name
item = driver.find_element("xpath", "//input[@name='wd']")
item.send_keys("找到xpath為//input[@name='wd']的元素")
選擇條件用class+層級關系
# 選擇條件用class
# 這個元素的class不是唯一的,是以可以用層級關系來輔助定位
# 因為要定位的是一個input 而input的class不是唯一的,是以找到input上一級的class,input上一級是一個div,把這個div寫出來,然後後面再加一個input
# 這個class在整個頁面中不是唯一的,但是在這個div中是唯一的
item = driver.find_element("xpath", "//div[@class='search-group']/input")
item.send_keys("找到xpath為//div[@class='search-group']/input的元素")
text() 函數
用屬性前面有@符,用函數前面沒有@符
# text屬性
# 先找到輸入框元素
item = driver.find_element("xpath", "//div[@class='search-group']/input")
# 在輸入框中輸入手機
item.send_keys("手機")
# 找到搜尋按鈕(已經精确到文字内容了,是以前面标簽名可以用通配符*)
search = driver.find_element("xpath", "//*[text()='搜尋']")
# 點選搜尋
search.click()
這時已經進到手機頁了
使用索引
沒有辦法唯一定位的時候可以使用索引
item = driver.find_element("xpath", "//div[@class='search-group']/input")
item.send_keys("手機")
item = driver.find_elements("xpath", "//button")
item[0].click()
多條件組合
當中括号中一個條件已經不足以确定元素的時候,就可以輸入多個條件
# 多條件組合
item = driver.find_element("xpath", "//input[@type = 'text' and @placeholder = '其實搜尋很簡單^_^ !']")
item.send_keys("電腦")
常用函數
contains() 包含XXX
# 常用函數之包含XXX——contains()
item = driver.find_element("xpath", "//input[contains(@placeholder,'^_^')]")
item.send_keys("電腦")
starts-with() 以XXX開頭
# 以XXX開頭——starts-with()
item = driver.find_element("xpath", "//input[starts-with(@placeholder,'其實')]")
item.send_keys("電腦")
……
軸 (相對查找. 找 父節點,祖父節點)
文法:
軸名稱::節點測試[謂語]
軸名稱 | 結果 |
---|---|
ancestor | 選取目前節點的所有先輩(父、祖父等)。 |
ancestor-or-self | 選取目前節點的所有先輩(父、祖父等)以及目前節點本身。 |
attribute | 選取目前節點的所有屬性。 |
child | 選取目前節點的所有子元素。 |
descendant | 選取目前節點的所有後代元素(子、孫等)。 |
descendant-or-self | 選取目前節點的所有後代元素(子、孫等)以及目前節點本身。 |
following | 選取文檔中目前節點的結束标簽之後的所有節點。 |
namespace | 選取目前節點的所有命名空間節點。 |
parent | 選取目前節點的父節點。 |
preceding | 選取文檔中目前節點的開始标簽之前的所有節點。 |
preceding-sibling | 選取目前節點之前的所有同級節點。 |
self | 選取目前節點。 |
… |
css selector定位
css定位是selenium首推的定位方式,因為css定位的速度快。項目小的時候無所謂,項目大的時候速度快是很重要的。
幾乎很難發現找到某一個元素沒有class沒有樣式的,所有網頁裡顯示的都系幾乎都會有樣式,沒有樣式會特别醜。是以css選擇器定位很友善,總會定位出來想要的元素。
css和xpath的比較:
- 速度比xpath快
- 文法簡潔
css選擇器用id定位
# css selector定位
# 用id定位 #代表id
item = driver.find_element("css selector", "#search-input")
item.send_keys("手機")
用name定位
# 用name定位 input是我要定位元素的标簽
item = driver.find_element("css selector", "input[name='wd']")
item.send_keys("手機")
用class name定位
class name定位的一般都會出現一堆,而不是一個,是以要通過索引定位
# class name定位 .代表class
items = driver.find_elements("css selector", ".outer")
items[2].click()
要定位的元素有多個class時
# 多個class
item = driver.find_element("css selector", "[class='am-text-truncate name']")
item.click()
用其他屬性定位
# 用其他屬性定位 三種都可以
# item = driver.find_element("css selector", "input[placeholder='其實搜尋很簡單^_^ !']")
# item = driver.find_element("css selector", "*[placeholder='其實搜尋很簡單^_^ !']")
item = driver.find_element("css selector", "[placeholder='其實搜尋很簡單^_^ !']")
item.send_keys("手機")
多個屬性組合
item = driver.find_element("css selector", "input[placeholder='其實搜尋很簡單^_^ !'][autocomplete='off']")
item.send_keys("手機")
部分屬性定位
包含 *=
# 包含 *=
item = driver.find_element("css selector", "input[placeholder *= '很簡']")
item.send_keys("手機")
以XXX開始 ^=
# 以XXX開始 ^=
item = driver.find_element("css selector", "input[placeholder ^= '其實']")
item.send_keys("手機")
以XXX結束 $=
# 以XXX結束 $=
item = driver.find_element("css selector", "input[placeholder $= '!']")
item.send_keys("手機")
層級關系 >
上下一級關系,頂頭上司
# 層級關系 > div是父級,input是子級
item = driver.find_element("css selector", "div[class='search-group']>input")
item.send_keys("電腦")
後代關系 用空格
上下多級關系,越級上司
# 後代關系 用空格
item = driver.find_element("css selector", "div[class='am-container'] input")
item.send_keys("電腦")
兄弟選擇器
# 兄弟選擇器 找到div中class為word的元素,在這個元素裡面找到a标簽,冒号後面代表要找第幾個a标簽的元素
# 找第一個
# item = driver.find_element("css selector", "div[class='word']>a:first-child")
# 找第三個
# item = driver.find_element("css selector", "div[class='word']>a:nth-child(3)")
# 找最後一個
item = driver.find_element("css selector", "div[class='word']>a:last-child")
item.click()
層級與class組合
# 層級與class組合
item = driver.find_element("css selector", "div.search-bar>form>div>input")
item.send_keys("電腦")
selenium官方文檔 CSS定位
css選擇器常用的文法
選擇器 | 例子 | 例子描述 |
---|---|---|
.class | .intro | 選擇 class=“intro” 的所有元素。 |
#id | #firstname | 選擇 id=“firstname” 的所有元素。 |
* | * | 選擇所有元素。 |
element | p | 選擇所有 < p > 元素。 |
element,element | div,p | 選擇所有 < div> 元素和所有 < p> 元素。 |
element element | div p | 選擇 < div> 元素内部的所有 < p> 元素。 |
element>element | div>p | 選擇父元素為 < div> 元素的所有 < p> 元素。 |
element+element | div+p | 選擇緊接在 < div> 元素之後的所有 < p> 元素。 |
[attribute] | [target] | 選擇帶有 target 屬性所有元素。 |
[attribute=value] | [target=_blank] | 選擇 target=“_blank” 的所有元素。 |
[attribute~=value] | [title~=flower] | 選擇 title 屬性包含單詞 “flower” 的所有元素。 |
[attribute I= value] | [lang I= en] | 選擇 lang 屬性值以 “en” 開頭的所有元素。 |
… |
多個元素的情況
在有些特殊情況就需要定位多個元素,然後挨個去進行操作
還有可能就是實在無法定位到唯一的元素了,找不到條件了,那就隻能定位多個元素然後通過索引定位到要用的元素
items = driver.find_elements("class name", "outer")
for item in items:
# 列印出所有的元素
print(item.text)
# 然後就可以根據對應的索引進行定位,然後操作了
items[1].click()
擷取頁面中元素的屬性值
items = driver.find_elements("class name", "outer")
# 擷取頁面元素的屬性值
print(items[2].get_attribute("name"))
print(items[2].get_attribute("type"))
print(items[2].get_attribute("class"))
有的有有的沒有,有值的會列印出來,沒有的會顯示為空
頁面元素的互動操作
點選:click()
輸入:send_keys()
清除:clear()
等等……