起因
在工作中因为用到了邮箱告警,所以导致测试邮箱帐号中积累了非常多(上万封)的垃圾邮件,导致了这个帐号的邮箱无法使用,希望有简单的方式可以把所有邮件都删除掉.以下是实践的几种方法.每种都经过了测试,没有问题.
JS删除
通过浏览器的开发者工具,在审查元素中找到对应元素的class name(为什么不用id, 网易邮箱的id会动态变化),再通过js对该元素进行操作
通过js删除网易已发送
邮箱
- 直接在console中输入下列代码即可,不用id的原因是id一直在变
- 找到对应的class下标
a = document.getElementsByClassName("js-component-checkbox-dc")
for (i=0; i<a.length;i++){
console.log(i + a[i].innerHTML);
}
- 执行定时删除操作
window.setInterval(function (){
document.getElementsByClassName("js-component-checkbox-dc")[0].click();
document.getElementsByClassName("js-component-button")[1].click();
}, 1000);
通过js删除网易已删除
邮箱
- 直接在console中输入下列代码即可,不用id的原因是id一直在变
window.setInterval(function (){
document.getElementsByClassName("js-component-checkbox-dc")[0].click();
document.getElementsByClassName("js-component-button")[1].click();
document.getElementsByClassName("nui-mainBtn")[0].click();
}, 1000);
Python删除
通过浏览器的开发者工具,发现登录/查询/删除等接口的API,然后再通过python的requests包发送对应的请求.主要难点在于发现所有使用的API,网易邮箱对应了多个版本的API,要找到能正确访问的API.
1.Python 版本2.7 2.依赖requests包
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import re
import requests
class Email163(object):
def __init__(self, username, password):
"""网易163邮箱登录
"""
self.username = username # 邮箱用户名
self.password = password # 邮箱密码
self.req_session = requests.Session() # 所有请求用同一个session,保证登录后不失效
self.sid = self.get_sid() # 登录一次后, sid不用变,所以不用每次操作都获取sid
def get_sid(self):
"""获取sid
:rtype str
:return
网易邮箱的认证 sid, 在后续所有的请求中都会带上sid,作为登录成功的标识
"""
headers = {
'Host': 'mail.163.com',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': 'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3',
'Accept-Encoding': 'gzip, deflate, br',
'Referer': 'http://email.163.com/',
'Connection': 'keep-alive',
'Upgrade-Insecure-Requests': '1'
}
data = {
'username': self.username,
'url2': 'http://email.163.com/errorpage/error163.htm',
'savalogin': '0',
'password': self.password
}
params = {
'funcid': 'loginone',
'language': -1,
'passtype': 1,
'iframe': 1,
'product': 'mail163',
'from': 'web',
'df': 'email163',
'race': '-2_-2_-2_db',
'module': '',
'uid': self.username,
'style': -1,
'net': 'c',
'skinid': 'null'
}
url = 'https://mail.163.com/entry/cgi/ntesdoor'
response = self.req_session.post(url=url, headers=headers, data=data, params=params)
sid = re.search(r'(?<=sid=).+(?=&df=email163)', response.text).group(0)
return sid
@staticmethod
def get_id_param(content):
"""把id组合成参数
解析api中返回的xml格式内容,在组合出后续操作需要的数据格式
:rtype str, int
:return id字符串, id的数量
"""
pattern = re.compile(r'<string name="id">(\d+:.+)</string>')
result = pattern.findall(content)
id_param = "<string>{}</string>".format("</string><string>".join(result))
return id_param, len(result)
def get_inbox(self):
"""收件箱列表
:rtype str
:return API请求返回的数据
"""
url = 'http://mail.163.com/js6/s'
params = {
'sid': self.sid,
'func': 'mbox:listMessages',
'LeftNavfolder1Click': 1,
'mbox_folder_enter': 1
}
data = {
'var': '<?xml version="1.0"?><object><int name="fid">1</int><string name="order">date</string>'
'<boolean name="desc">true</boolean><int name="limit">100</int><int name="start">0</int>'
'<boolean name="skipLockedFolders">false</boolean><string name="topFlag">top</string>'
'<boolean name="returnTag">true</boolean><boolean name="returnTotal">true</boolean></object>'
}
response = self.req_session.post(url=url, data=data, params=params)
content = response.content
return content
def get_deleted(self):
"""已删除邮箱列表
:rtype str
:return API请求返回的数据
"""
url = 'http://mail.163.com/js6/s'
params = {
'sid': self.sid,
'func': 'mbox:listMessages',
'LeftNavfolder1Click': 1,
'mbox_folder_enter': 4
}
data = {
'var': '<?xml version="1.0"?><object><int name="fid">4</int><string name="order">date</string>'
'<boolean name="desc">true</boolean><int name="limit">10</int><int name="start">0</int>'
'<boolean name="skipLockedFolders">false</boolean><boolean name="returnTag">true</boolean>'
'<boolean name="returnTotal">true</boolean></object>'
}
response = self.req_session.post(url=url, data=data, params=params)
content = response.content
return content
def get_send(self):
"""已发送邮箱列表
:rtype str
:return API请求返回的数据
"""
url = 'http://mail.163.com/js6/s'
params = {
'sid': self.sid,
'func': 'mbox:listMessages',
'LeftNavfolder1Click': 1,
'mbox_folder_enter': 1
}
data = {
'var': '<?xml version="1.0"?><object><int name="fid">1</int><string name="order">date</string>'
'<boolean name="desc">true</boolean><int name="limit">100</int><int name="start">0</int>'
'<boolean name="skipLockedFolders">false</boolean><string name="topFlag">top</string>'
'<boolean name="returnTag">true</boolean><boolean name="returnTotal">true</boolean></object>'
}
response = self.req_session.post(url=url, data=data, params=params)
content = response.content
return content
def delete_deleted(self):
"""删除已删除邮箱
"""
url = 'http://mail.163.com/js6/s'
params = {
'sid': self.sid,
'func': 'mbox:deleteMessages',
'mbox_toolbar_permanentdeleted': 1
}
id_param, count = self.get_id_param(self.get_deleted())
data = {
'var': '<?xml version="1.0"?><object><array name="ids">{id_param}</array></object>'.format(
id_param=id_param)
}
response = self.req_session.post(url=url, data=data, params=params)
print response.status_code
return count
def delete_send(self):
"""删除已发送邮箱
"""
url = 'http://mail.163.com/js6/s'
params = {
'sid': self.sid,
'func': 'mbox:updateMessageInfos',
'mbox_toolbar_permanentdeleted': 1
}
id_param, count = self.get_id_param(self.get_send())
data = {
'var': '<?xml version="1.0"?><object><array name="ids">{id_param}</array><object name="attrs">'
'<int name="fid">4</int></object></object>'.format(id_param=id_param)
}
response = self.req_session.post(url=url, data=data, params=params)
print response.status_code
return count
def delete_inbox(self):
"""删除收件箱
"""
url = 'http://mail.163.com/js6/s'
params = {
'sid': self.sid,
'func': 'mbox:updateMessageInfos',
'mbox_toolbar_allornone': 1,
'mbox_toolbar_movetodeleted': 1
}
id_param, count = self.get_id_param(self.get_inbox())
data = {
'var': '<?xml version="1.0"?><object><array name="ids">{id_param}</array><object name="attrs">'
'<int name="fid">4</int></object></object>'.format(id_param=id_param)
}
response = self.req_session.post(url=url, data=data, params=params)
print response.status_code
return count
def delete_email():
"""删除邮箱邮件
"""
name = "xxx@163.com"
pwd = "xxx"
manager = Email163(name, pwd)
func_list = [
manager.delete_inbox, # 收件箱
manager.delete_send, # 已发件箱
manager.delete_deleted # 已删除
]
# 收件箱,发件箱,已删除的邮件全部删除后结束
for func in func_list:
while True:
try:
count = func()
except Exception as e:
print("执行函数: {} 发生了错误: {}".format(func.__name__, e.message))
break
else:
if count <= 0:
break
if __name__ == '__main__':
delete_email()
Browser
通过 selenium 模拟人的点击操作,重复的点击要删除的邮件
1.Python 版本2.7 2.依赖谷歌浏览器 3.依赖谷歌浏览器的驱动 4.依赖 selenium 包
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import time
from selenium import webdriver
class Email163(object):
def __init__(self, username, password):
self.username = username # 163邮箱用户名
self.password = password # 163邮箱密码
self.driver = webdriver.Chrome() # 获取浏览器
self.driver.maximize_window() # 把浏览器窗口最大化
self.load_time = 5 # 加载页面等待的秒数
def _login(self):
"""登录邮箱
"""
url = "http://mail.163.com/"
iframe_name = "x-URS-iframe"
# 打开页面
self.driver.get(url)
# 点击邮箱登录
self.driver.find_element_by_id('lbNormal').click()
time.sleep(1)
# 切换到表单
self.driver.switch_to.frame(iframe_name)
# 输入用户名密码
self.driver.find_element_by_name("email").send_keys(self.username)
self.driver.find_element_by_name("password").send_keys(self.password)
# 点击登录按钮
self.driver.find_element_by_id('dologin').click()
# 可能会出现验证码, 10 输入验证码的时间
self.sleep_time(10)
# curr_handler = driver.current_window_handle
# 从iframe中退出回到主页面中
self.driver.switch_to.default_content()
@staticmethod
def sleep_time(seconds=1):
"""休眠 `seconds` 秒后再继续操作
:param seconds: int 等待的秒数 default=1
"""
time.sleep(seconds)
def _do_check_box(self, box_message=None):
"""检查邮件是否全部被删除了
:param box_message: str 检查的xpath
:rtype bool
:return
True: 还未删除干净
False: 邮件已经删除干净
"""
# 通过判断字符串在网页中不准确,字符串被隐藏掉了
# html = self.driver.page_source
# result = False
# if message.decode("utf-8") in html:
# result = True
if box_message is None:
box_message = "/html/body/div[2]/div[1]/div[2]/header/div/div[1]/div/span[1]/span"
result = False
try:
# 选中全选框
self.driver.find_element_by_xpath(box_message).click()
result = True
except Exception as e:
# 选择全选框操作失败了, 说明邮件都被删除了
print("选中全选框失败: {}".format(e.message))
return result
def _click_delete_button(self):
"""点击删除按钮
"""
self.driver.find_element_by_xpath("/html/body/div[2]/div[1]/div[2]/header/div[1]/div[2]/div").click()
def _delete_inbox(self):
"""删除收件箱内的邮件
检查全选框是否能选中
能:
执行删除操作,再次回到 重复上一步检查
不能:
认为该项中的邮件都被删除了,继续下一步
"""
# 点击收件箱
self.driver.find_element_by_xpath("/html/body/div[1]/nav/div[2]/ul/li[1]").click()
self.sleep_time(self.load_time)
while self._do_check_box():
self.sleep_time()
# 点击删除按钮
self._click_delete_button()
self.sleep_time()
else:
print("收件箱所有邮件都被删除了")
def _delete_sent(self):
"""删除已发送的邮件
检查全选框是否能选中
能:
执行删除操作,再次回到 重复上一步检查
不能:
认为该项中的邮件都被删除了,继续下一步
"""
# 点击已发送
self.driver.find_element_by_xpath("/html/body/div[1]/nav/div[2]/ul/li[6]").click()
self.sleep_time(self.load_time)
while self._do_check_box():
self.sleep_time()
# 点击删除按钮
self._click_delete_button()
self.sleep_time()
else:
print("已发送的所有邮件都被删除了")
def _delete_deleted(self):
"""删除已删除中的邮件
检查全选框是否能选中
能:
执行删除操作
执行确认操作
重复上一步检查
不能:
认为该项中的邮件都被删除了,继续下一步
"""
# 点击已删除
self.driver.find_element_by_xpath("/html/body/div[1]/nav/div[2]/ul/li[7]").click()
self.sleep_time(self.load_time)
while self._do_check_box():
self.sleep_time()
# 点击删除按钮
self._click_delete_button()
error_message = []
# div数量不确定
for i in range(3, 12):
try:
# 确认删除
self.driver.find_element_by_xpath("/html/body/div[{}]/div[3]/div[2]/div[1]".format(i)).click()
except Exception as e:
message = "{}: {}".format(i, e.message)
error_message.append(message)
else:
if error_message:
print("尝试了 {} 次才成功, {}".format(len(error_message), "\t".join(error_message)))
else:
print("尝试一次就删除成功")
break
self.sleep_time()
else:
print("已删除中的所有邮件都被删除了")
def _run(self):
"""执行删除的业务逻辑
1. 登录
2. 删除收件箱中的邮件
3. 删除已发送中的邮件
4. 删除已删除中的邮件
"""
self._login()
# 登录成功后等待页面加载完成
self.sleep_time(self.load_time)
self._delete_inbox()
self._delete_sent()
self._delete_deleted()
def run(self):
try:
self._run()
except Exception as e:
print("执行操作发生了错误: {}".format(e.message))
finally:
self.driver.close()
self.driver.quit()
def main():
username = "" # 163邮箱用户名
password = "" # 163邮箱密码
manager = Email163(username, password)
manager.run()
if __name__ == '__main__':
main()
总结
整个删除的过程中还会碰到了许多问题,像通过selenium删除
已删除
中的邮箱时,需要确认操作,但确定
这个button的xpath
是会动态变化的,所有需要对应不同的处理方式.同时调整等待的时间.
最开始我使用的是通过第一种方式
js
来进行删除,易操作.首先完成我自己想要的功能,后面才想着用python通过爬虫的方式来把这个删除邮件的功能实现,也算是业余时间的学习吧.