Python:一周笔记

主题

  • 邮件处理
  • 日志模块
  • pdf处理
  • md5
  • mongodb索引和聚合
  • excel 读写

1. 发送邮件模块

这里指的邮件功能当然不是指的是职场上所谓的邮件,指的是程序运行中希望将程序运行的日志信息或者错误捕获信息发送给指定的收件人,通过邮件可以了解程序运行的状态或者出错信息。

关于邮件的基本概念,这里引用廖雪峰老师python教程中的邮件模块:

假设我们自己的电子邮件地址是me@163.com,对方的电子邮件地址是friend@sina.com(注意地址都是虚构的哈),现在我们用Outlook或者Foxmail之类的软件写好邮件,填上对方的Email地址,点“发送”,电子邮件就发出去了。这些电子邮件软件被称为MUA:Mail User Agent——邮件用户代理。

Email从MUA发出去,不是直接到达对方电脑,而是发到MTA:Mail Transfer Agent——邮件传输代理,就是那些Email服务提供商,比如网易、新浪等等。由于我们自己的电子邮件是163.com,所以,Email首先被投递到网易提供的MTA,再由网易的MTA发到对方服务商,也就是新浪的MTA。这个过程中间可能还会经过别的MTA,但是我们不关心具体路线,我们只关心速度。

Email到达新浪的MTA后,由于对方使用的是@sina.com的邮箱,因此,新浪的MTA会把Email投递到邮件的最终目的地MDA:Mail Delivery Agent——邮件投递代理。Email到达MDA后,就静静地躺在新浪的某个服务器上,存放在某个文件或特殊的数据库里,我们将这个长期保存邮件的地方称之为电子邮箱。

同普通邮件类似,Email不会直接到达对方的电脑,因为对方电脑不一定开机,开机也不一定联网。对方要取到邮件,必须通过MUA从MDA上把邮件取到自己的电脑上。

所以,一封电子邮件的旅程就是:

发件人 -> MUA -> MTA -> MTA -> 若干个MTA -> MDA <- MUA <- 收件人

发送邮件使用到两个模块:smtplib, email
发送邮件分为两步:

  1. email 构造邮件
  2. smtplib 协议发送邮件

邮件发送主要涉及SMTP协议, 接收主要涉及POP 协议、IMAP协议。
在学习之前:我们先看看一封邮件基本包含哪些基础的东西:这里以QQ邮件为例:

1484399844411.png
  1. 收件人
  2. 发件人
  3. 邮件主题
  4. 邮件正文
  5. 邮件附件

所以使用邮件模块的步骤大概也就是完成这些基本的构造:
这里是使用QQ邮箱发送给163企业邮箱的一个实例:


import email
from email.mime.text import MIMEText
import smtplib
from email.header import Header

# 构造邮件信息
msg = MIMEText('这是一份python自动脚本邮件信息。', 'plain', 'utf-8') # 邮件正文

# QQ发给公司: 多了这步 server.starttls()
from_addr = "xie_wei_sh@foxmail.com" # 发件人
password = "****" # 发件人邮箱密码
smtp_server = "smtp.qq.com"  # SMTP 服务器地址
port = 587  # SMTP 服务器端口
to_addr = "paul.xie@chinascope.com"  # 收件人

msg["From"] = Header("Python爱好者<{}>".format(from_addr))  # 显示的邮件发件人
msg["To"] = Header("admin<{}>".format(to_addr))
msg["Subject"] = Header("来自SMTP的问候", "utf-8")  # 邮件主题

# 发送邮件 
server = smtplib.SMTP(smtp_server, port)
server.starttls()
server.set_debuglevel(1)
server.login(from_addr, password=password)
server.sendmail(from_addr, [to_addr], msg=msg.as_string())
server.quit()

上文看上去比较复杂。有人问有没有更清晰的方法。更清晰的接口。
有的。
模块:yagmail 第三方模块,需要自己安装

import yagmail

# 设置发送人信息及SMTP服务器和端口
yag = yagmail.SMTP(
    user="xie_wei_sh@foxmail.com",
    password="****",
    host="smtp.qq.com",
    port="587"
)

contents = u"系统发出警告,你已严重违规。"
yag.send(to=["paul.xie@chinascope.com","1156143589@qq.com"], subject="yagmail", contents=contents)

# 参数说明
to : 收件人,可以接受一个list 发送至多人

subject: 邮件主题

contents: 邮件正文,默认是文本信息,其实还可以接收各种常见的文件比如,*.jpg, *.docx, *.pdf ,*.html 等信息,只需要设置完整路径,或者同一目录下文件名称即可。

  • 总结
  1. 发送邮件的步骤: 构建邮件信息,SMTP协议发送邮件
  2. 更友好的第三方库yagmail
  3. 可能遇到的坑:SMTP协议服务器地址和端口不一致而产生的错误;再一个可能是邮箱设置中没有开启SMTP,POP等服务

