[python] 使用selenium模块实现QQ邮箱的自动化登录及邮件发送

文章目录

  • 前言
  • 前期准备
    • selenium模块
    • 测试
  • 过程讲解
    • 1.配置驱动,启动浏览器
    • 2.登录操作
      • 2.1 转换为账号密码登录
      • 2.2 键入邮箱密码并登录
    • 3.发送邮件
  • 实现
  • 完整代码
  • 总结


前言

在我们日常工作中,会有很多需要通过邮箱进行的推送,比如数据集更新推送、自动回复等等。这些操作的前提是需要自动化的登录到邮箱中,并操作QQ邮箱进行写信发送的操作,所以接下来配合着code来解释一下一个完整的邮件登录发送过程。

前期准备

selenium模块

这里需要使用pip安装selenium,并且根据自己的浏览器版本下载对应的驱动。还没有配置过的朋友可以参考一下我之前的文章,有任何问题欢迎私信或评论。

[python] 使用selenium+pywinauto模块处理弹窗中的图片/文件上传

这里顺带一提,我在conda环境下下载的selenium模块在驱动安装配置完毕的情况下并不能正常使用,需要更进一步的查看原因,所以这里暂时不推荐使用conda环境。

测试

同样,这里给出一个示例,如果你可以成功打开浏览器就说明配置成功了!

from selenium import webdriver
driver_edge=webdriver.Edge()
driver_edge.get("https://www.baidu.com/")

过程讲解

这里我以QQ邮箱举例,当然在理解本文中的登录发送操作后,对于别的邮箱。也可以举一反三。这里讲解时使用部分代码,完整版我会放在文末。

1.配置驱动,启动浏览器

# 配置浏览器驱动
url="https://mail.qq.com/"
# 确保浏览器打开后不会自动关闭
option = webdriver.EdgeOptions()
option.add_experimental_option('excludeSwitches', ['enable-automation'])
option.add_experimental_option("detach", True)
# 配置浏览器驱动
driver=webdriver.Edge(options=option)
# 打开网页
driver.get(url)
# 将浏览器网页最大化
driver.maximize_window()

2.登录操作

这里首先要讲一个和定位元素有关的知识点。

一般的登录网页都是将登陆框结构写在外层html网页内的,比如说csdn的登陆界面…

我们可以通过以下代码快速的定位到登录按钮并点击

driver.find_element(By.XPATH,'/html/body/div[2]/div/div[2]/div[2]/div[2]/div/div[2]/div/div[4]/button').click()

但是!但是!邮箱的登录页面一般使用frame的内嵌网页,可以大致理解为一个frame框为一个独立的网页。所以,常规的定位方法无法定位到对应frame框中的元素,需要先切入到所需元素所在的frame,再在frame内定位对应的元素。具体的操作方法可以参考这位大佬的文章

selenium之 定位以及切换frame

2.1 转换为账号密码登录

这里我们需要使用邮箱密码登录,由于网页默认的登陆方式扫码登录,所以必须先点击密码登录按钮,进行登录方式的转换。

可以通过右键检查的方法查看该按钮的位置:
[python] 使用selenium模块实现QQ邮箱的自动化登录及邮件发送_第1张图片
可以大致看到这个元素嵌套在两个frame框当中,所以我们需要两次切入到当前元素所在的frame框中。

注意:这里最好使用id、name、class_name等定位方法去做定位,相对简洁且可以避免大部分frame框加密和元素定位重复的问题。

切入到第一层frame中(使用class_name方法,当然也可以结合使用src和xpath方法定位):
[python] 使用selenium模块实现QQ邮箱的自动化登录及邮件发送_第2张图片

iframe1=driver.find_element(By.CLASS_NAME,"QQMailSdkTool_login_loginBox_qq_iframe")
driver.switch_to.frame(iframe1)

切入到第二层方法相同,这里不过多赘述。

iframe2=driver.find_element(By.NAME,'ptlogin_iframe')
driver.switch_to.frame(iframe2)

定位到当前frame中的密码登录按钮,并点击。

[python] 使用selenium模块实现QQ邮箱的自动化登录及邮件发送_第3张图片

# 定位到密码登录,并使用邮箱进行登录
trans=driver.find_element(By.XPATH,'//*[@id="switcher_plogin"]').click()

ok!到这一步我们就可以使用邮箱和密码进行登陆了。

2.2 键入邮箱密码并登录

与上面定位密码登录按钮的操作相似,我们也来定位一下邮箱和密码输入框的位置。

不难发现,当前的邮箱和密码输入框及登 录按钮是处在我们之前切入的id为ptlogin_iframe的frame中的,所以这里我们就不需要再做任何切入操作了。具体的位置如下图所示
[python] 使用selenium模块实现QQ邮箱的自动化登录及邮件发送_第4张图片

(1) 邮箱定位
既然不需要做任何操作,这里直接使用xpath定位到邮箱输入框并输入邮箱就行,这里最好clear一下文本框,以防之前浏览器记录过的邮箱或密码出现:

email=driver.find_element(By.XPATH,'//*[@id="u"]')
email.clear()
email.send_keys("your email")

