解決Selenium彈出新頁面無法定位元素問題(Unable to locate element)


Python 2.7
IDE Pycharm 5.0.3

環境細節詳見Python+Selenium+PIL+Tesseract真正自動識別驗證碼進行一鍵登錄

對於同一頁面無法定位元素問題請見姊妹篇解決網頁元素無法定位(NoSuchElementException: Unable to locate element)的幾種方法


 只解決一個問題--NoSuchElementException: Message: Unable to locate element

問題來源

在上一篇博客中,我進行了自動化登錄,之后我想直接進行對圖書的續約操作,但是利用元素定位的方法,怎么都找不到元素,我一直以為是我的規則用的不 對,導致元素找不到,其實,只是窗口句柄還停留在上一個頁面而已!對於新彈出的頁面還沒有定位!!!那怎么可能找得到在新頁面的元素呢!!這是新手(我) 犯下最大的錯誤,只顧於對元素方法的定位,卻沒有意識到頁面發生跳轉后的handles的變化。


解決方案

窗口重定位,感謝@一朵菊花向陽開——python + selenium webdriver 從主窗口A跳轉至主窗口B后,無法定位窗口B的元素的問題 讓我找到解決方案,最終得以實現句柄的重定位!


(這段可跳過,因為百度太不穩定了,測試結果有差別)
這里寫圖片描述
但話說到這的時候,我很疑惑一篇文章 python+selenuim webdriver 頁面跳轉后如何定位元素,他的方法我進行測試時不可行的,請看測試;

他的代碼:我一行沒動進行測試

#coding=utf-8

from selenium import webdriver
import time

browser=webdriver.Firefox()

browser.get("http://www.baidu.com")
browser.find_element_by_id("kw").send_keys("selenium")
browser.find_element_by_id("su").click()
time.sleep(3)
sreach_window=browser.current_window_handle  //此行代碼用來定位當前頁面

browser.find_element_by_xpath("/html/body/div[3]/div[4]/div/div[3]/div[4]/h3/a").click()
time.sleep(5)

 

當然如果我一點都不改,也是進行不了測試的,這位大哥把注釋符號寫錯了,不是//,而是#啊大哥
ok,然后運行下:出錯了
這里寫圖片描述
所以我感到好奇的是,這位大哥到底有沒有跑過這段代碼,看着原創的樣子應該沒有抄襲才對啊,那應該是測試過代碼才對,但是可重復性在哪?最后發現需要修改http成這樣才能訪問(大哥少加個/):
browser.get("https://www.baidu.com/")修改后代碼如下:

#coding=utf-8

from selenium import webdriver
import time

browser=webdriver.Firefox()

browser.get("https://www.baidu.com/")
browser.find_element_by_id("kw").send_keys("selenium")
browser.find_element_by_id("su").click()
time.sleep(1)
sreach_window=browser.current_window_handle #此行代碼用來定位當前頁面
time.sleep(2)
browser.find_element_by_xpath("/html/body/div[3]/div[3]/div/div[3]/div[4]/h3/a").click()#我這里修改了一下div[4],大哥的索引直接到有道翻譯了,不利於下一步測試
time.sleep(1)

 

 

 

ok,這次能正常索引到值,但是!!!我要說的是但是!!!
這根本沒有跳轉頁面!還是在同一個頁面進行操作的!如果我把大哥的代碼改成:
在我測試的時候,發生了奇怪的事情,同樣的代碼,有時候能跑有時候拋出錯誤,我已設定休眠時間,難道是我頻繁訪問導致百度封我?剛才上述的代碼我都實際測 試過的,但是現在又不能用了–wtf–,所以。我換了穩定的引擎,我采用bing搜索來試試,上面的全部作廢,如果有人知道問題出在哪,請留言
這里寫圖片描述


7.19補充

應該是搜索引擎熱點的問題,每次鍵入相同的值可能搜索結果首項會不一致的,百度可能更新熱點比較快把,所以出現了我所謂不穩定的情況


正題測試

這里寫圖片描述
我和上述那位大哥不同的觀點在於,他用的sreach_window=browser.current_window_handle方法並不能實現對新窗口句柄的捕捉,我以bing主頁為測試頁,重新構造了一下,

#coding=utf-8
from selenium import webdriver
import time

