selenium+python实现自动登陆QQ邮箱并发送邮件功能


Posted in Python onDecember 13, 2019

本期做一个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打开开发者工具,点击查看元素,选择元素:

selenium+python实现自动登陆QQ邮箱并发送邮件功能

可以看到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。
iframe也是有自己的元素属性的,selenium也提供了switch方法供我们使用

重新F12往上找iframe信息,可以看到被iframe嵌套了,id和name都是‘login_frame'

selenium+python实现自动登陆QQ邮箱并发送邮件功能

在定位元素之前,先输入如下代码:

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()

这样即可定位到写信按钮,进入到了发邮件的步骤

元素定位,邮件发送

selenium+python实现自动登陆QQ邮箱并发送邮件功能

邮件内容编辑有四个部分,收件人、主题、正文,以及最后点击发送按钮

通过之前踩的坑,到了这一步,我对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”

selenium+python实现自动登陆QQ邮箱并发送邮件功能

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"]'))

selenium+python实现自动登陆QQ邮箱并发送邮件功能

4.邮件正文需要先调用一个点击事件激活,才能启动send事件。如果没有先点击再编写,那么send的内容会放在主题后面的文本框中。(也不知道为啥会有这样的设定~)

所以综上所述,这一步的代码为:

# 切换到mainFrame
zhengyi.switch_to.frame('mainFrame')
time.sleep(1)
# 定位收件人,并输入
zhengyi.find_element_by_xpath("//*[@id='toAreaCtrl']/div[2]/input").send_keys("XXXXXXXXX@qq.com")
# 定位主题,并输入
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("839811794@qq.com")
# 定位主题,并输入
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嵌套

selenium+python实现自动登陆QQ邮箱并发送邮件功能

2、Elements,选中想定位的元素,右键?COPY?Copy XPath,可以直接复制元素的xpath
3、希望您能给我分享一点tips

总结

以上所述是小编给大家介绍的selenium+python实现自动登陆QQ邮箱并发送邮件功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

Python 相关文章推荐
Python中__init__和__new__的区别详解
Jul 09 Python
Python多线程下载文件的方法
Jul 10 Python
Python实现读取并保存文件的类
May 11 Python
python使用Flask操作mysql实现登录功能
May 14 Python
pytorch + visdom CNN处理自建图片数据集的方法
Jun 04 Python
Windows下python3.7安装教程
Jul 31 Python
Python爬虫小技巧之伪造随机的User-Agent
Sep 13 Python
用python打印1~20的整数实例讲解
Jul 01 Python
python面试题之列表声明实例分析
Jul 08 Python
python实现俄罗斯方块小游戏
Apr 24 Python
Python3内置函数chr和ord实现进制转换
Jun 05 Python
Tensorflow使用Anaconda、pycharm安装记录
Jul 29 Python
python中设置超时跳过,超时退出的方式
Dec 13 #Python
python opencv实现gif图片分解的示例代码
Dec 13 #Python
python多进程并发demo实例解析
Dec 13 #Python
使用Matplotlib 绘制精美的数学图形例子
Dec 13 #Python
python plotly画柱状图代码实例
Dec 13 #Python
Pytorch实现的手写数字mnist识别功能完整示例
Dec 13 #Python
使用matplotlib绘制图例标签中带有公式的图
Dec 13 #Python
You might like
如何对PHP程序中的常见漏洞进行攻击
2006/10/09 PHP
php array_flip() 删除数组重复元素
2009/01/14 PHP
php给图片添加文字水印方法汇总
2015/08/27 PHP
PHP封装的多文件上传类实例与用法详解
2017/02/07 PHP
php安装dblib扩展,连接mssql的具体步骤
2017/03/02 PHP
laravel5.4利用163邮箱发送邮件的步骤详解
2017/09/22 PHP
PHP基于imagick扩展实现合成图片的两种方法【附imagick扩展下载】
2017/11/14 PHP
cloudgamer出品ImageZoom 图片放大效果
2010/04/01 Javascript
jQuery 常见操作实现方式和常用函数方法总结
2011/05/06 Javascript
jQuery+CSS 半开折叠效果原理及代码(自写)
2013/03/04 Javascript
jquery中通过父级查找进行定位示例
2013/06/28 Javascript
鼠标移动到图片名上,显示图片的简单实例
2013/07/14 Javascript
输入自动提示搜索提示功能的使用说明:sugggestion.txt
2013/09/02 Javascript
解决canvas画布使用fillRect()时高度出现双倍效果的问题
2017/08/03 Javascript
JavaScript实现离开页面前提示功能【附jQuery实现方法】
2017/09/26 jQuery
基于JavaScript实现前端数据多条件筛选功能
2020/08/19 Javascript
nodejs制作小爬虫功能示例
2020/02/24 NodeJs
element 动态合并表格的步骤
2020/12/31 Javascript
[01:34]2014DOTA2 TI预选赛预选赛 选手比赛房大揭秘!
2014/05/20 DOTA
Python批量查询域名是否被注册过
2017/06/21 Python
python中实现指定时间调用函数示例代码
2017/09/08 Python
python如何读取bin文件并下发串口
2019/07/05 Python
python读写csv文件的方法
2019/08/13 Python
解决django migrate报错ORA-02000: missing ALWAYS keyword
2020/07/02 Python
Python爬虫之爬取淘女郎照片示例详解
2020/07/28 Python
matplotlib绘制鼠标的十字光标的实现(自定义方式,官方实例)
2021/01/10 Python
总结30个CSS3选择器
2017/04/13 HTML / CSS
来自南加州灵感的工作和娱乐服装:TravisMathew
2019/05/01 全球购物
正隆泰信息技术有限公司上机题
2012/06/14 面试题
施工班组长岗位职责
2014/01/05 职场文书
团拜会策划方案
2014/06/07 职场文书
2014年帮扶工作总结
2014/11/26 职场文书
经理助理岗位职责
2015/02/02 职场文书
万能检讨书开头与结尾怎么写
2015/02/17 职场文书
女方家长婚礼答谢词
2015/09/29 职场文书
低门槛开发iOS、Android、小程序应用的前端框架详解
2021/10/16 Javascript