python想要保存QQ邮箱富途的附件

来源:互联网 发布:珀莱雅淘宝店真假 编辑:程序博客网 时间:2024/05/01 02:31

一、前言


对于编程来说,我期望的是并不仅仅用于make money,而是出于生活,融于生活。 
最近炒股,每天都会有一封邮件发到我的QQ邮箱,里面有今天账户的结算信息,感觉这个挺有意义的,可以记录每天的交易情况和相关费用,但是我又不想每天去下载这个附件。于是乎花了一个晚上研究了一下python的poplib库,完成了一个拉取QQ邮箱附件的程序。

二、实现

2.1 poplib是什么?

poplib是一个python的一个模块,用于专门的处理邮箱的邮件,是基于pop3的协议。使用的话用import poplib就可以了。

2.2 代码说明

想要解析邮件分为几个步骤:

  • 第一步:创建链接
        pop_conn = poplib.POP3_SSL(self.host)          pop_conn.set_debuglevel(self.debugMode)         pop_conn.user(self.user)          pop_conn.pass_(self.pass_) 
  • 1
  • 2
  • 3
  • 4
使用poplib库创建一个SSL的链接,然后分别设置这个connect的几个参数,分别是:- debugmode:0为关闭,1为开启。如果开启的话,会显示交互时的日志。- username :邮箱的账号- password :邮箱的密码- host : 对应的邮箱的pop3协议的host,qq邮箱是pop.qq.com

注:这里有个坑爹的东西,如果直接用qq密码用作password的话,会提示这个报错 poplib.error_proto: -ERR Please using authorized code to login. 
这里写图片描述

跟着这个链接进去看,是因为qq出于安全的考虑,使用pop协议的时候,需要使用一个16位的密保来进行操作。按照链接里面的提示设置好了密码,再填入就可以使用了。

  • 第二步:获取邮件

几个主要的API:

pop_conn.stat()pop_conn.list()pop_conn.retr()
  • 1
  • 2
  • 3

stat()用于获取邮件的状态,例如:有46封邮件 
Messages: 46. Size: 3819672

list()用于获取邮件的列表状态: 
(‘+OK’, [‘1 196394’, ‘2 35328’, ‘3 195761’, ‘4 19024’, ‘5 63952’, ‘6 196662’, ‘7 45720’, ‘8 197030’, ‘9 15565’, ‘10 36985’, ‘11 2550’, ‘12 31237’, ‘13 26712’, ‘14 18984’, ‘15 15990’, ‘16 12196’, ‘17 21966’, ‘18 194291’, ‘19 194885’, ‘20 126483’, ‘21 14534’, ‘22 29710’, ‘23 196006’, ‘24 13974’, ‘25 34424’, ‘26 195320’, ‘27 202168’, ‘28 24900’, ‘29 22061’, ‘30 7843’, ‘31 53405’, ‘32 7958’, ‘33 7913’, ‘34 200682’, ‘35 5349’, ‘36 15979’, ‘37 34286’, ‘38 53619’, ‘39 198150’, ‘40 25144’, ‘41 7366’, ‘42 196818’, ‘43 214880’, ‘44 196847’, ‘45 18007’, ‘46 194614’], 461)

pop_conn.retr()则是用于获取每封邮件的状态了

  • 第三步:解析邮件

分为两步: 
1、先把pop_conn.retr()获得的一封邮件格式化一下,把其中的分割符化成”\n”(具体这一步的意义我没有深究,应该是方便email模块去解析)

        messages = ["\n".join(mssg[1]) for mssg in messages]  
  • 1
  • 2

注意每个邮件mssg里面只有mssg[1]是内容。

2、然后对邮件进行解析转化成Message对象

        messages = [Parser().parsestr(mssg) for mssg in messages]  
  • 1
  • 2

3、然后就可以获取到对应的邮件内容了

直接获取了主题:msg.get('subject')时间:msg.get('Date')发件人:email.utils.parseaddr(msg.get('from'))[1] 收件人:email.utils.parseaddr(msg.get('to'))[1]
  • 1
  • 2
  • 3
  • 4
  • 5

不过这些我都不需要,我只需要里面的附件内容。

4、保存附件

        for part in msg.walk():            fileName = part.get_filename()              # 保存附件            if fileName:                  fname = self.decode_str(fileName)                fEx = open("%s%s"%(self.savePath,fname), 'wb')                data = part.get_payload(decode=True)                  fEx.write(data)                  fEx.close()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

遍历一下msg,如果有附件就存下来,这里需要注意的是需要对文件的名字进行解码。 
然后找个目录存下来吧。

这里写图片描述

有个问题,不知道为什么只能取到最近的一个月的邮件,有点奇怪,不知道是不是QQ邮箱的限制了。

三、源码

#!/usr/bin/python#-*- encoding: utf-8 -*-# @auth atany 347702498@qq.com# blog : http://blog.csdn.net/yang8456211import poplib from email.parser import Parserfrom email.header import decode_headerfrom email.utils import parseaddrimport emailimport osimport sys reload(sys) sys.setdefaultencoding('utf-8') # 默认的编码是ASCII..class MailManager:    # 测试的邮件数量 0为所有    testLimitMailCount  = 0    def __init__(self, host, username, password, savePath, debugMode = 0):        self.host = host        self.user = username        self.pass_ = password        self.debugMode = debugMode        self.savePath = savePath    def _download_mail(self):        print "...\n============ Begin to DownLoad ============"        pop_conn = poplib.POP3_SSL(self.host)          pop_conn.set_debuglevel(self.debugMode)         pop_conn.user(self.user)          pop_conn.pass_(self.pass_)         print('Messages: %s. Size: %s' % pop_conn.stat())        ## 格式('+OK', ['1 12515', '2 196394', '3 35328', '4 195761', '5 19024'], 471)        print pop_conn.list()        messages = []        for i in range(1, len(pop_conn.list()[1]) + 1):            #print pop_conn.retr(i)            messages.append(pop_conn.retr(i))            # 太多了不好测试,限制一下            if 0 != self.testLimitMailCount and i >= self.testLimitMailCount:                break        # mssg[1]为内容正文,加个回车换行把逗号分隔符,链接成一个完整字符串        messages = ["\n".join(mssg[1]) for mssg in messages]          # 转化为邮件实例的Message对象        messages = [Parser().parsestr(mssg) for mssg in messages]          #print messages        for i in range(0, len(messages)):            msg = messages[i]            self._save_email(msg ,i)    def _save_email(self, msg, index):        # 其他的可能用到的属性        mailName = "Mail[%d]-%s.log - %s" % (index, self.decode_str(msg.get('subject')),msg["Date"])          print mailName        # mailName = "Mail[%d].log" % (index)          # print mailName        # print os.getcwd()        # file_ = open(mailName, 'w')        # print >> file_, "Date: ", msg["Date"]          # print >> file_, "From: ", email.utils.parseaddr(msg.get('from'))[1]          # print >> file_, "To: ", email.utils.parseaddr(msg.get('to'))[1]          # print >> file_, "Subject: ", self.decode_str(msg.get('subject'))  #主题 =?gbk?B?zfjJz7m6xrHPtc2zLdPDu6fWp7i2zajWqg==?=        # print >> file_, "Data: "        # 我只想要富途的附件        From = email.utils.parseaddr(msg.get('from'))[1]        if "@futu5.com" not in From:            return        for part in msg.walk():            fileName = part.get_filename()              # contentType = part.get_content_type()            # mycode=part.get_content_charset()            # 保存附件            if fileName:                  fname = self.decode_str(fileName)                fEx = open("%s%s"%(self.savePath,fname), 'wb')                data = part.get_payload(decode=True)                  fEx.write(data)                  fEx.close()        #file_.close()      def decode_str(self, s):        # # 下面的三行代码只是为了解码        # h = email.Header.Header(subject)        # # dh:内容+编码[('\xcd\xf8\xc9\xcf\xb9\xba\xc6\xb1\xcf\xb5\xcd\xb3-\xd3\xc3\xbb\xa7\xd6\xa7\xb8\xb6\xcd\xa8\xd6\xaa', 'gbk')]        # dh = email.Header.decode_header(h)        # if None != dh[0][1] and None != dh[0][0]:        #     subject = unicode(dh[0][0], dh[0][1]).encode('utf8')        value, charset = decode_header(s)[0]        if charset:            value = value.decode(charset)        return value    def _display_email(self, msg):        pass    def _display_info(self):        print "============ DisplayInfo Begin ============"        print "username : " , self.user        print "password : " , self.pass_        print "host : " , self.host        print "============ DisplayInfo End ============"if __name__ == '__main__':    host = 'pop.qq.com'      username = ''    # QQ邮箱这里改成16位的密保了,这里有个问题,一旦修改了密码或者独立密码,需要重新去生成一下密保    # 这里输入自己的密保就可以了    password = ''    # 不传debugMode 就是默认为0,不显示服务器日志    debugMode = 0    #保存附件的位置    savePath = "/Users/yangguang/Documents/stock/"    mailManager = MailManager(host, username, password, savePath, debugMode)    mailManager._display_info()    mailManager._download_mail()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134

四、后续问题

1)可以是用定时任务做个每天定时拉取应该不错。 
2)关于文章中的一些转码问题还是头疼了一小会,没想到系统的defaultencoding是ASCII.. 所以要在文件头加上

import sys reload(sys) sys.setdefaultencoding('utf-8') # 默认的编码是ASCII..
  • 1
  • 2
  • 3

关于解码: 
使用这个解码方法解出dh也是可以的,dh[0][0]是内容,dh [0][1]是当前的编码。

这里写图片描述

3)关于各个邮箱的pop协议的host可以自行百度 
例如: 
pop.163.com是网易的 

pop.live.com是微软的




宁波整容医院http://www.lyxcl.org/

原创粉丝点击