browser=webdriver.Firefox()
browser.get("http://cn.bing.com/")
keywords = 'MrLevo520 CSDN'
send_keywords=keywords.decode('utf-8')#中英混輸入可防止亂碼
browser.find_element_by_id("sb_form_q").send_keys(send_keywords)

time.sleep(1)
#----------操作一:進行對關鍵字MrLevo520 CSDN搜索----------------
browser.find_element_by_id("sb_form_go").click()#執行此操作會進行搜索,但是沒有彈出新窗口,所以句柄不用重定位
time.sleep(3)
#----------操作二:對搜索頁面"我的CSDN"進行點擊操作--------------
browser.find_element_by_xpath("/html/body/div/ol/li/h2/a").click()#進行當前頁面點擊第一項

#--------操作三:對新彈出的頁面再點擊"貢獻的資源"選項-----
sreach_window=browser.current_window_handle
browser.find_element_by_xpath("/html/body/div[3]/div[2]/div[2]/div/a[3]").click()

time.sleep(5)

 

瀏覽器運行結果只到如圖:
這里寫圖片描述

而且拋出錯誤:

selenium.common.exceptions.NoSuchElementException: Message: Unable to locate element: {"method":"xpath","selector":"/html/body/div[3]/div[2]/div[2]/div/a[3]"}

 

 

可見,此語句並沒有實現句柄重定位的功能,然后我再試試下面的方法,所有語句不變,只改變獲取當前句柄的語句,改成

browser.switch_to_window(browser.window_handles[1])
 

最后程序應該是這樣:

#coding=utf-8
from selenium import webdriver
import time

browser=webdriver.Firefox()
browser.get("http://cn.bing.com/")
keywords = 'MrLevo520 CSDN'
send_keywords=keywords.decode('utf-8')#中英混輸入可防止亂碼
browser.find_element_by_id("sb_form_q").send_keys(send_keywords)

time.sleep(1)
#----------操作一:進行對關鍵字MrLevo520 CSDN搜索----------------
browser.find_element_by_id("sb_form_go").click()#執行此操作會進行搜索,但是沒有彈出新窗口,所以句柄不用重定位
time.sleep(3)
#----------操作二:對搜索頁面"我的CSDN"進行點擊操作--------------
browser.find_element_by_xpath("/html/body/div/ol/li/h2/a").click()#進行當前頁面點擊第一項

#--------操作三:對新彈出的頁面再點擊"貢獻的資源"選項-----
browser.switch_to_window(browser.window_handles[1])
browser.find_element_by_xpath("/html/body/div[3]/div[2]/div[2]/div/a[3]").click()

time.sleep(5)

最后結果,按照我的思路,進行了相應的點擊,最后如圖

這里寫圖片描述

所以從上述的例子上來說,語句sreach_window=browser.current_window_handle並沒有實現重定位,可能我才疏學淺,但至少,在上述的那位大哥的博客中,寫的是錯誤的,運行失敗,我對2016.7.16的所有數據負責,實際測試失敗。



7.17-補充:另一種獲取句柄方法

還有另一種方法,就是直接定位當前最新彈出的窗口。代碼是這樣的

for handle in browser.window_handles:#方法二,始終獲得當前最后的窗口,所以多要多次使用
    browser.switch_to_window(handle)

 

那么結合到我的代碼中那就是這樣的:

 1 #Author:哈士奇說喵
 2 #因為搜索引擎檢索項根據熱度來排名,所以我只能對7.17的數據進行測試和負責,大家測試時候注意元素變化
 3 #coding=utf-8
 4 from selenium import webdriver
 5 import time
 6 
 7 browser=webdriver.Firefox()
 8 browser.get("http://cn.bing.com/")
 9 keywords = 'MrLevo520 CSDN'
