瀏覽器copy selector
我們選擇元素有一個方法可以快速生成,右鍵點擊元素點擊檢查定位到元素后糠亩,右鍵點擊元素有個Copy
秆撮,選擇Copy selector
Copy selector
是Css
的寫法收壕,我們看到也有XPath
大家也可以試一下歼捐,這種方法其實是非常有限的,這種方式是以一個有id
的元素為瞄點往下找你画,如果有id的元素不是本身而是上層節(jié)點他就要依賴上層節(jié)點和他的相對關(guān)系來找抵碟,如果上層節(jié)點跟他隔得很遠,他也會一層層的找打他有id
的上層節(jié)點坏匪,路徑會很長如果他中間的任何一個環(huán)節(jié)發(fā)生變化就容易出問題健壯性不好拟逮,他不會根據(jù)別的方法比如class
,這種方法我們了解一下就好很雞肋。
異常捕獲适滓,確保chrom進程退出
我們做練習(xí)的時候不可能一次就把作業(yè)做出來罚屋,總歸要做一些調(diào)試出錯調(diào)試出錯尖滚,肯定遇到過出錯瀏覽器就沒法關(guān)閉的狀況造锅,有的同學(xué)會想不關(guān)就不關(guān)唄我們手動關(guān)上就好了糙箍,調(diào)試的時候是可以的咕晋,假如我們做系統(tǒng)自動化的時候有很多的用例上百個web自動化用例在執(zhí)行质蕉,如果遇到報錯瀏覽器沒有關(guān)閉绷蹲,第二天我們?nèi)タ吹脑挋C器就像卡死了一樣测秸,因為很多用例遇到報錯比如找不到元素的錯誤導(dǎo)致瀏覽器開了二三十個在那甚至更多铃拇,我們可以把自動化邏輯放在異常捕獲try
里面`钞瀑,看下面例子
from selenium import webdriver
import time
driver = webdriver.Chrome('E:\ChromDriver\chromdriver2.43\chromedriver.exe')
driver.implicitly_wait(10)
driver.get('https://www.baidu.com/')
print(driver.title)
driver.find_element_by_id('kk').send_keys('杭州')
driver.quit()
百度的輸入框id
為kw
我這里改為kk
這時候,由于不能執(zhí)行到driver.quit,瀏覽器就不能自動關(guān)閉慷荔,解決方法
import traceback
from selenium import webdriver
import time
driver = webdriver.Chrome('E:\ChromDriver\chromdriver2.43\chromedriver.exe')
driver.implicitly_wait(10)
try:
driver.get('https://www.baidu.com/')
print(driver.title)
driver.find_element_by_id('kk').send_keys('杭州')
except:
print(traceback.format_exc())
finally:
driver.quit()0
寫在try
里面雕什,finally
后面需要driver.quit()
我們操作界面的時候不需要點擊他,把鼠標移動到上面就會導(dǎo)致頁面的變化显晶,比如我們打開華為官網(wǎng)https://www.vmall.com/
HTML
當中即使光標不放在上面磷雇,我們能不能不模擬光標放在上面偿警,可以找到直接去選擇元素(筆記本電腦之類的)嗎?像這些界面元素如果沒有把光標停在上面讓界面顯示出來唯笙,通常是不能操作他的會出錯螟蒸,因為當前這個元素如果處于沒有顯示出來的狀態(tài)你就想試著去操作他,其實這個元素有個屬性class
等于none
的這種屬性他的display
是none
display
元素是none
的意思是他當前在界面放在HTML里面但是他不顯示出來不顯示在界面上睁本,Selenium是高度模擬用戶點擊操作的尿庐,因為他沒有顯示出來這個時候你點擊他會出錯的,我們可以把它凍結(jié)Selenium
怎么模擬這個移動鼠標到某個元素的動作呢抄瑟?通過ActionChains
類,ActionChains
類 里面提供了 一些特殊的動作, 比如移動鼠標到某個元素枉疼,就是其中之一,ActionChains
本身有個ActionChains
模塊文件本身實現(xiàn)了一個ActionChains
類皮假,我們查看這個類的放方法
click
點擊,click_and_hold
點擊按住不動不要松骂维,context_click
右鍵點擊惹资,double_click
雙擊等這里不一一介紹大家自己去研究,我們這里用到的就是move_to_element
懸停就使用他
from selenium import webdriver
import time
executable_path = r"d:\tools\webdrivers\chromedriver.exe"
driver = webdriver.Chrome(executable_path)
driver.get('https://www.vmall.com/')
# ---------------------------------------
# 導(dǎo)入ActionChains這個類
from selenium.webdriver.common.action_chains import ActionChains
# 創(chuàng)建實例對象
ac = ActionChains(driver)
#移動不點擊 .perform()執(zhí)行
ac.move_to_element(driver.find_element_by_id('zxnav_1')).perform()
ele= driver.find_element_by_css_selector(
'#zxnav_1 > div.category-panels.relative > ul > li:nth-child(1) > a')
ele.click()
# ---------------------------------------
input('...')
driver.quit()
下面我們看一段HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>定位網(wǎng)頁元素</title>
</head>
<body style="width:1600px">
<div>
<span>輸入框</span> <input type="text" style="margin-top:2200px">
</div>
</body>
</html>
可以看到這段HTML很簡單航闺,body
里面有個div
褪测,div
里面有個span
里面有個input
輸入框,里面有個很奇怪的屬性margin-top
他的意思是
2200px
像素潦刃,這個間隔是很高的侮措,大家復(fù)制這段html
看一下,比如做自動化的時候web
頁面很長乖杠,他的內(nèi)容在很下面分扎,我們需不要把這個頁面滾動到下方讓他出來再去操作這個元素呢?大家注意華為官網(wǎng)的看不到是因為元素所在的區(qū)域已經(jīng)有了胧洒,只是你沒有操作他畏吓,它屬于不可見屬性的看不到墨状,但是我們現(xiàn)在講的這種其實可見狀態(tài)只是你滾動條沒有拉下來,通長這種情況不需要你滾動下來的菲饼,它本身在視圖上是有的只是沒呈現(xiàn)滾動區(qū)域里面
from selenium import webdriver
executable_path = r"d:\tools\webdrivers\chromedriver.exe"
driver = webdriver.Chrome(executable_path)
driver.implicitly_wait(10)
driver.get('file:///D:/gsync/workspace/sq/selenium/samples_selenium/wd/lesson07/winsize.html')
searchbox = driver.find_element_by_tag_name('input')
searchbox.send_keys('你好啊\n')
input('...')
driver.quit()
大家自己拿代碼試一下肾砂。
如果確實需要改變窗口大小,
- 有時確實讓元素可見巴粪,才能點擊(有時候確實是這樣通今,不知道什么原因)
- 或者覺得這樣看起來更清楚一些
size = driver.get_window_size()#返回是字典格式
driver.set_window_size(1100,size['height'])
下面是對網(wǎng)易云音樂寫的代碼,可拿去試一下
from selenium import webdriver
driver = webdriver.Chrome(r"E:\ChromDriver\chromedriver.exe")
driver.implicitly_wait(10)
driver.get('http://music.163.com')
# 結(jié)果像這樣 {'width': 855, 'height': 922}
size = driver.get_window_size()
print(size)
# 只改變寬度
driver.set_window_size(1300, size['height'])
#最大化
driver.maximize_window()
searchbox = driver.find_element_by_css_selector('#srch')
searchbox.send_keys('張學(xué)友\n')
driver.quit()
假如還一種情況要找的元素他在特別的右邊或特別的下邊窗口最大化都顯現(xiàn)不出來肛根,那就需要滾動元素的方案,selenium
沒有直接的方法漏策,可以使用最后一招派哲, 直接讓瀏覽器執(zhí)行javascript
腳本瀏覽器執(zhí)行的語言是js
, 如果我們能直接傳入js
代碼讓瀏覽器執(zhí)行掺喻,就得到了最大的靈活性去控制瀏覽器芭届。可以算是終極武器感耙。 比如滾動屏幕褂乍,就可以使用js
語言
driver.execute_script('window.scrollBy(250,0)')
第一個參數(shù)250是橫向滾動就是x坐標滾動,往右滾250個像素即硼,如果有們想往左滾
driver.execute_script('window.scrollBy(-250,0)')就滾回去了
第二個參數(shù)是下滾
driver.execute_script('window.scrollBy(0,300)')
上滾加個負號就好了
界面重新繪制
接下來說一下界面里面元素出現(xiàn)動態(tài)改變的這個情況逃片,我們看一個例子,下面截圖是一個教管系統(tǒng)!
假如我們要實現(xiàn)一個自動化只酥,要把所有的課程信息刪除掉褥实,如果按照之前的方法我們點擊“刪除”然后點擊“確定”,把所有的刪除按鈕都找到裂允,看似很簡單我們按照這個思路去寫代碼损离,根據(jù)我們的思路要把所有的刪除按鈕找出來
btn-green
看名字就可以看出來按鈕是綠色的btn-outlined
是外面有一個方框,根據(jù)這個class是不好去找的因為編輯也有同樣的屬性十饥,這里根據(jù)ng-click
這個屬性去找比較好窟勃,他這個屬性對應(yīng)刪除的動作,點了這個刪除之后會執(zhí)行一段JavaScript
代碼或函數(shù)绷跑,刪除是跟這個緊密相關(guān)的拳恋,點擊刪除之后這里還有個確定,from selenium import webdriver
import time
driver = webdriver.Chrome()
driver.implicitly_wait(5)
driver.get('http://localhost/mgr/login/login.html')
#登錄
driver.find_element_by_id('username').send_keys('auto')
driver.find_element_by_id('password').send_keys('sdfsdfsdf')
driver.find_element_by_tag_name('button').click()
time.sleep(1)
#根據(jù)ng-click去找刪除按鈕谬运,這里是個list
delButtons = driver.find_elements_by_css_selector(
'*[ng-click^=delOne]')
for button in delButtons:
button.click()
time.sleep(1)
driver.find_element_by_css_selector(
'.modal-footer .btn-primary').click()
運行會發(fā)現(xiàn)刪除第一個之后就不動了隙赁,報錯了報錯信息如下
selenium.common.exceptions.StaleElementReferenceException: Message: stale element reference: element is not attached to the page document
(Session info: chrome=74.0.3729.157)
(Driver info: chromedriver=74.0.3729.6 (255758eccf3d244491b8a1317aa76e1ce10d57e9-refs/branch-heads/3729@{#29}),platform=Windows NT 10.0.17134 x86_64)
我們分析一下報錯WebDriver
報的Exception
,unknown error
不知道什么類型,我們看下error的報錯Element <button >
對應(yīng)的是這個webelement對象梆暖,看后面的就是我們刪除按鈕web的寫法<button type="button" class="btn btn-green btn-outlined btn-xs ng-scope" ng-click="delOne(one)"
伞访,報is not clickable at point
是不可點擊的,Other element would receive the click
另外一個元素接收到點擊的動作轰驳,這個元素為什么不可點擊呢厚掷。大家想一下剛才的運行結(jié)果,確實已經(jīng)刪除了一個元素了到第二個刪除操作的時候就報錯了级解,大家以后做自動化的時候會經(jīng)常遇到這種事情冒黑,因為現(xiàn)在web前端的開發(fā)很多開發(fā)人員使用的方法都會動態(tài)的更新的前端界面,之前最早的web界面的呈現(xiàn)勤哗,比如導(dǎo)致web界面出現(xiàn)了變化抡爹,都是發(fā)起http請求,后端返回一個完整的http頁面給你芒划,以前都是這樣冬竟,隨著前端開發(fā)衍進覺得這種效率太低,因為有的時候并不需要后端重新產(chǎn)生一個完整的界面民逼,比如這個刪除操作泵殴,刪除一個課程只需要告訴后端我把這個課程刪了,服務(wù)器處理一下在數(shù)據(jù)庫把這個課程清除掉拼苍,沒有必要讓服務(wù)端再返回一個完整html的界面給前端笑诅,對于我們來說只需要在代碼里動態(tài)的把課程清除掉就可以,所以這個時候前端的開發(fā)可以動態(tài)改變前端的內(nèi)容映屋,可以通過JavaScript
代碼更新界面苟鸯,或者一些框架,這樣就產(chǎn)生了一個問題就像之前這樣看似點擊刪除按鈕棚点,點擊確定好像界面只少了一個課程早处,但實際上有的框架就不是簡單的把這一個元素刪了,他有可能把整個表格獲取一次重新產(chǎn)生了瘫析,重新產(chǎn)生意思是原來是4條記錄現(xiàn)在重新產(chǎn)生了眼睛看起來就少了一條ji記錄砌梆,實際上頁面上所有的元素都重新創(chuàng)建了一遍,這就帶來我們刪除一門課程之后導(dǎo)致現(xiàn)在界面剩下來3個刪除按鈕已經(jīng)不是剛才4個中的3個了贬循,就是這個原因?qū)е碌南贪覀兛梢赃@樣既然你之后界面刷新了那我們每次刪除之后就重新獲取當前界面的元素就可以了
from selenium import webdriver
import time
driver = webdriver.Chrome()
driver.implicitly_wait(5)
driver.get('http://localhost/mgr/login/login.html')
driver.find_element_by_id('username').send_keys('auto')
driver.find_element_by_id('password').send_keys('sdfsdfsdf')
driver.find_element_by_tag_name('button').click()
time.sleep(1)
driver.implicitly_wait(1)
while True:
#找刪除按鈕
delButtons = driver.find_elements_by_css_selector(
'*[ng-click^=delOne]')
#判斷有沒有刪除按鈕
if delButtons == []:
break
#如果有就找到第一個元素,點擊他
delButtons[0].click()
#點確定
driver.find_element_by_css_selector('.modal-footer .btn-primary').click()
time.sleep(1)
driver.implicitly_wait(5)
這樣就沒有問題杖虾,因為我們每次刪除按鈕都會重新獲取當前頁面烂瘫,大家會不會有個疑惑循環(huán)前有個implicitly_wait(1)
循環(huán)后又把implicitly_wait(1)
改成implicitly_wait(5)
呢,主要是因為循環(huán)刪除總有一次刪光了,刪光了最后一次循環(huán)執(zhí)行delButtons = driver.find_elements_by_css_selector('*[ng-click^=delOne]')
的時候坟比,因為刪光了就沒有元素芦鳍,就會等待全局的等待時間比如5秒,就會等待5秒葛账,臨時的把時間改短了點這樣比較好柠衅。這里的time.sleep(1)
很重要,因為你點擊確定刪除的時候就會執(zhí)行刪除操作籍琳,服務(wù)端就會刪除數(shù)據(jù)菲宴,界面刷新會花一段時間,如果沒有sleep(1)
就會立即獲取頁面趋急,就會獲取到?jīng)]有更新的頁面元素
看一個練習(xí):
Selenium 作業(yè) 6
作業(yè)1
登錄華為官網(wǎng) https://www.vmall.com/喝峦,
點擊 "華為官網(wǎng)" 鏈接
查 "華為官網(wǎng)" 頁面上是否 有如下主菜單
智能手機
筆記本
平板
穿戴設(shè)備
智能家居
更多產(chǎn)品
軟件應(yīng)用
服務(wù)與支持
最后再回到主窗口, 檢查鼠標停留在 "筆記本&平板" 處的時候宣谈, 是否顯示的菜單有
"平板電腦 筆記本電腦 筆記本配件"
怎么模擬鼠標停留事件愈犹,請大家自行網(wǎng)上搜索,看看能不能自己解決問題闻丑。
from selenium import webdriver
import time
from selenium.webdriver import ActionChains
driver = webdriver.Chrome('E:\ChromDriver\chromdriver2.43\chromedriver.exe')
driver.get('https://www.vmall.com/')
driver.implicitly_wait(10)
# print(driver.title)
#主窗口handle
main_window=driver.current_window_handle
#點擊進入華為官網(wǎng)
driver.find_element_by_css_selector('a[).click()
for handle in driver.window_handles:
driver.switch_to.window(handle)
if '華為消費者業(yè)務(wù)官網(wǎng)' in driver.title:
# print(handle)
break
#找到主菜單
orders_eles = driver.find_elements_by_css_selector('ul.clearfix.nav-cnt a.a-common.products-name')
orders_txt = [ele.text for ele in orders_eles]
expect_orders='''智能手機
筆記本
平板
穿戴設(shè)備
智能家居
更多產(chǎn)品
軟件應(yīng)用
服務(wù)與支持
'''
expect_text = [order.strip() for order in expect_orders.split('\n')]
if orders_txt == expect_text:
print('匹配菜單成功')
else:
print('匹配失敗')
# print(orders_txt)
# print(expect_text)
#回到主頁面
driver.switch_to.window(main_window)
# print(driver.title)
#鼠標停留在筆記本菜單
ele = driver.find_element_by_id('zxnav_1')
ActionChains(driver).move_to_element(ele).perform()
#檢查菜單項
css='li#zxnav_1 div.category-panels.category-panels-1 span'
orders = driver.find_elements_by_css_selector(css)
order_text = [order.text for order in orders]
# print(order_txt)
expect_txt = u'''平板電腦|筆記本電腦|筆記本配件'''
order_txt='|'.join(order_text)
if expect_txt == order_txt:
print('匹配菜單成功')
else:
print('匹配失敗')
print(expect_txt)
print(order_txt)
driver.quit()
作業(yè)2
寫一個程序?qū)崿F(xiàn)如下的自動化過程
- 登錄 https://tinypng.com/
- 點擊 上傳文件的虛線框
- 選擇 插圖,在本地目錄中選擇一張準備好的圖片 , 查看是否能夠上傳圖片成功
from selenium import webdriver
import time
driver = webdriver.Chrome('E:\ChromDriver\chromdriver2.43\chromedriver.exe')
driver.implicitly_wait(10)
driver.get('https://tinypng.com/')
print(driver.title)
#點擊上傳圖標
driver.find_element_by_css_selector("figure.icon").click()
# 直接發(fā)送鍵盤消息給 當前應(yīng)用程序勋颖,
# 前提是瀏覽器必須是當前應(yīng)用
# pip install pypiwin32
import win32com.client
shell = win32com.client.Dispatch("WScript.Shell")
# 有的系統(tǒng)要加 '\r'
# 有的系統(tǒng)要加 '\r\n'
img_name='1.jpg'
shell.Sendkeys('e:\\' + img_name + '\n'+ '\n')#在當前的焦點應(yīng)用程序發(fā)送一個字符串
time.sleep(3)
file_ele = driver.find_element_by_css_selector('div.before:nth-of-type(1)')
print(file_ele.text)
file_name = file_ele.text.split('\n')[1]
if img_name.upper() == file_name.upper():
print('上傳成功')
else:
print('上傳失敗')
input('...')
driver.quit()