实战02-selenium模拟QQ邮箱登录并批量爬取指定邮件的附件——体验版
1.功能需求
诞生的背景:作为一个学委,尤其受疫情影响,同学发的一大堆邮件单个下载非常耗时,而且无聊。
由此想到了用爬虫可以批量抓取,学了一天,果断四处找资源,终于可以解放收作业了(不过,还有待完善的地方,后面再贴出来)
这个爬虫脚本实现的功能:首先模拟用户登录(通过账号、密码)qq邮箱,然后进去收件箱后,获取已读/未读的邮件列表,
写了个正则表达式用于筛选指定的邮件(可按需你需求替换正则模板即可),接着点进去下载附件(也就是,这也有个隐式条件,
里面一定要有附件,且只下载一个,这也是不够完善的地方)。下载完后直接返回,如此循环遍历(怪我写的很粗糙:)批量下载指定的文件
2.直接上代码
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from config import *
import time
import re
# 这里是浏览器驱动路径,也可防止系统环境变量就不用指定了
browser = webdriver.Chrome(executable_path="./chromedriver.exe")
wait = WebDriverWait(browser, 10) # 设置下隐式等待时间10s
def mail_qq_login():
try:
browser.get("https://mail.qq.com/")
browser.switch_to.frame("login_frame")
login_bt = wait.until(
EC.presence_of_element_located((By.CSS_SELECTOR, '#switcher_plogin'))
)
login_bt.click() # 账号密码登录
qq_nb = wait.until(
EC.presence_of_element_located((By.ID,"u"))
)
qq_pw = wait.until(
EC.presence_of_element_located((By.ID,"p"))
)
login_bt = wait.until(
EC.element_to_be_clickable((By.CSS_SELECTOR,"#login_button"))
)
qq_nb.send_keys(QQ_NB) # 账号 QQ_NB和QQ_PW放置在配置文件中,注意替换
qq_pw.send_keys(QQ_PW) # 密码
login_bt.click()
except TimeoutException:
print("超时错误,重新登录...")
mail_qq_login()
pattern = re.compile("^机.*17.*") # 注意:这里需替换成你想爬取什么主题的邮件
def print_one_unread_mail(index):
try:
print(browser.page_source)
mail_list = browser.find_elements_by_css_selector('.tf.no')
print("print_one_unread_mail:%d" % len(mail_list))
if re.match(pattern, mail_list[index].find_element_by_class_name('tt').text):
print(mail_list[index].find_element_by_class_name('tt').text)
mail_list[index].click()
browser.find_element_by_partial_link_text("下载").click()
print(browser.page_source)
browser.back()
time.sleep(2)
browser.refresh()
recv_option = wait.until(
EC.presence_of_element_located((By.PARTIAL_LINK_TEXT, "收件箱"))
)
recv_option.click()
main_frame = wait.until(
EC.presence_of_element_located((By.CSS_SELECTOR, "#mainFrame"))
)
browser.switch_to.frame(main_frame)
else:
print(mail_list[index].find_element_by_class_name('tt').text)
return
except TimeoutException:
print_one_unread_mail(index)
def main():
mail_qq_login()
recv_option = wait.until(
EC.presence_of_element_located((By.PARTIAL_LINK_TEXT, "收件箱"))
)
recv_option.click()
main_frame = wait.until(
EC.presence_of_element_located((By.CSS_SELECTOR, "#mainFrame"))
)
browser.switch_to.frame(main_frame)
mail_list = browser.find_elements_by_class_name("M")
mail_num = len(mail_list)
print(mail_num)
mail_list = browser.find_elements_by_css_selector('.tf.no')
print(len(mail_list))
for i in range(len(mail_list)):
print(i)
print_one_unread_mail(i)
if __name__ == '__main__':
main()
3.数据作证

4.掉坑经历
如图所示,道路千万条,安全第一条。。。

解决:采取了个简单的办法,在for循环每次调用print_un_read_mail前 睡眠一会,time.sleep(x)
有更好的办法,欢迎交流呀(我是爬虫小白)
此外,还有几个特别需注意的地方:
1.模拟登陆时,因为腾讯(不止qq邮箱,还有qq)的登陆页面用的是iframe,故先切换到登录的iframe才能找到用账号密码登录的选项
2.进去“收件箱”后,注意切换回“mainFrame”<----很重要,我掉坑了(一直定位不到邮件的主题元素),还折腾了好久
3.返回之后,记得刷新一下(因为qq邮箱用了JS动态渲染),里面iframe的上下文在返回后会刷新,再次定位元素会
找不到的,如这个报错:element is not attach to the page document,就是页面过时的问题