10 send_keywords=keywords.decode('utf-8')#中英混輸入可防止亂碼
11 browser.find_element_by_id("sb_form_q").send_keys(send_keywords)
12 
13 time.sleep(1)
14 #----------操作一:進行對關鍵字MrLevo520 CSDN搜索----------------
15 browser.find_element_by_id("sb_form_go").click()#執行此操作會進行搜索,但是沒有彈出新窗口,所以句柄不用重定位
16 time.sleep(3)
17 #----------操作二:對搜索頁面第一項進行點擊操作--------------
18 browser.find_element_by_xpath("/html/body/div/ol/li/h2/a").click()#進行當前頁面點擊第一項
19 
20 #--------操作三:對新彈出的頁面再點擊"我的頭像"選項-----
21 #注意此時已經是彈出的第一個窗口了,需要重新定位句柄
22 '''browser.switch_to_window(browser.window_handles[1])#方法一'''
23 for handle in browser.window_handles:#方法二,始終獲得當前最后的窗口
24     browser.switch_to_window(handle)
25 
26 browser.find_element_by_xpath("//div[@id='body']/div[2]/div/div/ul[2]/div/a").click()
27 
28 #------------------操作四:點擊"貢獻的資源"-------------------
29 #注意此時已經是新彈出的第二個窗口了,需要重新定位句柄
30 browser.switch_to_window(browser.window_handles[2])#方法一,注意window_handles[2]變成了2
31 '''for handle in browser.window_handles:#方法二,始終獲得當前最后的窗口
32     browser.switch_to_window(handle)'''
33 
34 browser.find_element_by_xpath("/html/body/div[3]/div[2]/div[2]/div/a[3]").click()
35 
36 time.sleep(5)

 

上面的代碼,我要說幾點,總共實現完成會存在三個瀏覽器窗口,也就是相當於實現了兩次句柄重定位功能,也就是下面的圖片,對bing搜索 “MrLevo520 CSDN”跳出的最熱項,也就是這一篇(感謝大家厚愛),但是昨天最熱彈出來的是直接是我的主頁,大家從上面的動圖應該也可以看出來,所以等你測試這段代 碼的時候,可能最熱項目又變化了,道理大家懂就ok,不影響重抓句柄代碼。

這里寫圖片描述

代碼實現了從1,到2,點擊頭像后,再跳轉到3主頁,之后再點擊”貢獻資源”,實現的動圖如下:

這里寫圖片描述

Pay Attention

1.搜索引擎根據熱度來排名,也就是代碼具有”不穩定性”,應該根據自己實際情況,定位不同元素,我只對當前編輯時間的數據負責

2.在實際操作過程中,會產生第一個頁面還沒等第二個頁面緩沖完,直接又”占領”主視覺的問題,別擔心,句柄還是在傳遞的,程序一直在跑,而且沒有出錯,過一會時間就會更新加載頁面的,如果想要關閉無關頁面,請看這篇博客 基於Selenium一鍵寫CSDN博客

3.可能我的代碼第一次獲取句柄和第二次獲取句柄不一樣的方法,這是為了展示,你可以兩次句柄獲取都用方法二,也可以都是用方法一,但是方法一注意修改標號。


方法一 VS 方法二

相比較於方法二,方法一的優點在於后續操作,比如關閉第幾個窗口,句柄傳遞是按照順序來的。缺點在於對於較多新頁面,有時候彈出窗口太多會變得難以計算。

而方法二,一直在獲取最后的窗口,如果你只是對最后的窗口進行操作,也就是(自己定義的)”前向“操作時,不計后果,可以直接拿來用,而且代碼不變。缺點在於,如果要返回到某個窗口句柄,那就顯得沒有方法一來的好,至少我現在是這么認為的,可能以后我會回來修改。



總結

我姑且認為這句語句,單獨作用於上述博客中是不可行的。
所以我在后續的博客中對窗口重定向語句改成了browser.switch_to_window(browser.window_handles[1]),至少在我的實驗中,這句語句實現了我需要的操作。
最后上張動圖表示流程:
這里寫圖片描述


最后

雖然我才疏學淺,有時候還會有點錯誤,但是,我寫的很認真,所以請@第七城市轉載時候能轉載全了,格式我看着慘不忍睹,真的,能不能轉的問題你已經寫上作者和出處了,所以沒關系,但是,請也認真對待我的博客,謝謝。比如下圖,我看着都蛋疼、、、
這里寫圖片描述
這種格式和形式,我真的要吐了。。。。。
這里寫圖片描述


還有就是,辛辛苦苦寫的原創,連個作者和來源都沒有,我表示很受傷,更讓我受傷的是,,,閱讀量是我原創的6倍!!必須大寫加粗

這里寫圖片描述


這里寫圖片描述

能讓更多人看到自己寫的東西,和幫助更多的人,我還是很開心的。。。所以我也就不計較了。。。。。。

so ,see you guys,have a good night!



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM