python网易邮箱删除邮件

| 分类 python  | 标签 requests  selenium  js  爬虫  浏览次数: -

起因

在工作中因为用到了邮箱告警,所以导致测试邮箱帐号中积累了非常多(上万封)的垃圾邮件,导致了这个帐号的邮箱无法使用,希望有简单的方式可以把所有邮件都删除掉.以下是实践的几种方法.每种都经过了测试,没有问题.

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通过爬虫的方式来把这个删除邮件的功能实现,也算是业余时间的学习吧.


上一篇 Linux adb安装     下一篇 su,su -, sudo区别
目录导航