用Python从Gmail中提取信息

8
我已经找到了从Gmail邮箱中选定的电子邮件中提取有用信息的解决方案。
在这个例子中,目标是获取所有来自提供石油月度价格的新闻通讯的邮件。您可以在EIA网站上自由订阅此类通讯。所有这些通讯都会到达我的Gmail邮箱中的同一个文件夹,并以“$”开头。
邮件的内容如下所示:
(图片)
我的目标是编写一个脚本,获取最近10封此类邮件(最近10个月)并绘制不同美国地区的石油价格随时间变化的图表。
2个回答

26

Python的email库将提供帮助。

import email, getpass, imaplib, os, re
import matplotlib.pyplot as plt

这个目录是您保存附件的位置。

 detach_dir = "F:\OTHERS\CS\PYTHONPROJECTS"  

您的脚本随后会要求用户(或您自己)提供帐户功能

user = raw_input("Enter your GMail username --> ")
pwd = getpass.getpass("Enter your password --> ")

连接到 Gmail IMAP 服务器并登录。

m = imaplib.IMAP4_SSL("imap.gmail.com")
m.login(user, pwd)

选择一个文件夹,您可以使用整个收件箱代替

m.select("BUSINESS/PETROLEUM")    

使用m.list()获取所有邮箱。搜索来自指定发件人的所有电子邮件并选择邮件id:

resp, items = m.search(None, '(FROM "EIA_eLists@eia.gov")')
items = items[0].split()  

my_msg = [] # store relevant msgs here in please
msg_cnt = 0
break_ = False

我想获取最新的电子邮件,因此我使用了 items[::-1]

for emailid in items[::-1]:

    resp, data = m.fetch(emailid, "(RFC822)")

    if ( break_ ):
        break

    for response_part in data:

      if isinstance(response_part, tuple):
          msg = email.message_from_string(str(response_part[1]))
          varSubject = msg['subject']
          varDate = msg['date']

我只想得到那些以$开头的元素。
          if varSubject[0] == '$':
              r, d = m.fetch(emailid, "(UID BODY[TEXT])")

              ymd = email.utils.parsedate(varDate)[0:3]
              my_msg.append([ email.message_from_string(d[0][1]) , ymd ])

              msg_cnt += 1

我只想要最后的100条消息。
              if ( msg_cnt == 100 ):
                  break_ = True

l = len(my_msg)
US, EastCst, NewEng, CenAtl, LwrAtl, Midwst, GulfCst, RkyMt, WCst, CA = 
[0]*l, [0]*l, [0]*l, [0]*l, [0]*l, [0]*l, [0]*l, [0]*l, [0]*l, [0]*l 
absc = [k for k in range(len(my_msg))]
dates = [str(msg[1][2])+'-'+str(msg[1][3])+'-'+str(msg[1][0]) for msg in my_msg]
cnt = -1

for msg in my_msg:

    data = str(msg[0]).split("\n")
    cnt+=1
    for c in [k.split("\r")[0] for k in data[2:-2]]: 

使用正则表达式提取相关信息

        m = re.match( r"(.+)(=3D\$)(.+)" , c )  
        if( m == None ):
            continue 

        country, na, price = m.groups()

        if ( country == "US" or country == "USA" ) :
            US[cnt] = float(price)
        elif( country == "NewEng" ) :
            EastCst[cnt] = float(price)    
        elif( country == "EastCst" ) :
            NewEng[cnt] = float(price)  
        elif( country == "EastCst" ) :
            CenAtl[cnt] = float(price) 
        elif( country == "EastCst" ) :
            LwrAtl[cnt] = float(price)
        elif( country == "EastCst" ) :
            Midwst[cnt] = float(price)
        elif( country == "EastCst" ) :
            GulfCst[cnt] = float(price)
        elif( country == "EastCst" ) :
            RkyMt[cnt] = float(price)
        elif( country == "EastCst" ) :
            WCst[cnt] = float(price)
        elif( country == "EastCst" ) :
            CA[cnt] = float(price)

用美国价格绘制所有这些曲线

plt.plot( absc, US )

plt.plot( absc, EastCst )    
plt.plot( absc, NewEng, '#251BE0' )    
plt.plot( absc, EastCst, '#1BE0BF' )
plt.plot( absc, CenAtl, '#E0771B' )
plt.plot( absc, LwrAtl, '#CC1BE0' )
plt.plot( absc, Midwst, '#E01B8B' ) 
plt.plot( absc, GulfCst, '#E01B3F' )
plt.plot( absc, RkyMt )
plt.plot( absc, WCst )
plt.plot( absc, CA )

plt.legend( ('US', 'EastCst', 'NewEng' , 'EastCst', 'CenAtl', 'LwrAtl', 'Midwst', 'GulfCst', 'RkyMt', 'WCst', 'CA')  )
plt.title('Diesel price')
locs,labels = plt.xticks(absc, dates)
plt.show()

以下是一些相关且有趣的主题

仅获取新邮件

提取邮件正文

转发带附件的电子邮件

在Gmail中提取邮件正文

这里只列出了三个领域的结果

美国价格


我在msg = email.message_from_string(response_part[1])这一行中遇到了错误,错误提示为TypeError: initial_value must be str or None, not bytes - Debdut Goswami
1
@DebdutGoswami 请尝试使用email.message_from_bytes()方法(因为您从responses_part获取的数据是bytes类型)。 - CypherX
mmwahhhhh,这很有用。 - Michael

0

这是一个关于编程的例子,使用Red Box进行操作,(免责声明,我是该软件的作者)。

首先,配置Gmail应用密码

第二步,获取消息:

from redbox import gmail

# Set credentials
gmail.username = "me@gmail.com"
gmail.password = "<PASSWORD>"

# Select an email folder
inbox = gmail["INBOX"]

# Search and process messages
msgs = inbox.search(from_="EIA_eLists@eia.gov")

第三步,形成数据框:

import pandas as pd

dfs = []
for msg in msgs:
    body = msg.text_body
    df = pd.DataFrame(
        line.split("=")
        for line in body.split("\n),
        columns=["Region", "Price"]
    )
    df["Date"] = msg.date
    df["Price"] = df["Price"].str[1:].astype("float")
    dfs.append(df)

df = pd.concat(dfs)

最后绘制数据框:
df.pivot_table(
    index="Date", 
    columns="Region", 
    values="Price", 
    aggfunc="sum"
).plot()

To install:

pip install redbox pandas matplotlib

Red Box 相关链接:


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接