(2) 密码定位
密码输入框的定位方式和邮箱输入框一样:

password=driver.find_element(By.XPATH,'//*[@id="p"]')
password.clear()
password.send_keys("your password")

(3) 登录
定位到按钮并点击

driver.find_element(By.XPATH,'//*[@id="login_button"]').click()

这里我使用了强制等待20s的方式来等待新页面的出现,大家也可以使用selenium自带的显式等待方法until(),这个方法在本文的后半段会使用到,这里就先不做解释。

driver.find_element(By.XPATH,'//*[@id="login_button"]').click()
# 等待30s直到写信的按钮出现
time.sleep(20)
windows=driver.window_handles
# 切换到当前最新打开的窗口中
driver.switch_to.window(windows[-1])

window_handles方法获取当前浏览器中的所有窗口句柄,并使用switch_to.window(windows[-1])
转换到最新的页面中。

ok!到这里登陆操作已经全部完成了,可以操作邮箱发送邮件了。

3.发送邮件

左上角的写 信按钮在最外层的html中,直接定位点击

# 定位到写信按键
driver.find_element(By.XPATH,'//*[@id="composebtn_td"]').click()

右侧出现的写信界面也不出意料的在id为mainFrame的frame框中,先切入该frame

[python] 使用selenium模块实现QQ邮箱的自动化登录及邮件发送_第5张图片

# 与之前相同,还是先转换到写信的frame
iframe3=driver.find_element(By.ID,'mainFrame')
driver.switch_to.frame(iframe3)

下方的收件人和主题都属于这个frame,和之前邮件密码的输入方式相同

# 输入收件人
driver.find_element(By.XPATH,'/html/body/form[2]/div[2]/div[3]/div[2]/table[2]/tbody/tr/td[2]/div[1]/div[2]/input').send_keys(address)
# 输入主题
driver.find_element(By.XPATH,'/html/body/form[2]/div[2]/div[3]/table[3]/tbody/tr[2]/td[2]/div/div/div/input').send_keys(title)

我在这里遇到了问题,在定位正文的文本框的时候每次都会出现NoSuchElement的错误,后来才发现正文的文本框是在mainFrame下的另一个frame中的,大家要注意!

切入frame并输入邮件正文

# 输入正文
"""
这里正文仍然嵌套了一个frame框架
所以这里只有定位到该frame后才能输入正文
"""
iframe4=driver.find_element(By.CLASS_NAME,'qmEditorIfrmEditArea')
driver.switch_to.frame(iframe4)
# 定位到文本框,并输入正文
text_label=driver.find_element(By.XPATH,'/html/body/div[1]')
text_label.clear()
text_label.send_keys(text)

然后点击发送,细心的朋友一定会发现发 送按钮是在mainFrame当中的,那要重新回到最外层html中重新一层层切进来吗?当然不需要,selenium模块提供了退回的方法parent_frame(),可以退回到上一层frame中,如果已经在最外层html中了,该方法不会生效。

ok,那我们退回到mainFrame中,再点击发 送按钮。

[python] 使用selenium模块实现QQ邮箱的自动化登录及邮件发送_第6张图片

# 现在退回到上一层frame中进行发送操作
driver.switch_to.parent_frame()
driver.find_element(By.XPATH,'/html/body/form[2]/div[1]/div/a[1]').click()

接下来我们检查一下邮件是否发送成功,这里使用selenium.webdriver.support中的expected_conditions(简称EC)和WebDriverWait设置显式等待。

# 隐式等待发送完成的页面出现
WebDriverWait(driver,20,0.5).until(EC.presence_of_element_located((By.XPATH, '/html/body/div/div[1]/div/div[2]/span[2]/a[1]')))

这里的WebDriverWait中的三个参数依次为浏览器驱动,最长等待时间和时间间隔,until()方法中的是需要等待出现的某个元素。可以将其简单的理解为比强制等待更加高级的等待方式…一旦元素出现就会结束等待,若超过最大等待时间就会和强制等待一样,进行后续操作。

实现

由于隐私问题,我就不展示我的测试账号了…大家可以用自己的账号发给自己来测试。

if __name__=='__main__':
    # 配置浏览器驱动
    url="https://mail.qq.com/"
    # 邮箱密码
    email="your email"
    password="your password"
    # 目标邮箱、正文、标题
    addressee="your email"
    text="This is a test email..."
    title="test email"
    # 确保浏览器打开后不会自动关闭
    option = webdriver.EdgeOptions()
    option.add_experimental_option('excludeSwitches', ['enable-automation'])
    option.add_experimental_option("detach", True)
    # 配置浏览器驱动
    driver=webdriver.Edge(options=option)
    # 打开网页
    driver.get(url)
    # 将浏览器网页最大化
    driver.maximize_window()
    QQLogin(email=email,password=password)
    QQSend(address=addressee,text=text,title=title)

完整代码

# 使用selenium进行登录下载操作
from selenium import webdriver
import time
from selenium.webdriver.common.by import By
from selenium.webdriver import ActionChains
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

