最近遇到了一个问题,QQ邮箱提示我空间已满,所以我就专门去看看有哪些邮件可以删除,释放点空间。
我直接暴力删除了很多文件夹的邮件,在文件夹管理界面 有“清空”按钮,点一个即可清空。
但是。。。不出意外的话要出意外了
“已发送”中有12w+邮件,但是它居然没有清空选项!!!
产品经理怎么想的?请出来狡辩狡辩。
如果我不知道邮件列表每页展示数量可以修改,使用默认的25条每页,那我将需要删除 120000/25 约等于4800次;
如果我改成每页显示的最大条数100,那么我将删除1200次才能删除完。。。即使不停的点全选、删除也要花费我20分钟以上。
作为程序员的我怎么能被这个打败呢?重复点击的事情交给程序去做吧。
原理
利用python的selenium库可以很方便地实现 查找控件、条件判断、自动点击等操作,所以这里推荐使用python来完成。
基本流程如下:
- 利用webdriver打开chrome界面
- 在界面中手动进行qq邮箱登录
- 切换到已发送界面
- 自动化程序开始工作
- 等待程序结束即可。
最终效果如下(全自动删除了一千多页邮件):
大概一秒钟不到就删除了一页,至于总共花了多久?我不记得了,hhh, 我也不需要记得。
代码
今天不想太啰嗦,直接上代码,感兴趣地看注释吧
由于该代码主要是用来解放双手,所以看起来可能没那么优雅,望大家见谅,轻喷。
import datetime
import json
import os.path
import time
from selenium.webdriver.support import expected_conditions as EC
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
chrome_options = Options()
# chrome_options.add_argument("--headless") # 启用无头模式
chrome_options.add_argument("--disable-gpu") # 禁用 GPU 硬件加速
chrome_options.add_argument("--no-sandbox") # 解决沙盒问题
service = Service('/usr/bin/chromedriver')
browser = webdriver.Chrome(options=chrome_options, service=service)
# browser.get('http://baidu.com')
print("start")
try:
print(datetime.datetime.now())
# https://mail.qq.com/cgi-bin/frame_html?sid=vIKUzEIdIy73Aztd&r=15a14fa632ba665b73d40ab865d5d901&lang=zh
browser.get('https://mail.qq.com/cgi-bin/frame_html?sid=vIKUzEIdIy73Aztd&r=15a14fa632ba665b73d40ab865d5d901&lang=zh')
if os.path.exists('cookies_180.json'):
# browser.delete_all_cookies() # 删除所有cookie信息
with open('cookies_180.json', 'r', encoding='utf-8') as f:
cookie_list = json.loads(f.read())
for cookie in cookie_list:
browser.add_cookie(cookie)
browser.get('https://mail.qq.com/cgi-bin/frame_html?sid=vIKUzEIdIy73Aztd&r=15a14fa632ba665b73d40ab865d5d901&lang=zh')
browser.refresh()
time.sleep(1)
hasStoreCookie = False
while True:
try:
# 第一步 手动进行qq邮箱登录
# 第二步 等待并找到类名为 '升级为邮箱会员' 的元素.目的:判断是否已经登录
element = WebDriverWait(browser, 10).until(
EC.presence_of_element_located((By.LINK_TEXT, '升级为邮箱会员'))
)
print("Element 升级为邮箱会员 found!")
# 第三步 查找所有 iframe 元素
iframes = browser.find_elements(By.TAG_NAME, 'iframe')
# 打印每个 iframe 的信息
for index, iframe in enumerate(iframes):
print(f"Iframe {index + 1}:")
print(f"src: {iframe.get_attribute('src')}")
print(f"id: {iframe.get_attribute('id')}")
print(f"name: {iframe.get_attribute('name')}")
# 切换到当前 iframe,很关键!!!
browser.switch_to.frame(iframe)
# 查找元素(例如,查找 class 为 'txt_title' 的元素)
try:
element = browser.find_element(By.CLASS_NAME, 'txt_title')
print(f"Element found in Iframe {index + 1}: {element.text}")
except Exception as e:
print(f"Element not found in Iframe {index + 1}. Error: {e}")
try:
# 处于已发送界面
selectAll = browser.find_element(By.ID, 'ckb_selectAll')
print("click select all")
if selectAll.is_selected() is not True:
selectAll.click()
except Exception as e:
print(f"Element ckb_selectAll not found in Iframe {index + 1}. Error: {e}")
try:
# 处于已发送界面
delete = browser.find_element(By.ID, 'quick_del')
print("click delete")
delete.click()
time.sleep(0.5)
# 切换回主文档
browser.switch_to.default_content()
break
except Exception as e:
print(f"Element quick_del not found in Iframe {index + 1}. Error: {e}")
try:
# 请求太快触发了限制界面,需要返回并睡眠几秒中
delete = browser.find_element(By.LINK_TEXT, '您请求的频率太快,请稍后再试')
print("click too quickly")
deleteBtn = browser.find_element(By.LINK_TEXT, ' 返回上一步 ')
print("click too quickly")
deleteBtn.click()
time.sleep(5)
break
except Exception as e:
print(f"Element quick_del not found in Iframe {index + 1}. Error: {e}")
# 切换回主文档
browser.switch_to.default_content()
time.sleep(0.3)
if hasStoreCookie is False:
hasStoreCookie = True
cookies = browser.get_cookies()
with open('cookies_180.json', 'w') as f:
print('save cookies')
f.write(json.dumps(cookies))
except Exception as e:
print('str Error:', repr(e))
# 可能是正在登录,找不到元素,稍微等等
time.sleep(2)
except Exception as e:
print('str Error:', e)
print(str(e))
error_msg = repr(e)
print('repr Error:')
if 'NoSuchElementException' in error_msg:
print('没找到元素')
else:
print(repr(e))
finally:
time.sleep(2)
print('---------关闭浏览器---------')
# 关闭窗口
browser.close()
# 退出浏览器
browser.quit()
print(datetime.datetime.now())
踩过的坑
整个过程并不是一帆风顺的,说说遇到的坑吧
为了减少登录流程,需要保存cookie并恢复cookie
设置cookie之前,必须先加载指定的url。
比如 要设置mail.qq.com对应的cookie,要先加载mail.qq.com相关的域名,是不是有点反直觉?我加载域名之后,你才设置cookie那不晚了吗?
我的做法是:先加载再设置再刷新,这样就能保证后面加载的域名一定是用到了我设置的cookie。
但实际测试发现:在刷新之前以登录的界面就已经显示出来了,可能是我想多了,设置cookie的速度很快,不会影响页面加载。
明明页面存在那个元素,但却一直报 NoSuchElementException
这个坑可厉害了,在网上搜索查看了很多资料都说的是 要等待页面加载完成。。。我都能看到页面并且有些元素已经能查到,当然已经加载完成,排除这个原因。
最后问chatgpt才知道可能是frame/iframe的问题:一个页面加载了其他网页,查找元素时需要切换到对应的frame才可以。详见代码。
chrome界面怎么没看到?
刚开始从网上抄来的模板,稍加修改后运行,发现chrome界面没有出现。原因:
添加了 --headless 参数,注释掉即可。
总结
身为程序员,必须学会利用代码解决一些重复的操作来解放双手,你说对吗?