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. 再两重循环写入内容值

参考

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏为数不多的Android技巧

让Alfred支持拼音搜索

Alfred是个好东西,不过检索程序的时候不支持拼音搜索;我在论坛看到有人给作者反馈过,无奈作者说支持中文,他不知道拼音是什么,于是就不了了之了。举个例子:我想...

3071
来自专栏FreeBuf

解密所有APP运行过程中的内部逻辑

0x01前言 这年头,apk全都是加密啊,加壳啊,反调试啊,小伙伴们表示已经不能愉快的玩耍了。静态分析越来越不靠谱了,apktool、ApkIDE、jd GUI...

28110
来自专栏北京马哥教育

Linux之HA高可用集群的基础概念总结

HA(High Availability)高可用集群,其特点为根据实际需求为前端Diretor,后端RS-server,数据库服务器,共享存储等集群节点做一个...

4286
来自专栏程序猿

设计一个Nginx集群,当其中一台机器故障时候迅速调整并自动恢复?多Master部署情况下应该怎样进行?

先说一下Nginx的特点 Nginx能作为HTTP服务器,有下面几个特性: 处理静态文件,索引文件以及自动索引。 打开文件描述缓冲符 无缓存的反向代理加速,简...

3265
来自专栏雨过天晴

转 树莓派无显示器安装系统

1662
来自专栏老安的博客

vmware api开发之快照管理

1924
来自专栏玄魂工作室

Hacker基础之工具篇 Amap

今天我们来说一个Kali中的工具,在Information Gathering下面

1301
来自专栏FreeBuf

安全科普:利用WireShark破解网站密码

当我们输入账号、密码登录一个网站时,如果网站允许你使用HTTP(明文)进行身份验证,那么此时捕获通信流量非常简单,我们完全可以对捕获到的流量进行分析以获取登录账...

2785
来自专栏信安之路

Mimikatz 攻防杂谈

前几天看到了老外一篇讲 mimikatz 防御的文章,感觉行文思路还不错,但是内容稍有不足,国内也有一篇翻译,但是只是照着错误翻译的,所以就萌生了把那篇优秀文章...

4392
来自专栏FreeBuf

Kali 2.0 安装与使用指南

关于kali使用前的一些配置,网上有很多版本,但是几乎都很雷同,或者是不全,或者是根本就没有测试过,或者是有的方法是错的(换句话说是版本变化的差异),因此让很多...

9885

扫码关注云+社区

领取腾讯云代金券