def QQLogin(email,password):
    """
    本函数主要负责QQ邮箱登录操作
    参数包括
        eamil-您的登录邮箱
        password-您邮箱所对应的登陆密码
    """
    # 以下为登录邮箱流程
    # 先定位到QQ登录的frame
    print("当前开始登陆操作")
    iframe1=driver.find_element(By.CLASS_NAME,"QQMailSdkTool_login_loginBox_qq_iframe")
    driver.switch_to.frame(iframe1)
    # 再定位到登录框的frame
    iframe2=driver.find_element(By.NAME,'ptlogin_iframe')
    driver.switch_to.frame(iframe2)
    time.sleep(3)
    # 定位到密码登录,并使用邮箱进行登录
    driver.find_element(By.XPATH,'//*[@id="switcher_plogin"]').click()
    email_label=driver.find_element(By.XPATH,'//*[@id="u"]')
    email_label.clear()
    email_label.send_keys(email)
    time.sleep(3)
    password_label=driver.find_element(By.XPATH,'//*[@id="p"]')
    password_label.clear()
    password_label.send_keys(password)
    time.sleep(3)
    driver.find_element(By.XPATH,'//*[@id="login_button"]').click()
    # 等待30s直到写信的按钮出现
    time.sleep(20)
    windows=driver.window_handles
    # 切换到当前最新打开的窗口中
    driver.switch_to.window(windows[-1])
    print("登陆成功!正在进行邮件发送请稍后...")
    
def QQSendPrepare(address,title=""):
    """
    本函数主要负责QQ邮箱发送邮件前的收件人和标题键入操作
    参数包括
        address-收件人邮箱地址
        title-邮件主题(此处默认为空)
    """
    # 以下为写信发邮件流程
    # 定位到写信按键
    driver.find_element(By.XPATH,'//*[@id="composebtn_td"]').click()
    # 与之前相同,还是先转换到写信的frame
    iframe3=driver.find_element(By.ID,'mainFrame')
    driver.switch_to.frame(iframe3)
    # 输入收件人
    driver.find_element(By.XPATH,'/html/body/form[2]/div[2]/div[3]/div[2]/table[2]/tbody/tr/td[2]/div[1]/div[2]/input').send_keys(address)
    # 输入主题
    driver.find_element(By.XPATH,'/html/body/form[2]/div[2]/div[3]/table[3]/tbody/tr[2]/td[2]/div/div/div/input').send_keys(title)
    
def QQSend(address,text,title=""):
    """
    本函数为QQ邮箱发送邮件主函数
    参数包括
        address-收件人邮箱地址
        text-邮件具体内容
        title-邮件主题(此处默认为空)
    """
    QQSendPrepare(address,title)
    # 输入正文
    """
    这里正文仍然嵌套了一个frame框架
    所以这里只有定位到该frame后才能输入正文
    """
    iframe4=driver.find_element(By.CLASS_NAME,'qmEditorIfrmEditArea')
    driver.switch_to.frame(iframe4)
    # 定位到文本框,并输入正文
    text_label=driver.find_element(By.XPATH,'/html/body/div[1]')
    text_label.clear()
    text_label.send_keys(text)
    
    # 现在退回到上一层frame中进行发送操作
    driver.switch_to.parent_frame()
    driver.find_element(By.XPATH,'/html/body/form[2]/div[1]/div/a[1]').click()
    # 隐式等待发送完成的页面出现
    WebDriverWait(driver,20,0.5).until(EC.presence_of_element_located((By.XPATH, '/html/body/div/div[1]/div/div[2]/span[2]/a[1]')))
    # 等待当前的邮件发送完成,点击查看发送状态
    driver.find_element(By.XPATH,'/html/body/div/div[1]/div/div[1]/div[1]/a').click()
    # 切入状态frame中
    iframe5=driver.find_element(By.NAME,'mailSendStatus')
    driver.switch_to.frame(iframe5)
    status_text=driver.find_element(By.XPATH,"/html/body/div/table/tbody/tr[2]/td[2]/div").get_attribute("title")
    time.sleep(5)
    if status_text=="已投递到对方邮箱":
        driver.quit()
        print("当前邮件已经投递完毕")
        
if __name__=='__main__':
    # 配置浏览器驱动
    url="https://mail.qq.com/"
    # 邮箱密码
    email="your email"
    password="your password"
    # 目标邮箱、正文、标题
    addressee="your email"
    text="This is a test email..."
    title="test email"
    # 确保浏览器打开后不会自动关闭
    option = webdriver.EdgeOptions()
    option.add_experimental_option('excludeSwitches', ['enable-automation'])
    option.add_experimental_option("detach", True)
    # 配置浏览器驱动
    driver=webdriver.Edge(options=option)
    # 打开网页
    driver.get(url)
    # 将浏览器网页最大化
    driver.maximize_window()
    QQLogin(email=email,password=password)
    QQSend(address=addressee,text=text,title=title)

总结

以上就是使用python中的selenium模块实现QQ邮箱的登录和邮件发送的所有内容啦,本文有什么问题还请大家海涵!有问题欢迎在评论区留言或私信,希望大家能够多多点赞收藏,你们的点赞收藏就是我创作的动力喔!

你可能感兴趣的:(selenium,python,selenium,自动化,爬虫)