2. 日志

借用python最佳实践中日志模块的介绍:
关于日志的作用:

诊断日志 记录与应用程序操作相关的日志。例如,用户遇到的报错信息,可通过搜索诊断日志获得上下文信息。
审计日志 为商业分析而记录的日志。从审计日志中,可提取用户的交易信息,并结合其他用户资料构成用户报告或者用来优化商业目标。

其实print也能做到这些,那么为什么还使用日志模块呢?

一句话:日志更友好的了解程序运行中的信息或者错误信息,方便了解程序运行状态以及报错信息。

那么如何使用日志模块呢。logging

需要了解信息:

  1. 日志的级别
  2. 关于日志的基本概念:记录器,处理器,过滤器,格式化器
  3. 编写常规的日志需要的步骤
  • 日志的级别:日志分等级,设置好等级,比设置好的级别大的才能在显示
    • DEBUG
    • INFO
    • WARN
    • ERROR
    • CRITICAL

默认日志名为root, 默认日志级别为WARN

在程序中配置日志存在三种方法:

  • 使用INI文件配置
  • 使用字典或者JSON配置
  • 在程序源代码中配置

这里以在程序源代码中为例进行配置:读者要是感兴趣可以了解其他配置方式:

import logging

logger = logging.getLogger("logger_name") # 记录器
handler = logging.StreamHandler()  # 日志显示在控制台,还可以设置将日志信息输出为文本形式FileHandler()
formatter = logging.Formatter(
        '%(asctime)s %(name)-12s %(levelname)-8s %(message)s')
        
handler.setFormatter(formatter) # 设置日志显示方式
logger.addHandler(handler) # 添加处理器
logger.setLevel(logging.DEBUG) # 设置日志级别

logger.debug('often makes a very good meal of %s', 'visiting tourists') # 日志在程序中的使用

  • 总结
    基本步骤:
  • 创建logger
    logger = logging.getLogger("Your_logger_name")
    logger.setLevel(logging.DEBUG)
  • 创建handler
    logger_one = logging.StreamHandler()
    logger_one.setLevel(logging.INFO)
  • 创建Formatter
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
  • 配置Logger
    logger_one.setFormatter(formatter)
    logger.addHandler(logger_one)
  • 使用logger
    logger.info('info message')

3. pdf

存在这样一个需求:想要抓取网页上的信心,但发现所需要的信息在pdf中

在google中发现了其实存在将pdf信息转换为字符串信息的这种模块:pdfminer


# 读取本地pdf转化为字符串
from cStringIO import StringIO

from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
from pdfminer.converter import TextConverter
from pdfminer.layout import LAParams
from pdfminer.pdfpage import PDFPage


def convert_pdf_2_text(path):

    rsrcmgr = PDFResourceManager()
    retstr = StringIO()

    device = TextConverter(rsrcmgr, retstr, codec='utf-8', laparams=LAParams())
    interpreter = PDFPageInterpreter(rsrcmgr, device)

    with open(path, 'rb') as fp:
        for page in PDFPage.get_pages(fp, set()):
            interpreter.process_page(page)
        text = retstr.getvalue()

    device.close()
    retstr.close()

    return text

# 将数据读入内存在进行处理
url_data = requests.get("http://www.sse.com.cn/disclosure/bond/announcement/bookentry/c/2768799626348021.pdf").content

data = StringIO(url_data)
parser = PDFParser(data)
document = PDFDocument(parser)
rercmgr = PDFResourceManager(document)
retstr = StringIO()
laparams = LAParams()
codec = 'utf-8'
device = TextConverter(rercmgr, retstr, codec=codec, laparams=laparams)
interpreter = PDFPageInterpreter(rercmgr, device)
for page in PDFPage.create_pages(document):
    interpreter.process_page(page)
text = retstr.getvalue()


# 返回的text 就能普通字符串的处理提取信息了。

4. md5

from hashlib

md = hashlib.md5()
md.update("字符串")
md5.hexdigest()

// 现在的问题是想要根据一个字典数据形成一个hash, 以使得可以判断字典数据没有完全一致的。

str = ("_".join("%s:%s" % (key, value) for key, value in dict_item.items() if key not in ("ct")) + "_" + str(number)).encode("utf-8")

md5.update(str)
md5.hexdigest()

5. 索引和聚合

遇到的问题是:能够很好的对数据进行判重处理。

之前的思路是:

  • 根据数据字段进行数据唯一索引设置,这样处理其实去掉了好多为0的值,因为抓取的好多数据都是0,为了需要数据的完备性,这些数据其实也需要

