selenium+python實現自動登陸QQ郵箱併發送郵件功能
本期做一個selenium詳細例項,會把我在元素定位中遇到的一些阻塞和經驗分享給大家。
(瀏覽器為Chrome)
(如果只需要最終的完整程式碼,請直接跳轉到文章最後)
瀏覽器開啟QQ郵箱登入網址
QQ郵箱登入地址為:https://mail.qq.com/
from selenium import webdriver import time zhengyi = webdriver.Chrome() zhengyi.get('https://mail.qq.com/')
這一步沒有遇到問題,至於為什麼匯入時間庫,後面會說。
元素定位,輸入QQ賬號和QQ密碼
手動進入QQ郵箱登入網頁,按下F12開啟開發者工具,點選檢視元素,選擇元素:
可以看到QQ賬號輸入框的id、name等屬性,都是可以直接拿來定位的好選擇。
我這裡選擇最通用的xpath方法來定位,id=‘u',並用send事件輸入QQ賬號
(也可以用zhengyi.find_element_by_id(‘u')來定位,程式碼更清晰,不過我個人習慣採用通用的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',這裡不需要傳送資訊,所以選擇click點選事件
zhengyi.find_element_by_xpath('//*[@id="login_button"]').click()
好的,原則上到此為止,執行pycharm應該是能夠輸入賬號和密碼,並登陸成功。
but事情沒有那麼簡單,執行後發現,selenium報錯,無法找到id為u的元素。
進過仔細觀察,發現是frame巢狀頁面在作怪。
我們可以這樣理解,每一個網頁都是一個父類的frame,從我們訪問這個網址開始,就已經進入了這個父類frame巢狀。顧名思義,有父即有子。frame(父)裡嵌套了iframe(子),如果我們要定位的元素在iframe裡,那麼我們需要先切換至iframe。
重新F12往上找iframe資訊,可以看到被iframe嵌套了,id和name都是‘login_frame'
在定位元素之前,先輸入如下程式碼:
zhengyi.switch_to.frame("login_frame")
這樣就切換到iframe了,再繼續之前的元素定位,即可成功。
這一步的完整程式碼為:
# 定位login_frame zhengyi.switch_to.frame("login_frame") zhengyi.find_element_by_xpath('//*[@id="switcher_plogin"]').click() # 定位賬號、密碼,並輸入 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()
這個時候網頁已經可以成功QQ郵箱。
元素定位,寫信介面
繼續,郵箱登入成功之後,來到寫信介面,按照常規操作,我們需要先點選左上角寫信按鈕,展開具體寫信介面
同樣的方法,F12操作起來,檢視寫信按鈕,元素定位為id=‘composebtn',傳送點選事件
# 定位寫信按鈕 zhengyi.find_element_by_xpath('//*[@id="composebtn"]').click()
這個時候除錯程式,網頁成功開啟結果為selenium定位不到id為composebtn的元素。
這個時候就暴露了在上一個環節中出現的問題,之前的程式碼將巢狀切換到了iframe的login_frame中,而此時的寫信元素,不在iframe中,所以在定位之前,需要先離開這個巢狀,返回到主文件中
zhengyi.switch_to.default_content()
這樣巢狀就切換到主文件了,再次執行程式,發現還是報錯
通過反覆查資料,終於發現,寫信是在QQ登入後才會出現的。如果我們登陸之後的瞬間就去定位寫信按鈕,這個時候受網速、PC的客觀影響,會定位不到元素。
我們只需要加一個sleep一秒,即可完美解決。(這個時候就體現了匯入時間庫的作用了~)
#離開login_frame zhengyi.switch_to.default_content() #等待一秒 time.sleep(1) # 定位寫信按鈕 zhengyi.find_element_by_xpath('//*[@id="composebtn"]').click()
這樣即可定位到寫信按鈕,進入到了發郵件的步驟
元素定位,郵件傳送
郵件內容編輯有四個部分,收件人、主題、正文,以及最後點擊發送按鈕
通過之前踩的坑,到了這一步,我對iframe巢狀變得格外小心,準備定位的每個元素都去觀察是否被iframe巢狀。
果不其然,“收件人”、“主題”和“傳送”被主文件下的mainFrame嵌套了,而“正文”又被mainFrame的子frame嵌套了。
so,這一步的邏輯為:
1、先切換到mainFrame,
2、分別定位 收件人 和 主題 ,呼叫傳送事件
3、繼續切換到子frame
4、定位正文,呼叫傳送事件
5、從子frame,返回到它的父frame,也即是mainFrame中
6、定位傳送按鈕,呼叫點選事件
這一步中,也有很多意向不到的坑:
1、定位收件人的時候,發現定位到的元素,還有子div,經過模擬,發現只有第二個子div才是真正能夠定位到收件人的元素,於是先定位id=‘toAreaCtrl',然後選擇第二個div中的input作為定位。
具體xpath定位內容為:“//*[@id=‘toAreaCtrl']/div[2]/input”
2.同樣是定位收件人遇到的問題,必須在切換到mainFrame後、定位收件人之前,加一個延遲執行,不然一定會無法定位到收件人元素。原因不明,所以我建議如果以後遇到元素定位不到,可以嘗試加一個time.sleep。
3.定位正文時,從mainFrame切換到iframe,發現iframe的id和name是動態的一串數字,但是switch_to.frame只支援固定id或者name。所以想了別的法子,先用iframe的class進行xpath定位,然後把傳給switch_to.frame來切換。具體為:
#切換到iframe zhengyi.switch_to.frame(zhengyi.find_element_by_xpath('//*[@class="qmEditorIfrmEditArea"]'))
4.郵件正文需要先呼叫一個點選事件啟用,才能啟動send事件。如果沒有先點選再編寫,那麼send的內容會放在主題後面的文字框中。(也不知道為啥會有這樣的設定~)
所以綜上所述,這一步的程式碼為:
# 切換到mainFrame zhengyi.switch_to.frame('mainFrame') time.sleep(1) # 定位收件人,並輸入 zhengyi.find_element_by_xpath("//*[@id='toAreaCtrl']/div[2]/input").send_keys("[email protected]") # 定位主題,並輸入 zhengyi.find_element_by_xpath('//*[@id="subject"]').send_keys("來自zhengyi的郵件") # 定位郵件正文,先進入到iframe zhengyi.switch_to.frame(zhengyi.find_element_by_xpath('//*[@class="qmEditorIfrmEditArea"]')) # 必須先點選正文,再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() # 定位傳送按鈕 zhengyi.find_element_by_xpath('//*[@name="sendbtn"]').click()
(就這麼短短數十行,耗死了不少腦細胞)
元素定位總結
1、frame很重要,一定要看清楚是否被巢狀,以及注意切換
2、元素的id或者name如果是動態的,請放棄
3、用xpath定位真香
4、如果元素有子節點,使用相對路徑繼續定位
5、實在排查不出為什麼定位失敗,嘗試一下用time.sleep()
最終程式程式碼
from selenium import webdriver #匯入時間模組 import time # 注意大寫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() # 定位賬號、密碼,並輸入 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() # 離開login_frame # zhengyi.switch_to.parent_frame() zhengyi.switch_to.default_content() # 等待一秒 time.sleep(1) # 定位寫信按鈕 zhengyi.find_element_by_xpath('//*[@id="composebtn"]').click() # 切換到mainFrame zhengyi.switch_to.frame('mainFrame') time.sleep(1) # 定位收件人,並輸入 zhengyi.find_element_by_xpath("//*[@id='toAreaCtrl']/div[2]/input").send_keys("[email protected]") # 定位主題,並輸入 zhengyi.find_element_by_xpath('//*[@id="subject"]').send_keys("來自zhengyi發來的郵件") # 定位郵件正文,先進入到iframe zhengyi.switch_to.frame(zhengyi.find_element_by_xpath('//*[@class="qmEditorIfrmEditArea"]')) # 必須先點選正文,再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() # 定位傳送按鈕 zhengyi.find_element_by_xpath('//*[@name="sendbtn"]').click() time.sleep(5) #關閉瀏覽器 zhengyi.quit()
tips
分享幾點在開發者工具裡,比較方便的小竅門:
1、在開發者工具裡,選中元素,點選Console,可以很直觀的看到元素是否被iframe巢狀
2、Elements,選中想定位的元素,右鍵–COPY–Copy XPath,可以直接複製元素的xpath
3、希望您能給我分享一點tips
總結
以上所述是小編給大家介紹的selenium+python實現自動登陸QQ郵箱併發送郵件功能,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回覆大家的。在此也非常感謝大家對我們網站的支援!
如果你覺得本文對你有幫助,歡迎轉載,煩請註明出處,謝謝!