1.環境配置
-
給python安裝selenuim
-
python:
pip3 install selenium
-
Pycharm:
pycharm->perferences->project interpreter->+號->搜索selenium->左下角install package
-
-
安裝驅動
-
驅動下載:Goole驅動下載地址 搜狐驅動下載地址
-
下載的驅動版本要和瀏覽器的版本一致,Goole瀏覽器在
幫助->關於Goole->版本 85.0.4183.102(正式版本)
,下載時就需要下載85.0.4183版本對應的驅動。 -
驅動安裝路徑:
下載完驅動后接壓縮,將解壓縮后的
Chromedriver
放置在蘋果電腦的Gooleusr->local->bin
路徑下。依舊打不開時將
系統偏好設置->安全性與隱私->點擊鎖按鈕允許更改->允許app運行
來允許該驅動運行。
-
2.編寫第一個自動化腳本
from selenium import webdriver#導入selenium的webdriver包,調用webdriver API接口
import time
driver = webdriver.Chrome()#初始化Goole瀏覽器對象,啟動瀏覽器
driver.get("http://www.baidu.com")#通過get()方法向瀏覽器發送網址
#通過元素id=kw定位到搜索框,鍵盤輸入方法send_keys()輸入關鍵字Selenium2
driver.find_element_by_id("kw").send_keys("Selenium2")
#通過元素id=kw定位到“百度一下”搜索按鈕,並向其發送單擊事件click()
driver.find_element_by_id("su").click()
time.sleep(10)
driver.quit()#退出並關閉瀏覽器及相關驅動
3.元素定位
1.python中元素定位的方法:
-
id
-
Class name
-
link text
-
Xpath
-
find_element_by_id()
-
``find_element_by_class_name()`
-
``find_element_by_link_text()`
-
``find_element_by_xpath()`
-
通過
打開Goole瀏覽器-> 更多工具->開發者工具->使用左上角按鈕,點擊百度搜索框,會自動顯示對應HTML代碼,可以看到id=‘kw’
2.id、name、class定位
- id屬性
- 在HTML文檔中必須是唯一的
find_element_by_id("kw")
方法通過id屬性定位搜索
元素
- name屬性
- 在HTML文檔中可以不唯一
find_element_by_name("wd")
方法通過name屬性定位搜索
元素
- class屬性
find_element_by_class_name("s_ipt")
方法通過class屬性定位搜索
元素
3.tag 定位
- tagname其實就是HTML的標簽。不過一個HTML文件里面相同的標簽肯定很多,一般很少用到。
- 基本都是定位父元素,然后父元素定位下面所有tagname元素,再根絕其他條件去操作。比如表格啥的。
find_element_by_tag_name("")
方法通過tagname屬性定位元素
4.link定位
-
這是用來定位文字超鏈接的,可以通過文字鏈接部分的文字描述,定位百度首頁上的更多按鈕
-
find_element_by_link_text("更多").cilck()
方法通過link屬性定位更多
元素
5.partil link定位
- partil link定位是對link定位的一種補充,和link_text區別在於,有些文本鏈接比較長,這個相當於模糊搜索,只輸入部分文字描述就可以了。
driver.find_element_by_partial_link_text("更").click()
方法通過partial_link屬性定位更多
元素
6.Xpath定位
-
find_element_by_xpath()
-
XPath是在XML文檔中定位元素的語言,可參考考:http://www.w3school.com.cn/xpath/index.asp
-
絕對路徑定位
- 參考baidu.html前端工具所展示的代碼,我們可以通過下面的方式找到百度輸入框和搜索按鈕。
- find_element_by_xpath()方法使用XPath語言來定位元素。XPath主要用標簽名的層級關系來定位元素的絕對路徑,最外層為html語言。在body文本內,一級一級往下查找,如果一個層級下有多個相同的標簽名,那么就按上下順序確定是第幾個,例如,div[5]表示當前層級下的第二個div標簽
#找到輸入按鈕
driver.find_element_by_xpath("/html/body/div/div/div[5]/div/div/form/span/input").send_keys("Selenium2")
#搜索按鈕
driver.find_element_by_xpath("/html/body/div/div/div[5]/div/div/form/span[2]/input").click()
-
利用元素屬性定位
- 除了使用絕對路徑外,XPath 也可以使用元素的屬性值來定位。同樣以百度輸入框和搜索按鈕為例:
- //表示當前頁面某個目錄下,input 表示定位元素的標簽名,[@id="kw"]表示這個元素的 id 屬性值等於 kw。下面通過name和class屬性值來定位。
- 可以直接在開發者工具中復制xpath,注意外層 " 符號和內層 ‘ 符號,兩者相同會因無法區分而報錯
#輸入按鈕
find_element_by_xpath("//*[@id='kw']")
#搜索按鈕
find_element_by_xpath("//*[@id='su']")
- 層級與屬性結合
- 如果一個元素本身沒有可以唯一標識這個元素的屬性值,我們可以找其上一級元素,如果它的上一級元素有可以唯一標識屬性的值。也可以拿來使用。
- 通過
form
屬性定位到輸入按鈕的父元素,后面的span[1]
和input
表示父元素下的子元素,
#輸入按鈕
driver.find_element_by_xpath('//*[@id="form"]/span[1]/input').send_keys("Selenium2")
#搜索按鈕
driver.find_element_by_xpath('//*[@id="form"]/span[2]/input').click()
- 使用邏輯運算符
- 如果一個屬性不能唯一地區分一個元素,可以使用邏輯運算符and鏈接多個屬性來查找元素。
<input type="text" id="kw" class="su" name="ie">
<input type="text" id="kw" class="aa" name="ie">
<input type="text" id="bb" class="su" name="ie">
如上面的三行元素,假設我們現在要定位第一行元素,如果使用 id 將會與第二行元素重名,如果使用 class 將會與第三行元素重名,如果同時使用 id 和 class 就會唯一地標識這個元素,這個時候就可以通過邏輯運算符 “and” 來連接兩個條件。
當然,我們也可以用“and”連接更多的屬性來唯一地標識一個元素。
#輸入按鈕
#//input[@]選取所有id屬性的input元素
driver.find_element_by_xpath('//*[@id="kw" and @class="s_ipt"]').send_keys("Selenium2")
#搜索按鈕
driver.find_element_by_xpath('//*[@id="su" and @class="bg s_btn" ]').click()
7.CSS定位
find_element_by_css_selector()
- CSS可以較為靈活地選擇空間的任意屬性,一般情況下定位速度要比XPath快
選擇器 | 描述 |
---|---|
.class | class選擇器,選擇class=‘ ’的所有元素 |
#id | Id選擇器,選擇id=‘ ’的所有元素 |
* | 選擇所有元素 |
element | 元素所有的element元素 |
element1>element2 | 選擇父元素為element1的所有element2元素 |
element1+element2 | 選擇在同一級中緊接在element1元素之后的所有element2元素 |
[attribute=value] | 選擇attribute=value的所有元素 |
- (1) 通過 class 屬性定位
find_element_by_css_selector(".s_ipt")
find_element_by_css_selector(".bg s_btn")
- (2) 通過 id 屬性定位
find_element_by_css_selector("#kw")
find_element_by_css_selector("#su")
-
(3)定位元素
- 通過標簽名定位:
find_element_by_css_selector("input")
- 通過父子關系定位
#定位到搜索框 driver.find_element_by_css_selector('#form>span>input')\ .send_keys("Selenium2") #定位到搜索按鈕 driver.find_element_by_css_selector("#form>span+span>input").click()
- 其他屬性定位
#定位到搜索框 driver.find_element_by_css_selector('[name=wd]').send_keys("Selenium2") #定位到搜索按鈕 driver.find_element_by_css_selector("[type=submit]").click()
- 組合定位
#定位到搜索框 driver.find_element_by_css_selector('#form.fm>span>input.s_ipt').\ send_keys("Selenium2") #定位到搜索按鈕(span的class屬性不可見,無法用class定位) driver.find_element_by_css_selector("form.fm>span>input#su").click()
8.By定位
-
統一調用 find_element()方法,通過 By 來聲明定位的方法,並且傳入對應定位方法的定位參數
-
先通過
from selenium.webdriver.common.by import By
導入By類 -
find_element(By.ID,"kw") find_element(By.NAME,"wd") find_element(By.CLASS_NAME,"s_ipt") find_element(By.TAG_NAME,"input") find_element(By.LINK_TEXT,"更多") find_element(By.PARTIAL_LINK_TEXT,"更") find_element(By.XPATH,"//*[@class='s_ipt']") find_element(By.CSS_SELECTOR,"#form.fm>span>input.s_ipt")
4.控制瀏覽器
1.控制瀏覽器窗口大小
-
maximize_window()
- 使打開的瀏覽器全屏顯示,不需要參數
-
**set-window_size() **
-
設置打開的瀏覽器的大小,需要寬和高的像素點參數
-
print("設置瀏覽器寬800、高480顯示") driver.set_window_size(800,480)
-
2.控制瀏覽器后退、前進
-
back() 和 forward() 方法來模擬后退和前進按鈕
-
from selenium import webdriver import time driver = webdriver.Chrome() #訪問百度首頁 first_url="http://www.baidu.com" print("進入 %s" %(first_url)) driver.get(first_url) #訪問新聞頁面 second_url="http://news.baidu.com" print("進入 %s" %(second_url)) driver.get(second_url) #返回(后退)到百度首頁 print("回到 %s" %(first_url)) driver.back() #前進到新聞頁 print("前往 %s" %(second_url)) driver.forward() time.sleep(3) driver.quit()
3.模擬瀏覽器刷新
-
driver.refresh()刷新當前頁面
-
from selenium import webdriver import time driver = webdriver.Chrome() #訪問百度首頁 first_url="http://www.baidu.com" print("進入 %s" %(first_url)) driver.get(first_url) time.sleep(3) driver.refresh() time.sleep(3) driver.quit()
4.顯示瀏覽器信息
driver.title
打印當前頁面titledriver.current_url
打印當前頁面URLdriver.find_element_by_id("useraddr").text
獲取當前元素文本信息定位的元素.get_attribute('innerHTML')
:會返回元素的內部 HTML, 包含所有的HTML標簽。- ``定位的元素.get_attribute('textContent')`:獲取 HTML 文本,需要注意的是 textContent 是 W3C 兼容的文字內容屬性,不支持 IE 瀏覽器。
定位的元素.get_attribute('innerText')
:獲取 HTML 文本,與 textContent 不同的是 innerText 不是 W3C DOM 的指定內容,不支持 FireFox 瀏覽器。定位的元素.get_attribute('value’)
:獲取帶有 value 屬性的值
from selenium import webdriver
import time
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.keys import Keys
driver = webdriver.Chrome()
driver.get("https://mail.qq.com/")
#iframe有name或id
#driver.switch_to.frame('login_frame')
#iframe無name或id
elementi= driver.find_element_by_xpath('//*[@id="login_frame"]')
driver.switch_to.frame(elementi)
print("Before login==========")
# 打印當前頁面title
now_title = driver.title
print(now_title)
# 打印當前頁面URL
now_url = driver.current_url
print(now_url)
driver.find_element_by_xpath('//*[@id="u"]').clear()
driver.find_element_by_xpath('//*[@id="u"]').send_keys("*******")
driver.find_element_by_xpath('//*[@id="p"]').send_keys("*******")
driver.find_element_by_xpath('//*[@id="login_button"]').click()
#time.sleep(10)
print("After login==========")
# 獲取登錄的用戶名
user = WebDriverWait(driver,20,1).until\
(EC.presence_of_all_elements_located((By.ID,"useraddr")))
# 再次打印當前頁面title
now_title = driver.title
print(now_title)
# 再次打印當前頁面URL
now_url = driver.current_url
print(now_url)
# 打印登錄的用戶名
for i in user:
print(i.get_attribute('textContent'))
time.sleep(3)
driver.quit(
5.簡單元素操作
1.幾種常見方法
-
clear(): 清除文本輸入框文本
-
send_keys(*value): 模擬按鍵輸入
-
click(): 單擊元素,可用於單擊一個按鈕和任何可以單擊的文字/圖片鏈接、復選框、單選框、下拉框等
-
from selenium import webdriver import time driver = webdriver.Chrome() driver.get("https://mail.qq.com/") driver.find_element_by_xpath('//*[@id="u"]').clear() driver.find_element_by_xpath('//*[@id="u"]').send_keys("578389018@qq.com") driver.find_element_by_xpath('//*[@id="p"]').send_keys("*******") driver.find_element_by_xpath('//*[@id="login_button"]').click() time.sleep(3) driver.quit() #會報錯,表示找不到元素
2.找不到元素的可能
-
Frame/Iframe原因定位不到元素
-
-
frame中實際上是嵌入了另一個頁面,而webdriver每次只能在一個頁面識別,因此需要先定位到相應的frame,對那個頁面里的元素進行定位
-
如果 iframe有name或id的話,直接使用
switch_to.frame("name值")
或switch_to.frame("id值")
。 -
如果iframe沒有name或id,先定位到iframe,再將定位對象傳給
switch_to.frame()
方法 -
完成操作后,可以通過
switch_to.parent_content()
方法跳出當前一級iframe,或者還可以通過switch_to.default_content()
方法跳回最外層的頁面。 -
from selenium import webdriver import time driver = webdriver.Chrome() driver.get("https://mail.qq.com/") #iframe有name或id #driver.switch_to.frame('login_frame') #iframe無name或id elementi= driver.find_element_by_xpath('//*[@id="login_frame"]') driver.switch_to.frame(elementi) driver.find_element_by_xpath('//*[@id="u"]').clear() driver.find_element_by_xpath('//*[@id="u"]').send_keys("*******") driver.find_element_by_xpath('//*[@id="p"]').send_keys("*******") driver.find_element_by_xpath('//*[@id="login_button"]').click() time.sleep(3) driver.quit()
-
switch_to包的方法詳解
1. driver.switch_to.active_element() ---------------替換-------------- driver.switch_to_active_element()
定位到當前聚焦的元素上 聚焦這部分參考:https://blog.csdn.net/huilan_same/article/details/52338073
2. driver.switch_to.alert() *---------------**替換**--------------* driver.switch_to_alert()
切換到alert彈窗
3. driver.switch_to.default_content() *---------------替換--------------* driver.switch_to_default_content()
切換到最上層頁面
4. driver.switch_to.frame(frame_reference) *---------------替換--------------*driver.switch_to_frame(frame_reference)
通過id、name、element(定位的某個元素)、索引來切換到某個frame
5. driver.switch_to.parent_frame()
這是switch_to中獨有的方法,可以切換到上一層的frame,對於層層嵌套的frame很有用
6. driver.switch_to.window(window_name) 等同於 driver.switch_to_window(window_name)
切換到制定的window_name頁面
-
-
Xpath描述錯誤原因
-
由於Xpath層級太復雜容易犯錯,可以復制xpath路徑。該方式容易因為層級改變而需要重新編寫過xpath路徑,不建議使用,初學者可以先復制路徑,然后嘗試去修改它。
-
頁面還沒有加載出來,就對頁面上的元素進行的操作
-
這種情況一般說來,可以設置等待,等待頁面顯示之后再操作:
-
-
設置等待時間;缺點是需要設置較長的等待時間,案例多了測試就很慢;
導入時間模塊import time, time.sleep(3)
-
設置等待頁面的某個元素出現,比如一個文本、一個輸入框都可以,一旦指定的元素出現,就可以做操作。
-
使用implicitly_wait()隱形等待
driver.implicitly_wait(20)
- 整個運行過程有效,加載到整個頁面才執行代碼
- 元素到時間沒加載出來匯報ElementNotVisibleException
-
用WebDriverWait()顯性等待,配合該類的until(method, message=' ')和until_not()方法
-
from selenium.webdriver.common.by import By from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.support import expected_conditions as EC
-
WebDriverWait(driver,10,1).until(EC.presence_of_all_elements_located((By.ID,"TANGRAM__PSP_4__content")))
等待10s,每隔1s去檢查元素是否存在
出現執行下一步,10s結束不出現拋出異常 -
expected_conditions 類所提供的預期條件判斷的方法如下表所示
-
-
-
在調試的過程中可以把頁面的html代碼打印出來,以便分析。
print(driver.page_source)
-
-
-
動態id定位不到元素
- 如果發現是動態id,直接用xpath定位或其他方式定位。
-
二次定位,如彈出框登錄
- 如百度登錄彈出框登錄百度賬號,需先定位到百度彈出框,然后再定位到用戶名密碼登錄。
-
不可見元素定位
- 如上百度登錄代碼,通過名稱為tj_login查找的登錄元素,有些是不可見的,所以加一個循環判斷,找到可見元素(is_displayed())點擊登錄即可.
from selenium import webdriver import time from selenium.webdriver.common.by import By from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.support import expected_conditions as EC driver = webdriver.Chrome() ''' 1使用implicitly_wait()隱形等待, 整個運行過程有效,加載到整個頁面才執行代碼 元素到時間沒加載出來匯報ElementNotVisibleException ''' #driver.implicitly_wait(20) driver.get("http://www.baidu.com/") time.sleep(3) #點擊登錄:有些name為tj_login的元素為不可見的,點擊可見的那個登錄按鈕即可。 #否則會報:ElementNotVisibleException element0=driver.find_elements_by_name("tj_login") for ele0 in element0: if ele0.is_displayed(): ele0.click() #在登錄彈出框,需先等登陸彈出框出現 #否則會報:NoSuchElementException ''' 2用sleep time.sleep(3) ''' ''' 3用WebDriverWait()顯性等待,配合該類的until()和until_not()方法 等待10s,每隔1s去檢查元素是否存在 出現執行下一步,10s結束不出現拋出異常 ''' element1=WebDriverWait(driver,10,1).until\ (EC.presence_of_all_elements_located((By.ID,"TANGRAM__PSP_4__content"))) element11=driver.find_element_by_id("TANGRAM__PSP_11__footerULoginBtn").click() #輸入登錄名和密碼並提交 element2=driver.find_element_by_id("TANGRAM__PSP_11__userName") element2.send_keys("登錄名") element3=driver.find_element_by_id("TANGRAM__PSP_11__password") element3.clear() element3.send_keys("密碼") element4=driver.find_element_by_id("TANGRAM__PSP_11__submit") element4.click() element4.submit() try: assert "登錄名" in driver.page_source except AssertionError: print("登錄失敗") else: print("登錄成功") time.sleep(3) finally: print("測試記錄:已測試") driver.close()
3.WebElement 接口常用方法
-
submit()
- 用於提交表單。例如,在搜索框輸入關鍵字之后的“回車”操作,就可以通過submit() 方法模擬
- 有時候 submit() 可以與 click() 方法互換來使用,但 submit() 的應用范圍遠不及 click() 廣泛
-
size: 返回元素的尺寸
-
text: 獲取元素的文本
-
get_attribute(name): 獲取屬性值
-
is_dispalyed(): 設置該元素是否用戶可見,注意,是不可見,不是不存在
-
from selenium import webdriver import time from selenium.webdriver.common.by import By from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.support import expected_conditions as EC driver = webdriver.Chrome() driver.get("http://www.baidu.com") # 獲取輸入框的尺寸 size = driver.find_element_by_id("kw").size print(size) # 返回百度頁面底部備案信息 text = driver.find_element_by_id("s-bottom-layer-right").text print(text) # 返回元素的屬性值,可以是id、name、type或其他任意屬性 attribute = driver.find_element_by_id("kw").get_attribute("type") print(attribute) # 返回元素的結果是否可見,返回結果為True或False result = driver.find_element_by_id("kw").is_displayed() # 注意,是不可見,不是不存在。不存在會直接報錯 print(result) driver.quit() ''' {'height': 44, 'width': 548} ©2020 Baidu (京)-經營性-2017-0020京公網安備11000002000001號京ICP證030173號 text True '''
6.鼠標事件
- ActionChains 類提供了鼠標操作的常用方法:
from selenium.webdriver.common.action_chains import ActionChains
- perform(): 執行所有ActionChains中存儲的行為
- context_click(): 右擊
ActionChains(driver).context_click(right_click).perform()
- ActionChains(driver) 調用 ActionChains() 類,將瀏覽器驅動 driver 作為參數傳入
- context_click(right_click) context_click() 方法用於模擬鼠標右鍵操作,在調用時需要指定元素定位。
- perform() 執行所有 ActionChains 中儲存的行為,可以理解成是對整個操作的提交動作
- double_click(): 雙擊
ActionChains(driver).double_click(double_click).perform()
- drag_and_drop(): 拖動
ActionChains(driver).drag_and_drop(source,target).perform()
- source:鼠標拖動的源元素,target:鼠標釋放的目標元素,在源元素上按住鼠標左鍵,然后移動到目標元素上釋放。
- move_to_element(): 鼠標懸停
ActionChains(driver).move_to_element(above).perform()
- click_and_hold(): 鼠標左鍵按下不放
- ``ActionChains(driver).click_and_hold(above).perform()`
- release(): 釋放鼠標
ActionChains(driver).release().perform()
- reset_action():重置action
- ``ActionChains(driver).reset_action()`
- move_by_offset(x,y):移動鼠標
ActionChains(driver).move_by_offset(x,y).perform()
7.鍵盤事件
from selenium.webdriver.common.keys import Keys
- send_keys()方法可以用來模擬鍵盤輸入,除此之外,我們還可以用它來輸入鍵盤上的按鍵,甚至是組合鍵,如 Ctrl + A ,Ctrl + C等
- send_keys(Keys.BACK_SPACE) 刪除鍵(BackSpace)
- send_keys(Keys.SPACE) 空格鍵(Space)
- send_keys(Keys.TAB) 制表鍵(Tab)
- send_keys(Keys.ESCAPE) 回退鍵(Esc)
- send_keys(Keys.ENTER) 回車鍵(Enter)
- send_keys(Keys.CONTROL,"a") 全選(Ctrl+A)
- send_keys(Keys.CONTROL,"c") 復制(Ctrl+C)
- send_keys(Keys.CONTROL,"x") 剪切(Ctrl+X)
- send_keys(Keys.CONTROL,"v") 粘貼(Ctrl+V)
- send_keys(Keys.F1) 鍵盤F1
- send_keys(Keys.F12) 鍵盤F12
8.定位一組元素
-
定位一組元素的方法與定位單個元素的方法類似,唯一的區別是在單詞element后面多了一個s表示復數
-
find_elements_by_id()
find_elements_by_name()
find_elements_by_class_name()
find_elements_by_tag_name()
find_elements_by_link_text()
find_elements_by_partial_link_text()
find_elements_by_xpath
find_elements_by_css_selector() -
定位一組元素一般用於以下場景:
- 批量操作元素,例如勾選頁面上所有的多選框
- 先獲取一組元素,再從這組對象中過濾出需要操作的元素。例如定位出頁面上所有的checkbox然后選擇其中的一個進行操作。
<!DOCTYPE html> <html> <meta charset="UTF-8"> <body> <form > <p>測試多選框</p> <p><input type="checkbox" name="vehicle" value="Bike" /> 選擇1 </p> <p><input type="checkbox" name="vehicle" value="Car"/> 選擇2 </p> <p><input type="checkbox" name="vehicle" value="name"/> 選擇3 </p> </form> </body> </html>
from selenium import webdriver import time import os driver = webdriver.Chrome() file_path = "file:///" + os.path.abspath("checkbox.html") driver.get(file_path) # 通過XPath找到type=checkbox的元素 # checkboxes = driver.find_elements_by_xpath("//input[@type='checkbox']") # 通過CSS找到type=checkbox的元素 checkboxes = driver.find_elements_by_css_selector("input[type=checkbox]") for checkbox in checkboxes: checkbox.click() time.sleep(1) # 打印當前頁面上的type為checkbox的個數 print(len(checkboxes)) # 把頁面上第一個1個checkbox的鈎給去掉 driver.find_elements_by_css_selector("input[type=checkbox]").pop(0).click() time.sleep(3) driver.quit()
-
勾選頁面的復選框或下拉框
select = Select(定位元素)
獲取相應的元素select.deselect_all()
取消選擇所有的選項select.select_by_visible_text(" ")
通過文本選中選項1select.select_by_value(" ")
通過 value 值選中選項2select.select_by_index(4
通過索引選中選項4- HTML文檔如下
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <p>下拉框測試</p> <select id="selectdemo" onchange="change()" style="width:272px;"> <option id="1" value="選項1">a</option> <option id="2" value="選項2">b</option> <option id="3" value="選項3">c</option> </select> <script language="javascript"> function change() { var obj=document.getElementsByName("select").value; this.focus(); document.getElementById("div1").innerHTML=obj } </script> </head> <body> <p>復選框測試</p> <select id="select" multiple> <option value="xz1">選項1</option> <option value="xz2">選項2</option> <option value="xz3" selected="selected">選項3</option> <option value="xz4">選項4</option> </select> </body> </html>
- 測試文件如下
from selenium import webdriver import time import os from selenium.webdriver.support.ui import Select driver = webdriver.Chrome() file_path = "file:///" + os.path.abspath("checkbox.html") driver.get(file_path) # 通過Select找到id為select的元素 select1 = Select(driver.find_element_by_id("select")) # 先取消選擇所有的選項 select1.deselect_all() # 通過文本選中選項1 select1.select_by_visible_text("選項1") # 通過 value 值選中選項2 select1.select_by_value("xz2") # 通過 index 選擇元素,索引從0開始 select1.select_by_index(3) time.sleep(3) select1.deselect_all() time.sleep(3) select2=Select(driver.find_element_by_id("selectdemo")) select2.select_by_visible_text("c") time.sleep(3) driver.quit()
9.多窗口切換
driver.current_window_handle
獲得當前窗口句柄driver.window_handles
獲得當前所有打開的窗口的句柄driver.switch_to.window(窗口句柄)
跳轉到該窗口
from selenium import webdriver
import time
import os
driver = webdriver.Chrome()
driver.implicitly_wait(10)
driver.get("http://www.baidu.com")
# 獲得百度搜索窗口句柄
sreach_windows = driver.current_window_handle
driver.find_element_by_link_text("登錄").click()
driver.find_element_by_link_text("立即注冊").click()
# 獲得當前所有打開的窗口的句柄
all_handles = driver.window_handles
# 進入注冊窗口
for handle in all_handles:
if handle != sreach_windows:
driver.switch_to.window(handle)
print("now register window!")
time.sleep(2)
# 回到搜索窗口
for handle in all_handles:
if handle == sreach_windows:
driver.switch_to.window(handle)
print("now sreach window!")
# 會跳出來一個讓你下載APP的彈窗,把這個彈窗給點掉
try:
driver.find_element_by_id("TANGRAM__PSP_4__closeBtn")
except:
break
else:
driver.find_element_by_id("TANGRAM__PSP_4__closeBtn").click()
# 彈窗消失后,再去查找
driver.find_element_by_id("kw").send_keys("selenium")
driver.find_element_by_id("su").click()
time.sleep(2)
driver.quit()
10.警告框處理
-
在WebDriver 中處理JavaScript所生成的alert、confirm以及prompt十分簡單,具體做法是使用
dirver.switch_to.alert
方法定位到 alert/confirm/prompt,然后使用text/accept/dismiss/send_keys等方法進行操作。- text:返回 alert/confirm/prompt中的文字信息。
- accept():接受現有警告框
- dismiss():解散現有警告框
- send_keys(keysToSend):發送文本至警告框。keysToSend:將文本發送至警告框。
from selenium import webdriver import time import os from selenium.webdriver.common.action_chains import ActionChains driver = webdriver.Chrome() driver.implicitly_wait(10) driver.get("http://www.baidu.com") # 鼠標懸停至“設置”鏈接 link = driver.find_element_by_xpath('//*[@id="s-usersetting-top"]') ActionChains(driver).move_to_element(link).perform() time.sleep(1) # 打開搜索設置 driver.find_element_by_link_text("搜索設置").click() time.sleep(1) # 沒有這個延遲會出現問題 # 保存設置 driver.find_element_by_link_text('保存設置').click() time.sleep(1) # 接受警告框 alarm=driver.switch_to.alert alarm.accept() time.sleep(1) driver.quit()
11.文件
1.上傳文件
-
普通上傳:普通的附件上傳是將本地文件的路徑作為一個值放在input標簽中,通過form表單將這個值提交給服務器。
-
插件上傳:一般是指基於Flash、JavaScript或Ajax等技術所實現的上傳功能
-
send_keys 實現上傳
- 對於通過input標簽實現的上傳功能,可以將其看做是一個輸入框,即通過send_keys()指定本地文件路徑的方式實現文件上傳。
- HTML文件
<!DOCTYPE html> <html> <head> </head> <body> <form action="demo_form.php"> <input type="file" name="pic" accept="image/*"> <input type="submit"> </form> </body> </html>
- Python文件:
from selenium import webdriver import time import os driver = webdriver.Chrome() driver.implicitly_wait(10) file_path = "file:///" + os.path.abspath("file.html") driver.get(file_path) link = driver.find_element_by_name('pic').send_keys('文件路徑') time.sleep(3) driver.quit()
2.下載文件
-
WebDriver 允許我們設置默認的文件下載路徑,也就是說,文件會自動下載並且存放到設置的目錄中。下面以Firefox瀏覽器為例,執行文件的下載
-
Chrome文件下載
webdriver.ChromeOptions().add_experimental_option('', prefs)
給瀏覽器的啟動選項添加下載的實驗選項- ChromeOptions常用屬性及方法為:
- binary_location=‘‘:指定Chrome瀏覽器路徑
- debuger_address=‘:指定調試路徑
- headless: 無界面模式
- add_argument():添加啟動參數
- add_extension:添加本地插件
- add_experimental_option:添加實驗選項
- to_capablilities:將options轉為標准的capablitiies格式
- ChromeOptions常用屬性及方法為:
download.default_directory
:設置下載路徑profile.default_content_settings.popups
:設置為0禁止彈出窗口- 在網頁中選取要下載的元素下載
from selenium import webdriver import time #支持的瀏覽器啟動選項 options = webdriver.ChromeOptions() prefs = {'profile.default_content_settings.popups': 0, 'download.default_directory': '/Users/Jay/Downloads'} #add_experimental_option:添加實驗選項 options.add_experimental_option('prefs', prefs) driver = webdriver.Chrome(chrome_options=options) driver.get('http://sahitest.com/demo/saveAs.htm') driver.find_element_by_xpath('//a[text()="testsaveas.zip"]').click() time.sleep(3) driver.quit()
-
Firefox文件下載
-
通過FirefoxProfile()對其做一些設置。
-
browser.download.folderList
設置成0代表下載到瀏覽器默認下載路徑,設置成2則可以保存到制定目錄
-
browser.download.manager.showWhenStarting
是否顯示開始:True為顯示,Flase為不顯示
-
browser.download.dir
用於指定所下載文件的目錄。os.getcwd()函數不需要傳遞參數,用於返回當前的目錄
-
browser.helperApps.neverAsk.saveToDisk
指定要下載頁面的Content_type值,“application/octet-stream”為文件的類型
fp = webdriver.FirefoxProfile() #保存到指定目錄 fp.set_preference("browser.download.folderList",2) #不顯示開始 fp.set_preference("browser.download.manager.showWhenStarting",False) #指定所下載文件的目錄 fp.set_preference("browser.download.manager.dir",os.getcwd()) fp.set_preference("browser.helperApps.neverAsk.saveToDisk","application/octet-stream") # 下載文件的類型 driver = webdriver.Firefox(firefox_profile=fp) driver.get("http://pypi.Python.org/pypi/selenium") driver.find_element_by_partial_link_text("selenium-2").click()
-
12.操作cookie
- get_cookies(): 獲得所有cookie信息
- get_cookie(name): 返回字典的key為“name”的cookie信息
- add_cookie(cookie_dict): 添加cookie。“cookie_dict”指字典對象,必須有name和value值
- delete_cookie(name,optionsString): 刪除cookie信息。“name”是要刪除的cookie的名稱,“optionString”是該cookie的選項,目前支持的選項包括“路徑”,“域”。
- delete_all_cookies(): 刪除所有cookie信息
13.調用JavaScript
-
driver.execute_script()
執行JavaScript代碼 -
window.scrollTo()
方法- 用於設置瀏覽器窗口滾動條的水平和垂直位置。方法的第一個參數表示水平的左間距,第二個參數表示垂直的上邊距
-
document.getElementById('id').scrollTop=0
或者document.documentElement.scrollTop=0
滾動條回到頂部 -
document.getElementById('id').scrollTop=10000"
或者document.documentElement.scrollTop=10000
滾動條拉到底部 -
driver.execute_script("arguments[0].scrollIntoView();", 定位元素)
滾動條拉到指定位置(具體元素) -
window.scrollTo()
函數內置方法- document.body.scrollHeight 獲取對象的滾動高度。
- document.body.scrollLeft 設置或獲取位於對象左邊界和窗口中目前可見內容的最左端之間的距離。
- document.body.scrollTop 設置或獲取位於對象最頂端和窗口中可見內容的最頂端之間的距離。
- document.body.scrollWidth 獲取對象的滾動寬度
-
通過id的方式將其進行定位,但卻不能通過send_keys()向文本框中輸入文本信息。這種情況下,就需要借助JavaScript代碼完成輸入
-
text = "input text" js = "var sum=document.getElementById("id"); sum.value = '" + text + "';" driver.execute_script(js)
-
14.視頻播放
- HTML5定義了一個元素
- JavaScript 函數有個內置的對象叫做 arguments。arguments對象包含了函數調用的參數數組,[0]表示取對象的第1個值。
- arguments[0].currentSrc 熟悉返回當前的URL。如果未設置地址元素,則返回空字符串。
- arguments[0].load() 、arguments[0].play() 、arguments[0].pause() 、等控制着視頻的加載、播放和暫停。
from selenium import webdriver
import time
import os
driver=webdriver.Chrome()
driver.get("http://videojs.com/")
time.sleep(5)
video = driver.find_element_by_id('preview-player_html5_api')
# 返回播放文件地址
url = driver.execute_script("return arguments[0].currentSrc;",video)
print(url)
# 播放視頻
print("start")
driver.execute_script("arguments[0].play()",video)
# 播放15秒鍾
time.sleep(5)
# 暫停視頻
print("stop")
driver.execute_script("arguments[0].pause()",video)
time.sleep(3)
driver.quit()
15.窗口截圖
driver.get_screenshot_as_file(‘截圖保存路徑.圖片格式’)
來截取當前窗口- 自動化用例是由程序去執行的,因此有時候打印的錯誤信息並不十分明確。如果在腳本執行出錯的時候能對當前窗口截圖保存,那么通過圖片就可以非常直觀地看出出錯的原因。
from selenium import webdriver
import time
driver=webdriver.Chrome()
driver.get("http://www.baidu.com")
driver.find_element_by_id("kw").send_keys("selenium")
driver.find_element_by_id("su").click()
time.sleep(2)
# 截圖當前窗口,並制定截圖圖片的保存位置
driver.get_screenshot_as_file("/Users/Jay/Downloads/baidu.png") # png格式
driver.quit()
time.sleep(3)
driver.quit()
16.驗證碼的處理
-
cookie繞過登陸
-
通過add_cookie({‘key’:’value'}) 方法將用戶名密碼寫入瀏覽器cookie,當再次訪問網站時,服務器將直接讀取瀏覽器的cookie進行登錄,再次訪問xx網站driver.get("http://www.xx.cn/"),將會自動登錄
-
get_cookies():獲得cookie所有信息,返回的是一個字典
get_cookie(key):獲取返回cookie中,某一個key的值
add_cookie(cookie_dict):手動添加cookie,需要傳一個字典進去,用cookie_dict來接收,字典的鍵必須要有‘name’和‘value’
delete_cookie(name):刪除cookie信息,name是要刪除的cookie名稱
delete_all_cookies():刪除所有cookie信息
from selenium import webdriver import time import os from selenium.webdriver.common.by import By from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.action_chains import ActionChains from selenium.webdriver.common.keys import Keys #給Google添加cookie profile_dir=r"/Users/Jay/Library/Application\ Support/Google/Chrome/Default" # 對應你的chrome的用戶數據存放路徑 chrome_options=webdriver.ChromeOptions() chrome_options.add_argument("user-data-dir="+os.path.abspath(profile_dir)) driver = webdriver.Chrome() driver.get("https://mail.qq.com/") #iframe有name或id #driver.switch_to.frame('login_frame') #iframe無name或id elementi= driver.find_element_by_xpath('//*[@id="login_frame"]') driver.switch_to.frame(elementi) print("Before login==========") # 打印當前頁面title now_title = driver.title print(now_title) # 打印當前頁面URL now_url = driver.current_url print(now_url) driver.find_element_by_xpath('//*[@id="u"]').clear() driver.find_element_by_xpath('//*[@id="u"]').send_keys("***") driver.find_element_by_xpath('//*[@id="p"]').send_keys("***") time.sleep(1) driver.find_element_by_xpath('//*[@id="login_button"]').click() #通過進入登陸成功后的頁面,通過driver.get_cookies()獲得其cookie cookie_get = [{'domain': '.mail.qq.com', 'httpOnly': False, 'name': 'tinfo', 'path': '/', 'secure': False, 'value': '1604393486.0000'}, {'domain': '.mail.qq.com', 'httpOnly': False, 'name': 'qm_ptsk', 'path': '/', 'secure': False, 'value': '1932791597&@G6PjTrqGY'}, {'domain': '.mail.qq.com', 'expiry': 1606985276, 'httpOnly': False, 'name': 'qm_logintype', 'path': '/', 'secure': False, 'value': 'qq'}, {'domain': '.mail.qq.com', 'expiry': 1606985276, 'httpOnly': False, 'name': 'edition', 'path': '/', 'secure': False, 'value': 'mail.qq.com'}, {'domain': '.mail.qq.com', 'httpOnly': False, 'name': 'qm_loginfrom', 'path': '/', 'secure': False, 'value': '1932791597&wsk'}, {'domain': '.mail.qq.com', 'httpOnly': False, 'name': 'qm_domain', 'path': '/', 'secure': False, 'value': 'https://mail.qq.com'}, {'domain': '.mail.qq.com', 'httpOnly': False, 'name': 'xm_uin', 'path': '/', 'secure': True, 'value': '13102662957666093'}, {'domain': '.qq.com', 'expiry': 1604393306, 'httpOnly': False, 'name': 'qm_lg', 'path': '/', 'secure': False, 'value': 'qm_lg'}, {'domain': '.mail.qq.com', 'httpOnly': False, 'name': 'username', 'path': '/', 'secure': False, 'value': '1932791597&1932791597'}, {'domain': '.mail.qq.com', 'httpOnly': False, 'name': 'qm_username', 'path': '/', 'secure': False, 'value': '1932791597'}, {'domain': '.mail.qq.com', 'httpOnly': False, 'name': 'xm_skey', 'path': '/', 'secure': True, 'value': '13102662957666093&3d414a0498da32571b39397536fda73b'}, {'domain': '.mail.qq.com', 'httpOnly': False, 'name': 'sid', 'path': '/', 'secure': False, 'value': '1932791597&9fd715cd79f08f79e96f3591dd09e44c,qQkI1NjRleWFFWVRTUnJwZVU0LVRVQVN3M21KYmtacjVZNG1vdUY2SGVIY18.'}, {'domain': '.mail.qq.com', 'httpOnly': False, 'name': 'p_uin', 'path': '/', 'secure': False, 'value': 'o1932791597'}, {'domain': '.mail.qq.com', 'httpOnly': False, 'name': 'qqmail_alias', 'path': '/', 'secure': False, 'value': '1932791597@qq.com'}, {'domain': '.mail.qq.com', 'httpOnly': False, 'name': 'p_skey', 'path': '/', 'secure': False, 'value': 'BB564eyaEYTSRrpeU4-TUASw3mJbkZr5Y4mouF6HeHc_'}, {'domain': '.mail.qq.com', 'httpOnly': False, 'name': 'foxacc', 'path': '/', 'secure': False, 'value': '1932791597&0'}, {'domain': '.mail.qq.com', 'expiry': 1606985277, 'httpOnly': False, 'name': 'CCSHOW', 'path': '/', 'secure': False, 'value': '000001'}, {'domain': '.mail.qq.com', 'httpOnly': False, 'name': 'pt4_token', 'path': '/', 'secure': False, 'value': 'ebJ5K28JPz4eSfUv0mGoIEkiilKEwej93KO18-GImzo_'}, {'domain': '.qq.com', 'httpOnly': False, 'name': 'uin', 'path': '/', 'secure': False, 'value': 'o1932791597'}, {'domain': '.qq.com', 'httpOnly': False, 'name': 'skey', 'path': '/', 'secure': False, 'value': '@G6PjTrqGY'}, {'domain': '.qq.com', 'expiry': 2147483437, 'httpOnly': False, 'name': 'ptcz', 'path': '/', 'secure': False, 'value': '2c72c4c3127f1ca12f0eb04c2298f08c8d738f2eefe8e93b9110b3eb043d3284'}, {'domain': '.mail.qq.com', 'httpOnly': False, 'name': 'qm_flag', 'path': '/', 'secure': False, 'value': '0'}, {'domain': '.mail.qq.com', 'httpOnly': False, 'name': 'new_mail_num', 'path': '/', 'secure': False, 'value': '1932791597&45'}, {'domain': '.mail.qq.com', 'httpOnly': False, 'name': 'ssl_edition', 'path': '/', 'secure': False, 'value': 'sail.qq.com'}, {'domain': '.mail.qq.com', 'httpOnly': False, 'name': 'xm_sid', 'path': '/', 'secure': True, 'value': 'zS0wTYwPUXguNFVPAHMwNwAA'}, {'domain': '.qq.com', 'expiry': 2147483437, 'httpOnly': False, 'name': 'RK', 'path': '/', 'secure': False, 'value': 'WvBENmHXPC'}, {'domain': '.mail.qq.com', 'httpOnly': False, 'name': 'wimrefreshrun', 'path': '/', 'secure': False, 'value': '0&'}, {'domain': '.qq.com', 'expiry': 1606985272, 'httpOnly': False, 'name': 'ptui_loginuin', 'path': '/', 'secure': False, 'value': '1932791597@qq.com'}] print(cookie_get) #清除瀏覽器cookie driver.delete_all_cookies() cookies = cookie_get for cookie in cookies: #去除無效cookie if 'expiry' in cookie: del cookie['expiry'] #添加cookie driver.add_cookie(cookie) #刷新頁面 driver.refresh() time.sleep(3) print("After login==========") # 獲取登錄的用戶名 user = WebDriverWait(driver,20,1).until\ (EC.presence_of_all_elements_located((By.ID,"useraddr"))) # 再次打印當前頁面title now_title = driver.title print(now_title) # 再次打印當前頁面URL now_url = driver.current_url print(now_url) # 打印登錄的用戶名 for i in user: print(i.get_attribute('textContent')) time.sleep(3) driver.quit()
-