First
首先汽抚,簡書賬號和CSDN賬號都是我的,所以我依然是原創(chuàng)作者枕荞,因為喜歡簡書比較單純簡潔的格式柜候,所以我重心慢慢移向簡書。兩個依然會保持更新躏精,畢竟大家都是MarkDown編輯啊渣刷,復(fù)制粘貼不要太快,當(dāng)然矗烛,以后文章辅柴,簡書首發(fā)。
Python 2.7
IDE Pycharm 5.0.3
環(huán)境細(xì)節(jié)詳見Python+Selenium+PIL+Tesseract真正自動識別驗證碼進(jìn)行一鍵登錄
對于同一頁面無法定位元素問題請見姊妹篇解決網(wǎng)頁元素?zé)o法定位(NoSuchElementException: Unable to locate element)的幾種方法
只解決一個問題--NoSuchElementException: Message: Unable to locate element
問題來源
在上一篇博客中瞭吃,我進(jìn)行了自動化登錄碌嘀,之后我想直接進(jìn)行對圖書的續(xù)約操作,但是利用元素定位的方法歪架,怎么都找不到元素股冗,我一直以為是我的規(guī)則用的不對,導(dǎo)致元素找不到和蚪,其實魁瞪,只是窗口句柄還停留在上一個頁面而已!對于新彈出的頁面還沒有定位;莺簟!峦耘!那怎么可能找得到在新頁面的元素呢L尢!!這是新手(我)犯下最大的錯誤辅髓,只顧于對元素方法的定位泣崩,卻沒有意識到頁面發(fā)生跳轉(zhuǎn)后的handles的變化。
解決方案
窗口重定位洛口,感謝@一朵菊花向陽開------python + selenium webdriver 從主窗口A跳轉(zhuǎn)至主窗口B后矫付,無法定位窗口B的元素的問題 讓我找到解決方案,最終得以實現(xiàn)句柄的重定位第焰!
(這段可跳過买优,因為百度太不穩(wěn)定了,測試結(jié)果有差別)
但話說到這的時候挺举,我很疑惑一篇文章 python+selenuim webdriver 頁面跳轉(zhuǎn)后如何定位元素杀赢,他的方法我進(jìn)行測試時不可行的,請看測試湘纵;
他的代碼:我一行沒動進(jìn)行測試
#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 //此行代碼用來定位當(dāng)前頁面
browser.find_element_by_xpath("/html/body/div[3]/div[4]/div/div[3]/div[4]/h3/a").click()
time.sleep(5)
當(dāng)然如果我一點都不改脂崔,也是進(jìn)行不了測試的,這位大哥把注釋符號寫錯了梧喷,不是//砌左,而是#啊大哥
ok脖咐,然后運行下:出錯了
所以我感到好奇的是,這位大哥到底有沒有跑過這段代碼汇歹,看著原創(chuàng)的樣子應(yīng)該沒有抄襲才對啊屁擅,那應(yīng)該是測試過代碼才對,但是可重復(fù)性在哪秤朗?最后發(fā)現(xiàn)需要修改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 #此行代碼用來定位當(dāng)前頁面
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取视,這次能正常索引到值硝皂,但是!W魈贰稽物!我要說的是但是!U矍贰贝或!
這根本沒有跳轉(zhuǎn)頁面!還是在同一個頁面進(jìn)行操作的锐秦!如果我把大哥的代碼改成:
在我測試的時候咪奖,發(fā)生了奇怪的事情,同樣的代碼酱床,有時候能跑有時候拋出錯誤羊赵,我已設(shè)定休眠時間,難道是我頻繁訪問導(dǎo)致百度封我扇谣?剛才上述的代碼我都實際測試過的昧捷,但是現(xiàn)在又不能用了--wtf--,所以罐寨。我換了穩(wěn)定的引擎靡挥,我采用bing搜索來試試,上面的全部作廢鸯绿,如果有人知道問題出在哪跋破,請留言
7.19補(bǔ)充
應(yīng)該是搜索引擎熱點的問題,每次鍵入相同的值可能搜索結(jié)果首項會不一致的瓶蝴,百度可能更新熱點比較快把幔烛,所以出現(xiàn)了我所謂不穩(wěn)定的情況
正題測試
我和上述那位大哥不同的觀點在于,他用的
sreach_window=browser.current_window_handle
方法并不能實現(xiàn)對新窗口句柄的捕捉囊蓝,我以bing主頁為測試頁饿悬,重新構(gòu)造了一下,
#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)
#----------操作一:進(jìn)行對關(guān)鍵字MrLevo520 CSDN搜索----------------
browser.find_element_by_id("sb_form_go").click()#執(zhí)行此操作會進(jìn)行搜索聚霜,但是沒有彈出新窗口狡恬,所以句柄不用重定位
time.sleep(3)
#----------操作二:對搜索頁面"我的CSDN"進(jìn)行點擊操作--------------
browser.find_element_by_xpath("/html/body/div/ol/li/h2/a").click()#進(jìn)行當(dāng)前頁面點擊第一項
#--------操作三:對新彈出的頁面再點擊"貢獻(xiàn)的資源"選項-----
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)
瀏覽器運行結(jié)果只到如圖:
而且拋出錯誤:
selenium.common.exceptions.NoSuchElementException: Message: Unable to locate element: {"method":"xpath","selector":"/html/body/div[3]/div[2]/div[2]/div/a[3]"}
可見珠叔,此語句并沒有實現(xiàn)句柄重定位的功能,然后我再試試下面的方法弟劲,所有語句不變祷安,只改變獲取當(dāng)前句柄的語句,改成
browser.switch_to_window(browser.window_handles[1])
最后程序應(yīng)該是這樣:
#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)
#----------操作一:進(jìn)行對關(guān)鍵字MrLevo520 CSDN搜索----------------
browser.find_element_by_id("sb_form_go").click()#執(zhí)行此操作會進(jìn)行搜索兔乞,但是沒有彈出新窗口汇鞭,所以句柄不用重定位
time.sleep(3)
#----------操作二:對搜索頁面"我的CSDN"進(jìn)行點擊操作--------------
browser.find_element_by_xpath("/html/body/div/ol/li/h2/a").click()#進(jìn)行當(dāng)前頁面點擊第一項
#--------操作三:對新彈出的頁面再點擊"貢獻(xiàn)的資源"選項-----
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)
最后結(jié)果,按照我的思路庸追,進(jìn)行了相應(yīng)的點擊霍骄,最后如圖
所以從上述的例子上來說,語句sreach_window=browser.current_window_handle
并沒有實現(xiàn)重定位淡溯,可能我才疏學(xué)淺读整,但至少,在上述的那位大哥的博客中咱娶,寫的是錯誤的米间,運行失敗,我對2016.7.16的所有數(shù)據(jù)負(fù)責(zé)膘侮,實際測試失敗屈糊。
7.17-補(bǔ)充:另一種獲取句柄方法
還有另一種方法,就是直接定位當(dāng)前最新彈出的窗口琼了。代碼是這樣的
for handle in browser.window_handles:#方法二另玖,始終獲得當(dāng)前最后的窗口,所以多要多次使用
browser.switch_to_window(handle)
那么結(jié)合到我的代碼中那就是這樣的:
#Author:哈士奇說喵
#因為搜索引擎檢索項根據(jù)熱度來排名表伦,所以我只能對7.17的數(shù)據(jù)進(jìn)行測試和負(fù)責(zé),大家測試時候注意元素變化
#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)
#----------操作一:進(jìn)行對關(guān)鍵字MrLevo520 CSDN搜索----------------
browser.find_element_by_id("sb_form_go").click()#執(zhí)行此操作會進(jìn)行搜索慷丽,但是沒有彈出新窗口蹦哼,所以句柄不用重定位
time.sleep(3)
#----------操作二:對搜索頁面第一項進(jìn)行點擊操作--------------
browser.find_element_by_xpath("/html/body/div/ol/li/h2/a").click()#進(jìn)行當(dāng)前頁面點擊第一項
#--------操作三:對新彈出的頁面再點擊"我的頭像"選項-----
#注意此時已經(jīng)是彈出的第一個窗口了,需要重新定位句柄
'''browser.switch_to_window(browser.window_handles[1])#方法一'''
for handle in browser.window_handles:#方法二要糊,始終獲得當(dāng)前最后的窗口
browser.switch_to_window(handle)
browser.find_element_by_xpath("http://div[@id='body']/div[2]/div/div/ul[2]/div/a").click()
#------------------操作四:點擊"貢獻(xiàn)的資源"-------------------
#注意此時已經(jīng)是新彈出的第二個窗口了纲熏,需要重新定位句柄
browser.switch_to_window(browser.window_handles[2])#方法一,注意window_handles[2]變成了2
'''for handle in browser.window_handles:#方法二锄俄,始終獲得當(dāng)前最后的窗口
browser.switch_to_window(handle)'''
browser.find_element_by_xpath("/html/body/div[3]/div[2]/div[2]/div/a[3]").click()
time.sleep(5)
上面的代碼局劲,我要說幾點,總共實現(xiàn)完成會存在三個瀏覽器窗口奶赠,也就是相當(dāng)于實現(xiàn)了兩次句柄重定位功能鱼填,也就是下面的圖片,對bing搜索“MrLevo520 CSDN”跳出的最熱項毅戈,也就是這一篇(感謝大家厚愛)苹丸,但是昨天最熱彈出來的是直接是我的主頁愤惰,大家從上面的動圖應(yīng)該也可以看出來,所以等你測試這段代碼的時候赘理,可能最熱項目又變化了宦言,道理大家懂就ok,不影響重抓句柄代碼商模。
代碼實現(xiàn)了從1奠旺,到2,點擊頭像后施流,再跳轉(zhuǎn)到3主頁响疚,之后再點擊"貢獻(xiàn)資源",實現(xiàn)的動圖如下:
Pay Attention
1.搜索引擎根據(jù)熱度來排名嫂沉,也就是代碼具有"不穩(wěn)定性"稽寒,應(yīng)該根據(jù)自己實際情況,定位不同元素趟章,我只對當(dāng)前編輯時間的數(shù)據(jù)負(fù)責(zé)
2.在實際操作過程中杏糙,會產(chǎn)生第一個頁面還沒等第二個頁面緩沖完,直接又"占領(lǐng)"主視覺的問題蚓土,別擔(dān)心宏侍,句柄還是在傳遞的,程序一直在跑蜀漆,而且沒有出錯谅河,過一會時間就會更新加載頁面的,如果想要關(guān)閉無關(guān)頁面确丢,請看這篇博客 基于Selenium一鍵寫CSDN博客
3.可能我的代碼第一次獲取句柄和第二次獲取句柄不一樣的方法绷耍,這是為了展示,你可以兩次句柄獲取都用方法二鲜侥,也可以都是用方法一褂始,但是方法一注意修改標(biāo)號。
方法一 VS 方法二
相比較于方法二描函,方法一的優(yōu)點在于后續(xù)操作崎苗,比如關(guān)閉第幾個窗口,句柄傳遞是按照順序來的舀寓。缺點在于對于較多新頁面胆数,有時候彈出窗口太多會變得難以計算。
而方法二互墓,一直在獲取最后的窗口必尼,如果你只是對最后的窗口進(jìn)行操作,也就是(自己定義的)”前向“操作時篡撵,不計后果胰伍,可以直接拿來用齿诞,而且代碼不變。缺點在于骂租,如果要返回到某個窗口句柄祷杈,那就顯得沒有方法一來的好,至少我現(xiàn)在是這么認(rèn)為的渗饮,可能以后我會回來修改但汞。
總結(jié)
我姑且認(rèn)為這句語句,單獨作用于上述博客中是不可行的互站。
所以我在后續(xù)的博客中對窗口重定向語句改成了browser.switch_to_window(browser.window_handles[1])
私蕾,至少在我的實驗中,這句語句實現(xiàn)了我需要的操作胡桃。
最后上張動圖表示流程:
最后
將待解決實際問題解決踩叭,方法總是好多種,就看自己想不想解決翠胰。
so 容贝,see you guys,have a good night之景!
致謝
@一朵菊花向陽開--python + selenium webdriver 從主窗口A跳轉(zhuǎn)至主窗口B后斤富,無法定位窗口B的元素的問題
@Do it Yourself--python+selenuim webdriver 頁面跳轉(zhuǎn)后如何定位元素
@崔慶才--Python爬蟲利器五之Selenium的用法