之后的思路是:

  • 根据入库的数据进行生成md5值,将md5值设置为唯一索引值,完成了较好的去重操作
  1. 索引
coll_values.create_index([("md5_values", pymongo.ASCENDING)], unique=True)
  1. 聚合操作:对mongodb数据中数据进行一些统计工作
  • match
  • group
  • limit
  • sort
query = [
    {
        "$match": {"key": code, "year": year, "type": type}
    },
    {
        "$group": {"_id": {"code": "$key", "year":"$year"}, "total": {"$sum":1}}
    }

]
total = []
for code in ["ACH", "IKGH", "ALN", "AMCN", "ATAI", "AXN", "ATV", "BIDU", "BITA", "BORN", "BSPM"]:
    for one in ["2011", '2012', '2013', '2014', "2015"]:
        A = Count(code=code, year=one, type="Annual", factor="Income Statement")
        result = A.aggregation()
        total.append(list(result))
pprint(total)

# 根据股票信息统计年份的数据数

6. excel 读写

需求是:想要将mongodb数据库中的数据导入入excel中

使用到的模块是:xlwt

关于excel的一些基本概念:

  1. Workbook : 工作簿
  2. sheet: 工作表
  3. cell: 单元格
1484444580203.png

一个workbook 可以包含多个sheet, 一个sheet中包含更多的行列组成的表格。

编写程序的大概步骤也是:

  1. 实例化workbook
  2. 添加sheet
  3. 往单元格里面写入内容
  4. 保存文件
import xlwt

wb = xlwt.Workbook()
ws = wb.add_sheet('A Test Sheet')

ws.write(0, 0, 1234.56)  # 第一行第一列写入123.56
ws.write(2, 0, 1)   # 第三行第一列写入 1
ws.write(2, 1, 1)   # 第三行第二列写入 1
ws.write(2, 2, xlwt.Formula("A3+B3"))  # 第三行第三列是前面值之和

wb.save('example.xls')  # 保存为文件名example.xls

所以:xlwt的基本使用就是往单元格中进行内容的写入。

// mongodb 实例

from pymongo import MongoClient
from xlwt import Workbook
from xlwt import easyxf  # 可以定义字体,颜色等样式


class MongoToXls(object):

    def __init__(self, collection, name):
        self.work_book = collection
        self.sheet_name = name
        self.wb = Workbook()
        self.ws = [self.wb.add_sheet(one) for one in self.sheet_name]
        self.style = easyxf("align: vert centre, horiz center")
        pass

    def info(self, number):
        self.contents = list(self.work_book[number].find())
        self.headers = [key for key in self.contents[0].keys()]
        rows = len(self.contents)
        columns = len(self.headers)
        return rows, columns

    def write_header(self, number):
        ws = self.ws[number]
        _, columns = self.info(number)
        for i in range(0, columns):
            ws.write(0, i, self.headers[i], style=self.style)

    def write_content(self, number):
        ws = self.ws[number]
        rows, columns = self.info(number)
        if rows >= 65536:
            rows = 65535
        for j in range(1, rows + 1):
            for k in range(0, columns):
                ws.write(j, k, str(self.contents[j - 1][self.headers[k]]), style=self.style)

    def save(self):
        name = "_".join(self.sheet_name) +"2"+ str(".xls")
        self.wb.save(str(name))

collection1 = MongoClient()["db5"]["base"]
collection2 = MongoClient()["db5"]["items"]
collection3 = MongoClient()["db5"]["values"]
collection = [collection1, collection2, collection3]
name = ["base", "items", "values"]

A = MongoToXls(collection=collection, name=name)
for number in range(len(collection)):
    print A.info(number)
    A.write_header(number)
    A.write_content(number)
A.save()

总结:

  1. 根据数据获取行和列数
  2. 先写入header信息
  3. 再两重循环写入内容值

参考

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容

  • 主要介绍几个用到的python模块的使用方法。python 含有丰富的内置和第三方库,企图全部掌握并精通那是不可能...
    谢小路阅读 1,062评论 3 20
  • 在应用程序中添加日志记录总的来说基于三个目的:监视代码中变量的变化情况,周期性的记录到文件中供其他应用进行统计分析...
    时待吾阅读 4,957评论 0 6
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,596评论 18 139
  • 那一年的南国,下了雪,很大很大的雪,飘飘洒洒,肆意飞扬。整个天地纯洁无比! 南蝶钟爱红衣,一身红衣如火,红与白,她...
    蝶雪微明阅读 677评论 6 14
  • 目标:不停追求(卓)、不断翱翔(菲) 晨读半个小时。 做饭。 中午看小说。 有点烦,我的眼镜又跑了。 下午练习乒乓...
    逆风追梦人阅读 89评论 0 0