摘要:耗時(shí)代碼運(yùn)行到這句之后觸發(fā)隱式等待,在輪詢檢查后仍然沒(méi)有定位到元素,拋出異常。耗時(shí)值得一提的是,對(duì)于定位不到元素的時(shí)候,從耗時(shí)方面隱式等待和強(qiáng)制等待沒(méi)什么區(qū)別。
? 系列內(nèi)容 ?
爬蟲+自動(dòng)化利器 selenium 之自學(xué)成才篇(一)
主要內(nèi)容:selenium 簡(jiǎn)介、selenium 安裝、安裝瀏覽器驅(qū)動(dòng)、8 種方式定位頁(yè)面元素、瀏覽器控制、鼠標(biāo)控制、鍵盤控制
爬蟲+自動(dòng)化利器 selenium 之自學(xué)成才篇(二)
主要內(nèi)容:三種等待方式(顯式等待、隱式等待、強(qiáng)制等待)、一組元素的定位方式、切換操作(窗口切換、表單切換)、彈窗處理等。
爬蟲+自動(dòng)化利器 selenium 之自學(xué)成才篇(三)
主要內(nèi)容:文件上傳 & 下載、cookie 操作、調(diào)用 JavaScript(滑動(dòng)滾動(dòng)條)、關(guān)閉操作、頁(yè)面截圖等。
很多頁(yè)面都使用 ajax
技術(shù),頁(yè)面的元素不是同時(shí)被加載出來(lái)的,為了防止定位這些尚在加載的元素報(bào)錯(cuò),可以設(shè)置元素等來(lái)增加腳本的穩(wěn)定性。webdriver
中的等待分為 顯式等待 和 隱式等待。
顯式等待:設(shè)置一個(gè)超時(shí)時(shí)間,每個(gè)一段時(shí)間就去檢測(cè)一次該元素是否存在,如果存在則執(zhí)行后續(xù)內(nèi)容,如果超過(guò)最大時(shí)間(超時(shí)時(shí)間)則拋出超時(shí)異常(TimeoutException
)。顯示等待需要使用 WebDriverWait
,同時(shí)配合 until
或 not until
。下面詳細(xì)講解一下。
WebDriverWait(driver, timeout, poll_frequency=0.5, ignored_exceptions=None)
driver
:瀏覽器驅(qū)動(dòng)timeout
:超時(shí)時(shí)間,單位秒poll_frequency
:每次檢測(cè)的間隔時(shí)間,默認(rèn)為0.5秒ignored_exceptions
:指定忽略的異常,如果在調(diào)用 until
或 until_not
的過(guò)程中拋出指定忽略的異常,則不中斷代碼,默認(rèn)忽略的只有 NoSuchElementException
。until(method, message=’ ‘)
until_not(method, message=’ ")
method
:指定預(yù)期條件的判斷方法,在等待期間,每隔一段時(shí)間調(diào)用該方法,判斷元素是否存在,直到元素出現(xiàn)。until_not
正好相反,當(dāng)元素消失或指定條件不成立,則繼續(xù)執(zhí)行后續(xù)代碼message
: 如果超時(shí),拋出 TimeoutException
,并顯示 message
中的內(nèi)容method
中的預(yù)期條件判斷方法是由 expected_conditions
提供,下面列舉常用方法。
先定義一個(gè)定位器
from selenium.webdriver.common.by import Byfrom selenium import webdriverdriver = webdriver.Chrome()locator = (By.ID, "kw")element = driver.find_element_by_id("kw")
方法 | 描述 |
---|---|
title_is(‘百度一下’) | 判斷當(dāng)前頁(yè)面的 title 是否等于預(yù)期 |
title_contains(‘百度’) | 判斷當(dāng)前頁(yè)面的 title 是否包含預(yù)期字符串 |
presence_of_element_located(locator) | 判斷元素是否被加到了 dom 樹里,并不代表該元素一定可見 |
visibility_of_element_located(locator) | 判斷元素是否可見,可見代表元素非隱藏,并且元素的寬和高都不等于0 |
visibility_of(element) | 跟上一個(gè)方法作用相同,但傳入?yún)?shù)為 element |
text_to_be_present_in_element(locator , ‘百度’) | 判斷元素中的 text 是否包含了預(yù)期的字符串 |
text_to_be_present_in_element_value(locator , ‘某值’) | 判斷元素中的 value 屬性是否包含了預(yù)期的字符串 |
frame_to_be_available_and_switch_to_it(locator) | 判斷該 frame 是否可以 switch 進(jìn)去,True 則 switch 進(jìn)去,反之 False |
invisibility_of_element_located(locator) | 判斷元素中是否不存在于 dom 樹或不可見 |
element_to_be_clickable(locator) | 判斷元素中是否可見并且是可點(diǎn)擊的 |
staleness_of(element) | 等待元素從 dom 樹中移除 |
element_to_be_selected(element) | 判斷元素是否被選中,一般用在下拉列表 |
element_selection_state_to_be(element, True) | 判斷元素的選中狀態(tài)是否符合預(yù)期,參數(shù) element,第二個(gè)參數(shù)為 True/False |
element_located_selection_state_to_be(locator, True) | 跟上一個(gè)方法作用相同,但傳入?yún)?shù)為 locator |
alert_is_present() | 判斷頁(yè)面上是否存在 alert |
下面寫一個(gè)簡(jiǎn)單的例子,這里定位一個(gè)頁(yè)面不存在的元素,拋出的異常信息正是我們指定的內(nèi)容。
from selenium import webdriverfrom selenium.webdriver.support.ui import WebDriverWaitfrom selenium.webdriver.support import expected_conditions as ECfrom selenium.webdriver.common.by import Bydriver = webdriver.Chrome()element = WebDriverWait(driver, 5, 0.5).until( EC.presence_of_element_located((By.ID, "kw")), message="超時(shí)啦!")
隱式等待也是指定一個(gè)超時(shí)時(shí)間,如果超出這個(gè)時(shí)間指定元素還沒(méi)有被加載出來(lái),就會(huì)拋出 NoSuchElementException
異常。
除了拋出的異常不同外,還有一點(diǎn),隱式等待是全局性的,即運(yùn)行過(guò)程中,如果元素可以定位到,它不會(huì)影響代碼運(yùn)行,但如果定位不到,則它會(huì)以輪詢的方式不斷地訪問(wèn)元素直到元素被找到,若超過(guò)指定時(shí)間,則拋出異常。
使用 implicitly_wait()
來(lái)實(shí)現(xiàn)隱式等待,使用難度相對(duì)于顯式等待要簡(jiǎn)單很多。
示例:打開個(gè)人主頁(yè),設(shè)置一個(gè)隱式等待時(shí)間 5s,通過(guò) id
定位一個(gè)不存在的元素,最后打印 拋出的異常 與 運(yùn)行時(shí)間。
from selenium import webdriverfrom time import timedriver = webdriver.Chrome()driver.get("https://blog.csdn.net/qq_43965708")start = time()driver.implicitly_wait(5)try: driver.find_element_by_id("kw")except Exception as e: print(e) print(f"耗時(shí):{time()-start}")
代碼運(yùn)行到 driver.find_element_by_id("kw")
這句之后觸發(fā)隱式等待,在輪詢檢查 5s 后仍然沒(méi)有定位到元素,拋出異常。
使用 time.sleep()
強(qiáng)制等待,設(shè)置固定的休眠時(shí)間,對(duì)于代碼的運(yùn)行效率會(huì)有影響。以上面的例子作為參照,將 隱式等待 改為 強(qiáng)制等待。
from selenium import webdriverfrom time import time, sleepdriver = webdriver.Chrome()driver.get("https://blog.csdn.net/qq_43965708")start = time()sleep(5)try: driver.find_element_by_id("kw")except Exception as e: print(e) print(f"耗時(shí):{time()-start}")
值得一提的是,對(duì)于定位不到元素的時(shí)候,從耗時(shí)方面隱式等待和強(qiáng)制等待沒(méi)什么區(qū)別。但如果元素經(jīng)過(guò) 2s 后被加載出來(lái),這時(shí)隱式等待就會(huì)繼續(xù)執(zhí)行下面的代碼,但 sleep還要繼續(xù)等待 3s。
上篇講述了定位一個(gè)元素的 8 種方法,定位一組元素使用的方法只需要將 element
改為 elements
即可,它的使用場(chǎng)景一般是為了批量操作元素。
find_elements_by_id()
find_elements_by_name()
find_elements_by_class_name()
find_elements_by_tag_name()
find_elements_by_xpath()
find_elements_by_css_selector()
find_elements_by_link_text()
find_elements_by_partial_link_text()
這里以 CSDN 首頁(yè)的一個(gè) 博客專家欄 為例。
下面使用 find_elements_by_xpath
來(lái)定位三位專家的名稱。
這是專家名稱部分的頁(yè)面代碼,不知各位有沒(méi)有想到如何通過(guò) xpath
定位這一組專家的名稱呢?
from selenium import webdriver# 設(shè)置無(wú)頭瀏覽器option = webdriver.ChromeOptions()option.add_argument("--headless")driver = webdriver.Chrome(options=option)driver.get("https://blog.csdn.net/")p_list = driver.find_elements_by_xpath("http://p[@class="name"]")name = [p.text for p in p_list]name
在 selenium
操作頁(yè)面的時(shí)候,可能會(huì)因?yàn)辄c(diǎn)擊某個(gè)鏈接而跳轉(zhuǎn)到一個(gè)新的頁(yè)面(打開了一個(gè)新標(biāo)簽頁(yè)),這時(shí)候 selenium
實(shí)際還是處于上一個(gè)頁(yè)面的,需要我們進(jìn)行切換才能夠定位最新頁(yè)面上的元素。
窗口切換需要使用 switch_to.windows()
方法。
首先我們先看看下面的代碼。
代碼流程:先進(jìn)入 【CSDN首頁(yè)】,保存當(dāng)前頁(yè)面的句柄,然后再點(diǎn)擊左側(cè) 【CSDN官方博客】跳轉(zhuǎn)進(jìn)入新的標(biāo)簽頁(yè),再次保存頁(yè)面的句柄,我們驗(yàn)證一下 selenium
會(huì)不會(huì)自動(dòng)定位到新打開的窗口。
from selenium import webdriverhandles = []driver = webdriver.Chrome()driver.get("https://blog.csdn.net/")# 設(shè)置隱式等待driver.implicitly_wait(3)# 獲取當(dāng)前窗口的句柄handles.append(driver.current_window_handle)# 點(diǎn)擊 python,進(jìn)入分類頁(yè)面driver.find_element_by_xpath("http://*[@id="mainContent"]/aside/div[1]/div").click()# 獲取當(dāng)前窗口的句柄handles.append(driver.current_window_handle)print(handles)# 獲取當(dāng)前所有窗口的句柄print(driver.window_handles)
可以看到第一個(gè)列表 handle
是相同的,說(shuō)明 selenium
實(shí)際操作的還是 CSDN首頁(yè) ,并未切換到新頁(yè)面。
下面使用 switch_to.windows()
進(jìn)行切換。
from selenium import webdriverhandles = []driver = webdriver.Chrome()driver.get("https://blog.csdn.net/")# 設(shè)置隱式等待driver.implicitly_wait(3)# 獲取當(dāng)前窗口的句柄handles.append(driver.current_window_handle)# 點(diǎn)擊 python,進(jìn)入分類頁(yè)面driver.find_element_by_xpath("http://*[@id="mainContent"]/aside/div[1]/div").click()# 切換窗口driver.switch_to.window(driver.window_handles[-1])# 獲取當(dāng)前窗口的句柄handles.append(driver.current_window_handle)print(handles)print(driver.window_handles)
上面代碼在點(diǎn)擊跳轉(zhuǎn)后,使用 switch_to
切換窗口,window_handles
返回的 handle
列表是按照頁(yè)面出現(xiàn)時(shí)間進(jìn)行排序的,最新打開的頁(yè)面肯定是最后一個(gè),這樣用 driver.window_handles[-1]
+ switch_to
即可跳轉(zhuǎn)到最新打開的頁(yè)面了。
那如果打開的窗口有多個(gè),如何跳轉(zhuǎn)到之前打開的窗口,如果確實(shí)有這個(gè)需求,那么打開窗口是就需要記錄每一個(gè)窗口的 key
(別名) 與 value
(handle
),保存到字典中,后續(xù)根據(jù) key
來(lái)取 handle
。
很多頁(yè)面也會(huì)用帶 frame/iframe
表單嵌套,對(duì)于這種內(nèi)嵌的頁(yè)面 selenium
是無(wú)法直接定位的,需要使用 switch_to.frame()
方法將當(dāng)前操作的對(duì)象切換成 frame/iframe
內(nèi)嵌的頁(yè)面。
switch_to.frame()
默認(rèn)可以用的 id
或 name
屬性直接定位,但如果 iframe
沒(méi)有 id
或 name
,這時(shí)就需要使用 xpath
進(jìn)行定位。下面先寫一個(gè)包含 iframe
的頁(yè)面做測(cè)試用。
DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Documenttitle> <style> div p { color: #red; animation: change 2s infinite; } @keyframes change { from { color: red; } to { color: blue; } } style>head><body> <div> <p>公眾號(hào):Python新視野p> <p>CSDN:Dream丶Killerp> <p>微信:python-sunp> div> <iframe src="https://blog.csdn.net/qq_43965708" width="400" height="200">iframe>body>html>
現(xiàn)在我們定位紅框中的 CSDN 按鈕,可以跳轉(zhuǎn)到 CSDN 首頁(yè)。
from selenium import webdriverfrom pathlib import Pathdriver = webdriver.Chrome()# 讀取本地html文件driver.get("file:///" + str(Path(Path.cwd(), "iframe測(cè)試.html")))# 1.通過(guò)id定位driver.switch_to.frame("CSDN_info")# 2.通過(guò)name定位# driver.switch_to.frame("Dream丶Killer")# 通過(guò)xpath定位# 3.iframe_label = driver.find_element_by_xpath("/html/body/iframe")# driver.switch_to.frame(iframe_label)driver.find_element_by_xpath("http://*[@id="csdn-toolbar"]/div/div/div[1]/div/a/img").click()
這里列舉了三種定位方式,都可以定位 iframe
。
JavaScript
有三種彈窗 alert
(確認(rèn))、confirm
(確認(rèn)、取消)、prompt
(文本框、確認(rèn)、取消)。
處理方式:先定位(switch_to.alert
自動(dòng)獲取當(dāng)前彈窗),再使用 text
、accept
、dismiss
、send_keys
等方法進(jìn)行操作
方法 | 描述 |
---|---|
text | 獲取彈窗中的文字 |
accept | 接受(確認(rèn))彈窗內(nèi)容 |
dismiss | 解除(取消)彈窗 |
send_keys | 發(fā)送文本至警告框 |
這里寫一個(gè)簡(jiǎn)單的測(cè)試頁(yè)面,其中包含三個(gè)按鈕,分別對(duì)應(yīng)三個(gè)彈窗。
DOCTYPE html><html lang="en"><head>head><body> <button id="alert">alertbutton> <button id="confirm">confirmbutton> <button id="prompt">promptbutton> <script type="text/javascript"> const dom1 = document.getElementById("alert") dom1.addEventListener("click", function(){ alert("alert hello") }) const dom2 = document.getElementById("confirm") dom2.addEventListener("click", function(){ confirm("confirm hello") }) const dom3 = document.getElementById("prompt") dom3.addEventListener("click", function(){ prompt("prompt hello") }) script>body>html>
下面使用上面的方法進(jìn)行測(cè)試。為了防止彈窗操作過(guò)快,每次操作彈窗,都使用 sleep
強(qiáng)制等待一段時(shí)間。
from selenium import webdriverfrom pathlib import Pathfrom time import sleepdriver = webdriver.Firefox()driver.get("file:///" + str(Path(Path.cwd(), "彈窗.html")))sleep(2)# 點(diǎn)擊alert按鈕driver.find_element_by_xpath("http://*[@id="alert"]").click()sleep(1)alert = driver.switch_to.alert# 打印alert彈窗的文本print(alert.text)# 確認(rèn)alert.accept()sleep(2)# 點(diǎn)擊confirm按鈕driver.find_element_by_xpath("http://*[@id="confirm"]").click()sleep(1)confirm = driver.switch_to.alertprint(confirm.text)# 取消confirm.dismiss()sleep(2)# 點(diǎn)擊confirm按鈕driver.find_element_by_xpath("http://*[@id="prompt"]").click()sleep(1)prompt = driver.switch_to.alertprint(prompt.text)# 向prompt的輸入框中傳入文本prompt.send_keys("Dream丶Killer")sleep(2)prompt.accept()"""輸出alert helloconfirm helloprompt hello"""
注:細(xì)心地讀者應(yīng)該會(huì)發(fā)現(xiàn)這次操作的瀏覽器是
Firefox
,為什么不用Chrome
呢?原因是測(cè)試時(shí)發(fā)現(xiàn)執(zhí)行prompt
的send_keys
時(shí),不能將文本填入輸入框。嘗試了各種方法并查看源碼后確認(rèn)不是代碼的問(wèn)題,之后通過(guò)其他渠道得知原因可能是Chrome
的版本與selenium
版本的問(wèn)題,但也沒(méi)有很方便的解決方案,因此沒(méi)有繼續(xù)深究,改用Firefox
可成功運(yùn)行。這里記錄一下我的Chrome
版本,如果有大佬懂得如何在Chrome
上解決這個(gè)問(wèn)題,請(qǐng)?jiān)谠u(píng)論區(qū)指導(dǎo)一下,提前感謝!
selenium:3.141.0
Chrome:94.0.4606.71
未完待續(xù)~
??往期精彩,不容錯(cuò)過(guò)??
總結(jié)篇
??兩萬(wàn)字,50個(gè)pandas高頻操作【圖文并茂,值得收藏】??
??吐血總結(jié)《Mysql從入門到入魔》,圖文并茂(建議收藏)??
工具篇
??Python實(shí)用小工具之制作酷炫二維碼(有界面、附源碼)??
??Python實(shí)用工具之制作證件照(有界面、附源碼)??
??女朋友桌面文件雜亂無(wú)章?氣得我用Python給她做了一個(gè)文件整理工具??
更多有趣的文章及干貨,盡在
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/122012.html
文章目錄 selenium 簡(jiǎn)介selenium安裝安裝瀏覽器驅(qū)動(dòng)確定瀏覽器版本下載驅(qū)動(dòng) 定位頁(yè)面元素打開指定頁(yè)面id 定位name 定位class 定位tag 定位xpath 定位css 定位link 定位partial_link 定位 瀏覽器控制修改瀏覽器窗口大小瀏覽器前進(jìn)&后退瀏覽器刷新瀏覽器窗口切換常見操作 鼠標(biāo)控制單擊左鍵單擊右鍵雙擊拖動(dòng)鼠標(biāo)懸停 鍵盤控制 seleni...
摘要:楚江數(shù)據(jù)是專業(yè)的互聯(lián)網(wǎng)數(shù)據(jù)技術(shù)服務(wù),現(xiàn)整理出零基礎(chǔ)如何學(xué)爬蟲技術(shù)以供學(xué)習(xí),。本文來(lái)源知乎作者路人甲鏈接楚江數(shù)據(jù)提供網(wǎng)站數(shù)據(jù)采集和爬蟲軟件定制開發(fā)服務(wù),服務(wù)范圍涵蓋社交網(wǎng)絡(luò)電子商務(wù)分類信息學(xué)術(shù)研究等。 楚江數(shù)據(jù)是專業(yè)的互聯(lián)網(wǎng)數(shù)據(jù)技術(shù)服務(wù),現(xiàn)整理出零基礎(chǔ)如何學(xué)爬蟲技術(shù)以供學(xué)習(xí),http://www.chujiangdata.com。 第一:Python爬蟲學(xué)習(xí)系列教程(來(lái)源于某博主:htt...
摘要:時(shí)間永遠(yuǎn)都過(guò)得那么快,一晃從年注冊(cè),到現(xiàn)在已經(jīng)過(guò)去了年那些被我藏在收藏夾吃灰的文章,已經(jīng)太多了,是時(shí)候把他們整理一下了。那是因?yàn)槭詹貖A太亂,橡皮擦給設(shè)置私密了,不收拾不好看呀。 ...
摘要:軟件測(cè)試江湖二神兵利器篇在上一篇文章中我們介紹了江湖上流傳的各種軟件測(cè)試的武功秘籍和心法,相信看過(guò)的小伙伴內(nèi)力得到了很大的提升。功能測(cè)試篇功能測(cè)試,是軟件測(cè)試?yán)锏娜腴T級(jí)心法,自然也有與之相對(duì)應(yīng)的兵器來(lái)發(fā)揮心法的最大功力。 軟件測(cè)試江湖(二)神兵利器篇 在上一篇文章中我們介紹了江湖上流傳的各種軟件測(cè)試的武功秘籍和心法,相信看過(guò)的小伙伴內(nèi)力得到了很大的提升。如果沒(méi)有,一定是你看的姿勢(shì)不對(duì),...
摘要:軟件測(cè)試江湖二神兵利器篇在上一篇文章中我們介紹了江湖上流傳的各種軟件測(cè)試的武功秘籍和心法,相信看過(guò)的小伙伴內(nèi)力得到了很大的提升。功能測(cè)試篇功能測(cè)試,是軟件測(cè)試?yán)锏娜腴T級(jí)心法,自然也有與之相對(duì)應(yīng)的兵器來(lái)發(fā)揮心法的最大功力。 軟件測(cè)試江湖(二)神兵利器篇 在上一篇文章中我們介紹了江湖上流傳的各種軟件測(cè)試的武功秘籍和心法,相信看過(guò)的小伙伴內(nèi)力得到了很大的提升。如果沒(méi)有,一定是你看的姿勢(shì)不對(duì),...
閱讀 2760·2021-10-09 09:44
閱讀 3562·2019-08-30 15:54
閱讀 2172·2019-08-30 14:16
閱讀 2803·2019-08-30 13:09
閱讀 835·2019-08-30 13:08
閱讀 1296·2019-08-29 16:29
閱讀 1683·2019-08-26 13:57
閱讀 1941·2019-08-26 13:53