再用python写一个文本处理的东东
朋友遇到一点麻烦,我自告奋勇帮忙。事情是这样的:
- 他们的业务系统中,数据来自一个邮箱;
- 每一个邮件包含一条记录;
- 这些记录是纯文本的,字段之间由一些特殊字符分隔;
- 他们需要从邮箱中批量取出每一封邮件,放到一个excel文件中。
这些对python来说,真是小菜一碟。(事后证明,还是有些小坑,让我头疼了好一会儿。)
因为是初学者,没有必要从python2起步,我直接用了python3。
首先是收信。邮箱不支持pop3取信,好在支持IMAP。查了一下,python3有专门的库可以做到。
然后是要用正则表达式处理文本。
生成excel需要用到什么什么第三方库,找了一下,没下下来。干脆就简单点,生成csv文件吧。
==============
def main():
M = imaplib.IMAP4_SSL("my-host.com","993")
t=0
try:
try:
M.login('my-username','my-password')
except Exception as e:
print('login error: %s' % e)
M.close() M.select('INBOX',False) # result, message = M.select()
# tips: 如果想找Essh邮件的话,使用
# type, data = M.search(None, '(SUBJECT "Essh")')
# 里面要用一个括号,代表是一个查询条件,可以同时指定多个查询条件,例如FROM xxxx SUBJECT "aaa",
# 注意,命令要用括号罩住(痛苦的尝试)
typ, data = M.search(None, 'ALL') msgList = data[0].split()
print("total mails:" + str(len(msgList)))
last = msgList[len(msgList) - 1]
# first = msgList[0]
# M.store(first, '-FLAGS', '(\Seen)')
# M.store("1:*", '+FLAGS', '\\Deleted') #Flag all Trash as Deleted
output=PATH+'\output.csv'
fp2=open(output, 'w') last_id=read_config()
count=0
for idx in range(int(last_id), len(msgList)):
print("curr id: "+str(idx)+'\n')
type,data=M.fetch(msgList[idx],'(RFC822)')
deal_mail(data, fp2)
count=count+1
if count>500:
break write_config(idx)
# print(str(idx))
print("OK!")
M.logout()
except Exception as e:
print('imap error: %s' % e)
M.close()
这是main()部分。主要是连接IMAP服务器、取信、调用处理函数。
我发现,IMAP提供的接口比较怪异。不管怎么说,没怎么掉坑,网上的资料都很齐全。关于搜索的语法以及删除和置为已读/未读的命令都放在注释里。
这里面的逻辑是:首先获取上次处理的序号last_id,从此处开始,处理500条信件。然后将新的last_id写入配置文件中,下次读取。
在写这个程序的时候,遇到的最多的麻烦是关于str和bytes类型的。因为网上许多代码都是来自python2,所以在python3中就遇到多次提示:
这个错:
content=content.replace(',', ',')
error: a bytes-like object is required, not 'str'
这个也错:
content=content.replace(',', bytes(','))
error: string argument without an encoding
最终这个才对了:
content=content.replace(bytearray(',','GBK'), ','.encode('GBK'))
可是当我继续要把半角双引号变成全角双引号时,情况又不一样:
matchObj = re.match( r'.*<body>(.*)</body>.*', content.decode('GBK'), re.M|re.I|re.S)
if matchObj:
found=matchObj.group(1) #邮件正文
aa=found.split('#$') #分解为一个个field
aa[9]=aa[9].replace('"', '“') #我靠前面的写法用不着了! content=content.replace(bytearray(',','GBK'), ','.encode('GBK'))
我汗。。。总之肯定里面有什么东西还不大明白,导致走了许多弯路。记录下来,利已助人吧。
以下是全部源码
#-*- coding:UTF-8 -*-
import imaplib, string, email
import os
import re CONFIG_FILE='last_id.txt'
PATH=os.path.split(os.path.realpath(__file__))[0] def main():
M = imaplib.IMAP4_SSL("my-host.com","993")
t=0
try:
try:
M.login('my-username','my-password')
except Exception as e:
print('login error: %s' % e)
M.close() M.select('INBOX',False) # result, message = M.select()
# tips: 如果想找Essh邮件的话,使用
# type, data = M.search(None, '(SUBJECT "Essh")')
# 里面要用一个括号,代表是一个查询条件,可以同时指定多个查询条件,例如FROM xxxx SUBJECT "aaa",
# 注意,命令要用括号罩住(痛苦的尝试)
typ, data = M.search(None, 'ALL') msgList = data[0].split()
print("total mails:" + str(len(msgList)))
last = msgList[len(msgList) - 1]
# first = msgList[0]
# M.store(first, '-FLAGS', '(\Seen)')
# M.store("1:*", '+FLAGS', '\\Deleted') #Flag all Trash as Deleted
output=PATH+'\output.csv'
fp2=open(output, 'w') last_id=read_config()
count=0
for idx in range(int(last_id), len(msgList)):
print("curr id: "+str(idx)+'\n')
type,data=M.fetch(msgList[idx],'(RFC822)')
deal_mail(data, fp2)
count=count+1
if count>500:
break write_config(idx)
# print(str(idx))
print("OK!")
M.logout()
except Exception as e:
print('imap error: %s' % e)
M.close() def main2():
path=os.path.split(os.path.realpath(__file__))[0]
input=path+'\input2.txt'
output=path+'\output.csv' fp=open(input, 'rb')
fp2=open(output, 'w')
if True:
line=fp.read()
pharse_content(fp2, line) def get_mime_version(msg):
if msg != None:
return email.utils.parseaddr(msg.get('mime-version'))[1]
else:
empty_obj()
def get_message_id(msg):
if msg != None:
return email.utils.parseaddr(msg.get('Message-ID'))[1]
else:
empty_obj() # 读config文件,获取上次最大id,从这个id开始读邮件
def read_config():
if os.path.isfile(PATH+"\\"+CONFIG_FILE):
_fp=open(PATH+"\\"+CONFIG_FILE)
id=_fp.read()
_fp.close()
else:
id=0
return id # 将本次处理的邮件的最大id写入config,以便下次读取
def write_config(id):
_fp=open(PATH+"\\"+CONFIG_FILE, 'w')
_fp.write(str(id))
_fp.close() def deal_mail(data, fp2):
msg=email.message_from_string(data[0][1].decode('GBK'))
messageid = get_message_id(msg)
print(messageid)
content=msg.get_payload(decode=True)
#print(content)
pharse_content(fp2, content, messageid) def pharse_content(fp2, content, messageid):
#将半角的 , 换成全角的 ,
# content=content.replace(',', ',') # error: a bytes-like object is required, not 'str'
# content=content.replace(',', bytes(',')) # error: string argument without an encoding
content=content.replace(bytearray(',','GBK'), ','.encode('GBK'))
# print(content.decode('GBK')) # strinfo=re.compile(',')
# content=strinfo.sub(',', content) # error: cannot use a string pattern on a bytes-like object matchObj = re.match( r'.*<body>(.*)</body>.*', content.decode('GBK'), re.M|re.I|re.S)
if matchObj:
found=matchObj.group(1) #邮件正文
aa=found.split('#$') #分解为一个个field # 获取申诉涉及号码。匹配模式:申诉问题涉及号码:18790912404;
mobileObj=re.match(r'.*申诉问题涉及号码:(.*);', aa[9], re.M|re.I|re.S)
if mobileObj:
mobile=mobileObj.group(1)
else:
mobile='' # bb 是结果数组,对应生成的csv文件的列
aa[9]=aa[9].replace('"', '“') #我靠前面的写法用不着了! content=content.replace(bytearray(',','GBK'), ','.encode('GBK')) bb=['']*40 #40个元素的数组,对应40个列
bb[3]=aa[0] #D列
bb[4]=aa[4] #E
bb[5]=mobile #F
bb[6]=aa[5] #G
bb[7]=aa[2] #H
bb[8]=aa[1] #I
bb[9]=aa[3] #J
bb[11]=aa[6] #L
bb[12]=aa[6] #M
bb[22]='网站' #W 申诉来源。此处可自行修改为指定类型
bb[36]='"'+aa[9]+'"' #AK,两侧加 "" 是为了保证多行文字都放进一个单元格中 DELI=','
# fp2.write("AAAAA,"+DELI.join(bb)+"\\n")
fp2.write(DELI.join(bb)+"\n")
else:
print("No match!!") main()
再用python写一个文本处理的东东的更多相关文章
- 【Python】如何基于Python写一个TCP反向连接后门
首发安全客 如何基于Python写一个TCP反向连接后门 https://www.anquanke.com/post/id/92401 0x0 介绍 在Linux系统做未授权测试,我们须准备一个安全的 ...
- Python写一个自动点餐程序
Python写一个自动点餐程序 为什么要写这个 公司现在用meican作为点餐渠道,每天规定的时间是早7:00-9:40点餐,有时候我经常容易忘记,或者是在地铁/公交上没办法点餐,所以总是没饭吃,只有 ...
- 用Python写一个简单的Web框架
一.概述 二.从demo_app开始 三.WSGI中的application 四.区分URL 五.重构 1.正则匹配URL 2.DRY 3.抽象出框架 六.参考 一.概述 在Python中,WSGI( ...
- 十行代码--用python写一个USB病毒 (知乎 DeepWeaver)
昨天在上厕所的时候突发奇想,当你把usb插进去的时候,能不能自动执行usb上的程序.查了一下,发现只有windows上可以,具体的大家也可以搜索(搜索关键词usb autorun)到.但是,如果我想, ...
- [py]python写一个通讯录step by step V3.0
python写一个通讯录step by step V3.0 参考: http://blog.51cto.com/lovelace/1631831 更新功能: 数据库进行数据存入和读取操作 字典配合函数 ...
- python统计一个文本中重复行数的方法
python统计一个文本中重复行数的方法 这篇文章主要介绍了python统计一个文本中重复行数的方法,涉及针对Python中dict对象的使用及相关本文的操作,具有一定的借鉴价值,需要的朋友可以参考下 ...
- 用python写一个自动化盲注脚本
前言 当我们进行SQL注入攻击时,当发现无法进行union注入或者报错等注入,那么,就需要考虑盲注了,当我们进行盲注时,需要通过页面的反馈(布尔盲注)或者相应时间(时间盲注),来一个字符一个字符的进行 ...
- python写一个能变身电光耗子的贪吃蛇
python写一个不同的贪吃蛇 写这篇文章是因为最近课太多,没有精力去挖洞,记录一下学习中的收获,python那么好玩就写一个大一没有完成的贪吃蛇(主要还是跟课程有关o(╥﹏╥)o,课太多好烦) 第一 ...
- python写一个双色球彩票计算器
首先声明,赌博一定不是什么好事,也完全没有意义,不要指望用彩票发财.之所以写这个,其实是用来练手的,可以参考这个来预测一些其他的东西,意在抛砖引玉. 啰嗦完了,马上开始,先上伪代码 打开网址 读取内容 ...
随机推荐
- tty初探 — uart驱动框架分析
写在前面: 我们没有讲UART驱动,不过我们认为,只要系统学习了第2期,应该具备分析UART驱动的能力,小编做答疑几年以来,陆陆续续有不少人问到UART驱动怎么写,所以今天就分享一篇深度长文(1700 ...
- spark运行模式之二:Spark的Standalone模式安装部署
Spark运行模式 Spark 有很多种模式,最简单就是单机本地模式,还有单机伪分布式模式,复杂的则运行在集群中,目前能很好的运行在 Yarn和 Mesos 中,当然 Spark 还有自带的 Stan ...
- 最新sublimetext3080注册
----- BEGIN LICENSE -----K-20Single User LicenseEA7E-9401293A099EC1 C0B5C7C5 33EBF0CF BE82FE3BEAC216 ...
- python中panda的dateframe
1 函数介绍 #to_csv函数的语法#函数原型# to_csv(filepath,sep=",",index=TRUE,header=TRUE)#参数介绍: #(1)导出的文件路 ...
- Identity Server 4 原理和实战(完结)_Reference Token,撤销Tokens,Google和Github登录
服务端设置为ReferenceToken accessToken的内容比原来的少了很多 断点继续回来就会发生异常 服务端设置 客户端设置,使用一个封装好的库 撤销Token 我们在点击退出按钮的时候撤 ...
- 挨踢职场求生法则-----我在IT职场打滚超过15年了,从小小的程序员做到常务副总
摘要我在IT职场打滚超过15年了,从小小的程序员做到常务副总.相对于其它行业,IT职场应该算比较光明的了,但也陷阱重重,本文说说我的亲身体会,希望大家能在IT职场上战无不胜! 通用法则 法则1:忍耐是 ...
- IOS开发 UITabBarController
UITabBarController使用详解 UITabBarController是IOS中很常用的一个viewController,例如系统的闹钟程 序,ipod程序等.UITabBarContro ...
- IP服务-7-系统日志
默认情况下.Cisco路由器和交换机并不在NVRAM (非易失性内存)中记录事件:工程师可以使用命令logging buffered改变设备的这一默认行为.并且还可以使用额外参数来设定日志缓存的大小. ...
- python 基础(七) 异常处理
异常处理 一.需求 当遇到错误的时候 不让程序停止执行 而是越过错误继续执行 二.主体结构 (抓取所有异常) try: 可能出现异常的代码段 except: 出现异常以后的处理 三.处理特 ...
- 【bzoj1718】Redundant Paths 分离的路径
1718: [Usaco2006 Jan] Redundant Paths 分离的路径 Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 964 Solve ...