selenium+python實(shí)現(xiàn)登陸QQ郵箱并發(fā)送郵件功能
本期做一個(gè)selenium詳細(xì)實(shí)例,會(huì)把我在元素定位中遇到的一些阻塞和經(jīng)驗(yàn)分享給大家。
(瀏覽器為Chrome)
(如果只需要最終的完整代碼,請(qǐng)直接跳轉(zhuǎn)到文章最后)
瀏覽器打開(kāi)QQ郵箱登錄網(wǎng)址
QQ郵箱登錄地址為:https://mail.qq.com/
from selenium import webdriver import time zhengyi = webdriver.Chrome() zhengyi.get('https://mail.qq.com/')
這一步?jīng)]有遇到問(wèn)題,至于為什么導(dǎo)入時(shí)間庫(kù),后面會(huì)說(shuō)。
元素定位,輸入QQ賬號(hào)和QQ密碼
手動(dòng)進(jìn)入QQ郵箱登錄網(wǎng)頁(yè),按下F12打開(kāi)開(kāi)發(fā)者工具,點(diǎn)擊查看元素,選擇元素:
可以看到QQ賬號(hào)輸入框的id、name等屬性,都是可以直接拿來(lái)定位的好選擇。
我這里選擇最通用的xpath方法來(lái)定位,id=‘u’,并用send事件輸入QQ賬號(hào)
(也可以用zhengyi.find_element_by_id(‘u’)來(lái)定位,代碼更清晰,不過(guò)我個(gè)人習(xí)慣采用通用的xpath)
zhengyi.find_element_by_xpath('//*[@id="u"]').send_keys("XXXXXXXXX")
同理,QQ密碼元素屬性id=‘p’,同樣定位方法
zhengyi.find_element_by_xpath('//*[@id="p"]').send_keys("XXXXXXXX")
再同理,登錄按鈕元素屬性id=‘login_button’,這里不需要發(fā)送信息,所以選擇click點(diǎn)擊事件
zhengyi.find_element_by_xpath('//*[@id="login_button"]').click()
好的,原則上到此為止,運(yùn)行pycharm應(yīng)該是能夠輸入賬號(hào)和密碼,并登陸成功。
but事情沒(méi)有那么簡(jiǎn)單,運(yùn)行后發(fā)現(xiàn),selenium報(bào)錯(cuò),無(wú)法找到id為u的元素。
進(jìn)過(guò)仔細(xì)觀察,發(fā)現(xiàn)是frame嵌套頁(yè)面在作怪。
我們可以這樣理解,每一個(gè)網(wǎng)頁(yè)都是一個(gè)父類(lèi)的frame,從我們?cè)L問(wèn)這個(gè)網(wǎng)址開(kāi)始,就已經(jīng)進(jìn)入了這個(gè)父類(lèi)frame嵌套。顧名思義,有父即有子。frame(父)里嵌套了iframe(子),如果我們要定位的元素在iframe里,那么我們需要先切換至iframe。
iframe也是有自己的元素屬性的,selenium也提供了switch方法供我們使用
重新F12往上找iframe信息,可以看到被iframe嵌套了,id和name都是‘login_frame’
在定位元素之前,先輸入如下代碼:
zhengyi.switch_to.frame("login_frame")
這樣就切換到iframe了,再繼續(xù)之前的元素定位,即可成功。
這一步的完整代碼為:
# 定位login_frame zhengyi.switch_to.frame("login_frame") zhengyi.find_element_by_xpath('//*[@id="switcher_plogin"]').click() # 定位賬號(hào)、密碼,并輸入 zhengyi.find_element_by_xpath('//*[@id="u"]').send_keys("839811794") zhengyi.find_element_by_xpath('//*[@id="p"]').send_keys("199306zy") # 定位登錄按鈕 zhengyi.find_element_by_xpath('//*[@id="login_button"]').click()
這個(gè)時(shí)候網(wǎng)頁(yè)已經(jīng)可以成功QQ郵箱。
元素定位,寫(xiě)信界面
繼續(xù),郵箱登錄成功之后,來(lái)到寫(xiě)信界面,按照常規(guī)操作,我們需要先點(diǎn)擊左上角寫(xiě)信按鈕,展開(kāi)具體寫(xiě)信界面
同樣的方法,F(xiàn)12操作起來(lái),查看寫(xiě)信按鈕,元素定位為id=‘composebtn’,發(fā)送點(diǎn)擊事件
# 定位寫(xiě)信按鈕 zhengyi.find_element_by_xpath('//*[@id="composebtn"]').click()
這個(gè)時(shí)候調(diào)試程序,網(wǎng)頁(yè)成功打開(kāi)結(jié)果為selenium定位不到id為composebtn的元素。
這個(gè)時(shí)候就暴露了在上一個(gè)環(huán)節(jié)中出現(xiàn)的問(wèn)題,之前的代碼將嵌套切換到了iframe的login_frame中,而此時(shí)的寫(xiě)信元素,不在iframe中,所以在定位之前,需要先離開(kāi)這個(gè)嵌套,返回到主文檔中
zhengyi.switch_to.default_content()
這樣嵌套就切換到主文檔了,再次運(yùn)行程序,發(fā)現(xiàn)還是報(bào)錯(cuò)
通過(guò)反復(fù)查資料,終于發(fā)現(xiàn),寫(xiě)信是在QQ登錄后才會(huì)出現(xiàn)的。如果我們登陸之后的瞬間就去定位寫(xiě)信按鈕,這個(gè)時(shí)候受網(wǎng)速、PC的客觀影響,會(huì)定位不到元素。
我們只需要加一個(gè)sleep一秒,即可完美解決。(這個(gè)時(shí)候就體現(xiàn)了導(dǎo)入時(shí)間庫(kù)的作用了~)
#離開(kāi)login_frame zhengyi.switch_to.default_content() #等待一秒 time.sleep(1) # 定位寫(xiě)信按鈕 zhengyi.find_element_by_xpath('//*[@id="composebtn"]').click()
這樣即可定位到寫(xiě)信按鈕,進(jìn)入到了發(fā)郵件的步驟
元素定位,郵件發(fā)送
郵件內(nèi)容編輯有四個(gè)部分,收件人、主題、正文,以及最后點(diǎn)擊發(fā)送按鈕
通過(guò)之前踩的坑,到了這一步,我對(duì)iframe嵌套變得格外小心,準(zhǔn)備定位的每個(gè)元素都去觀察是否被iframe嵌套。
果不其然,“收件人”、“主題”和“發(fā)送”被主文檔下的mainFrame嵌套了,而“正文”又被mainFrame的子frame嵌套了。
so,這一步的邏輯為:
1、先切換到mainFrame,
2、分別定位 收件人 和 主題 ,調(diào)用發(fā)送事件
3、繼續(xù)切換到子frame
4、定位正文,調(diào)用發(fā)送事件
5、從子frame,返回到它的父frame,也即是mainFrame中
6、定位發(fā)送按鈕,調(diào)用點(diǎn)擊事件
這一步中,也有很多意向不到的坑:
1、定位收件人的時(shí)候,發(fā)現(xiàn)定位到的元素,還有子div,經(jīng)過(guò)模擬,發(fā)現(xiàn)只有第二個(gè)子div才是真正能夠定位到收件人的元素,于是先定位id=‘toAreaCtrl’,然后選擇第二個(gè)div中的input作為定位。
具體xpath定位內(nèi)容為:“//*[@id=‘toAreaCtrl’]/div[2]/input”
2.同樣是定位收件人遇到的問(wèn)題,必須在切換到mainFrame后、定位收件人之前,加一個(gè)延遲執(zhí)行,不然一定會(huì)無(wú)法定位到收件人元素。原因不明,所以我建議如果以后遇到元素定位不到,可以嘗試加一個(gè)time.sleep。
3.定位正文時(shí),從mainFrame切換到iframe,發(fā)現(xiàn)iframe的id和name是動(dòng)態(tài)的一串?dāng)?shù)字,但是switch_to.frame只支持固定id或者name。所以想了別的法子,先用iframe的class進(jìn)行xpath定位,然后把傳給switch_to.frame來(lái)切換。具體為:
#切換到iframe zhengyi.switch_to.frame(zhengyi.find_element_by_xpath('//*[@class="qmEditorIfrmEditArea"]'))
4.郵件正文需要先調(diào)用一個(gè)點(diǎn)擊事件激活,才能啟動(dòng)send事件。如果沒(méi)有先點(diǎn)擊再編寫(xiě),那么send的內(nèi)容會(huì)放在主題后面的文本框中。(也不知道為啥會(huì)有這樣的設(shè)定~)
所以綜上所述,這一步的代碼為:
# 切換到mainFrame zhengyi.switch_to.frame('mainFrame') time.sleep(1) # 定位收件人,并輸入 zhengyi.find_element_by_xpath("http://*[@id='toAreaCtrl']/div[2]/input").send_keys("XXXXXXXXX@qq.com") # 定位主題,并輸入 zhengyi.find_element_by_xpath('//*[@id="subject"]').send_keys("來(lái)自zhengyi的郵件") # 定位郵件正文,先進(jìn)入到iframe zhengyi.switch_to.frame(zhengyi.find_element_by_xpath('//*[@class="qmEditorIfrmEditArea"]')) # 必須先點(diǎn)擊正文,再send_keys zhengyi.find_element_by_xpath('/html/body').click() zhengyi.find_element_by_xpath('/html/body').send_keys("Hello World","\nZhengyi") # 返回到mainframe zhengyi.switch_to.parent_frame() # 定位發(fā)送按鈕 zhengyi.find_element_by_xpath('//*[@name="sendbtn"]').click()
(就這么短短數(shù)十行,耗死了不少腦細(xì)胞)
元素定位總結(jié)
1、frame很重要,一定要看清楚是否被嵌套,以及注意切換
2、元素的id或者name如果是動(dòng)態(tài)的,請(qǐng)放棄
3、用xpath定位真香
4、如果元素有子節(jié)點(diǎn),使用相對(duì)路徑繼續(xù)定位
5、實(shí)在排查不出為什么定位失敗,嘗試一下用time.sleep()
最終程序代碼
from selenium import webdriver #導(dǎo)入時(shí)間模塊 import time # 注意大寫(xiě)Chrome的C zhengyi = webdriver.Chrome() zhengyi.get('https://mail.qq.com/') # 定位login_frame zhengyi.switch_to.frame("login_frame") zhengyi.find_element_by_xpath('//*[@id="switcher_plogin"]').click() # 定位賬號(hào)、密碼,并輸入 zhengyi.find_element_by_xpath('//*[@id="u"]').send_keys("839811794") zhengyi.find_element_by_xpath('//*[@id="p"]').send_keys("199306zy") # 定位登錄按鈕 zhengyi.find_element_by_xpath('//*[@id="login_button"]').click() # 離開(kāi)login_frame # zhengyi.switch_to.parent_frame() zhengyi.switch_to.default_content() # 等待一秒 time.sleep(1) # 定位寫(xiě)信按鈕 zhengyi.find_element_by_xpath('//*[@id="composebtn"]').click() # 切換到mainFrame zhengyi.switch_to.frame('mainFrame') time.sleep(1) # 定位收件人,并輸入 zhengyi.find_element_by_xpath("http://*[@id='toAreaCtrl']/div[2]/input").send_keys("839811794@qq.com") # 定位主題,并輸入 zhengyi.find_element_by_xpath('//*[@id="subject"]').send_keys("來(lái)自zhengyi發(fā)來(lái)的郵件") # 定位郵件正文,先進(jìn)入到iframe zhengyi.switch_to.frame(zhengyi.find_element_by_xpath('//*[@class="qmEditorIfrmEditArea"]')) # 必須先點(diǎn)擊正文,再send_keys zhengyi.find_element_by_xpath('/html/body').click() zhengyi.find_element_by_xpath('/html/body').send_keys("Hello World","\nZhengyi") # 返回到mainframe zhengyi.switch_to.parent_frame() # 定位發(fā)送按鈕 zhengyi.find_element_by_xpath('//*[@name="sendbtn"]').click() time.sleep(5) #關(guān)閉瀏覽器 zhengyi.quit()
tips
分享幾點(diǎn)在開(kāi)發(fā)者工具里,比較方便的小竅門(mén):
1、在開(kāi)發(fā)者工具里,選中元素,點(diǎn)擊Console,可以很直觀的看到元素是否被iframe嵌套
2、Elements,選中想定位的元素,右鍵–COPY–Copy XPath,可以直接復(fù)制元素的xpath
3、希望您能給我分享一點(diǎn)tips
總結(jié)
以上所述是小編給大家介紹的selenium+python實(shí)現(xiàn)登陸QQ郵箱并發(fā)送郵件功能,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
如果你覺(jué)得本文對(duì)你有幫助,歡迎轉(zhuǎn)載,煩請(qǐng)注明出處,謝謝!
相關(guān)文章
Python創(chuàng)建多線程的兩種常用方法總結(jié)
這篇文章主要為大家詳細(xì)介紹了Python中創(chuàng)建多線程的兩種常用方法,文中的示例代碼簡(jiǎn)潔易懂,對(duì)我們掌握Python有一定的幫助,需要的可以收藏一下2023-05-05Python多進(jìn)程Process和管道Pipe的使用方式
這篇文章主要介紹了Python多進(jìn)程Process和管道Pipe的使用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-02-02python獲取整個(gè)網(wǎng)頁(yè)源碼的方法
在本篇文章里小編給大家整理的是關(guān)于python獲取整個(gè)網(wǎng)頁(yè)源碼的方法,需要的朋友們可以參考下。2020-08-08關(guān)于Python 解決Python3.9 pandas.read_excel(‘xxx.xlsx‘)報(bào)錯(cuò)的問(wèn)題
這篇文章主要介紹了關(guān)于Python 解決Python3.9 pandas.read_excel(‘xxx.xlsx‘)報(bào)錯(cuò)的問(wèn)題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-11-11Python Matplotlib條形圖之垂直條形圖和水平條形圖詳解
這篇文章主要為大家詳細(xì)介紹了Python Matplotlib條形圖之垂直條形圖和水平條形圖,使用數(shù)據(jù)庫(kù),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03selenium+python實(shí)現(xiàn)自動(dòng)登錄腳本
下面小編就為大家分享一篇selenium+python實(shí)現(xiàn)自動(dòng)登錄腳本,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-04-04Python自動(dòng)化測(cè)試工具Splinter簡(jiǎn)介和使用實(shí)例
這篇文章主要介紹了Python自動(dòng)化測(cè)試工具Splinter簡(jiǎn)介和使用實(shí)例,Splinter可以非常棒的模擬瀏覽器的行為,Splinter提供了豐富的API,可以獲取頁(yè)面的信息判斷當(dāng)前的行為所產(chǎn)生的結(jié)果2014-05-05Python extract及contains方法代碼實(shí)例
這篇文章主要介紹了Python extract及contains方法代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-09-09