Python常用内置模块之datetime、collections、base64、hash、request

1.datetime时间格式转化

from datetime import datetime, timedelta

# datetime 当前时间
t1 = datetime.now()  # 当前时间 2019-08-14 16:05:41.923949
# timestamp 默认是秒
t2 = t1.timestamp() * 1000  # 时间毫秒值 1565769941923
# datetime 将年月日时分秒传入格式化为datatime
t3 = datetime(2019, 8, 14, 15, 42, 30)  # 年月日时分秒 指定时间 2019-08-14 15:42:30
# timestamp 
t4 = t3.timestamp() * 1000  # 时间毫秒值 1565768550000
# datetime 将时间戳(秒)重新格式化为datatime
t5 = datetime.fromtimestamp(t2 / 1000)  # 将时间戳重新格式化为时间格式 2019-08-14 16:05:41.923949
# str转换为datetime 将时间字符串转化为datatime
t6 = datetime.strptime('2015-6-1 18:19:59', '%Y-%m-%d %H:%M:%S')
# datetime转换为str 将datatime转化为时间字符串
t7 = t1.strftime('%a, %b %Y-%m-%d %H:%M:%S')
# datetime加减
# 对日期和时间进行加减实际上就是把datetime往后或往前计算,得到新的datetime。加减可以直接用+和-运算符
t8 = t1 - timedelta(hours=10)  # 往前倒退10个小时
t9 = t1 - timedelta(days=1)  # 往前倒退1天、
t10 = t1 - timedelta(days=1, hours=1)  # 往前倒退一天零1小时
print(t1)
print(int(t2))
print(t3)
print(int(t4))
print(t5)
print(t6)
print(t7)
print(t8, '  ', t9, '  ', t10)

打印结果:
2019-08-22 10:33:54.487574
1566441234487
2019-08-14 15:42:30
1565768550000
2019-08-22 10:33:54.487574
2015-06-01 18:19:59
Thu, Aug 2019-08-22 10:33:54
2019-08-22 00:33:54.487574   2019-08-21 10:33:54.487574   2019-08-21 09:33:54.487574

collections:系统内置的特殊集合类

from collections import namedtuple, deque, defaultdict, OrderedDict, ChainMap, Counter
import os, argparse

# namedtuple是一个函数,它用来创建一个自定义的tuple对象,
# 并且规定了tuple元素的个数,并可以用属性而不是索引来引用tuple的某个元素。
# 这样一来,我们用namedtuple可以很方便地定义一种数据类型,
# 它具备tuple的不变性,又可以根据属性来引用,使用十分方便。
# namedtuple('名称', [属性list]):
# 比如定义一个坐标
Point = namedtuple('Point', ['x', 'y'])
P = Point(1, 2)
print(P.x, P.y)
# 定义一个圆
Circle = namedtuple('Circle', ['x', 'y', 'r'])
c = Circle(10, 10, 5)
print(c.x, c.y, c.r)

打印结果:
1 2
10 10 5

# deque
# 使用list存储数据时,按索引访问元素很快,但是插入和删除元素就很慢了,
# 因为list是线性存储,数据量大的时候,插入和删除效率很低。
# deque是为了高效实现插入和删除操作的双向列表,适合用于队列和栈:
# deque除了实现list的append()和pop()外,还支持appendleft()和popleft(),这样就可以非常高效地往头部添加或删除元素。
q = deque(['a', 'b', 'c', 'd'])
print(q)
q.append('e')  # 成功
print(q)
q.appendleft(('q', 'w', 'e'))  # 成功
print(q)
q.appendleft(['r', 't', 'y'])  # 成功
print(q)
'''
q.append('x', 'y')  # 失败
q.append(('s', 'g'))  # 成功
q.append(*('s', 'g'))  # 失败
q.appendleft(*['r', 't', 'y'])  # 失败
q.appendleft('x', 'y')  # 失败
'''

打印结果:
deque(['a', 'b', 'c', 'd'])
deque(['a', 'b', 'c', 'd', 'e'])
deque([('q', 'w', 'e'), 'a', 'b', 'c', 'd', 'e'])
deque([['r', 't', 'y'], ('q', 'w', 'e'), 'a', 'b', 'c', 'd', 'e'])

# defaultdict
# 使用dict时,如果引用的Key不存在,就会抛出KeyError。如果希望key不存在时,返回一个默认值,就可以用defaultdict:
# defaultdict是无需的 如果对它进行迭代 可能每次都会回去不同的结果
dd = defaultdict(lambda: 'N/a')
dd['key1'] = 'default'
print(dd['key1'], '- - -分割线- - -', dd['key2'])

打印结果:
default - - -分割线- - - N/a

# OrderedDict
# 同上 但是它是有顺序的
test_dict = dict([('a', 1), ('b', 2), ('c', 3)])  # 它是无序的
print(test_dict)
for k, v in test_dict.items():
    print(k, v)

od = OrderedDict([('a', 1), ('b', 2), ('c', 3)])  # 它是有序的
print(od)
for k, v in od.items():
    print(k, v)

打印结果:
{'c': 3, 'a': 1, 'b': 2}
c 3
a 1
b 2
OrderedDict([('a', 1), ('b', 2), ('c', 3)])
a 1
b 2
c 3

# OrderedDict可以实现一个FIFO(先进先出)的dict,当容量超出限制时,先删除最早添加的Key:
class LastUpdatedOrderedDict(OrderedDict):
    def __init__(self, capacity):
        super(LastUpdatedOrderedDict, self).__init__()
        self._capacity = capacity

    def __setitem__(self, key, value):
        containsKey = 1 if key in self else 0
        if len(self) - containsKey >= self._capacity:
            last = self.popitem(last=False)
            print('remove:', last)
        if containsKey:
            del self[key]
            print('set:', (key, value))
        else:
            print('add:', (key, value))
        OrderedDict.__setitem__(self, key, value)


# ChainMap
# ChainMap可以把一组dict串起来并组成一个逻辑上的dict。ChainMap本身也是一个dict,
# 但是查找的时候,会按照顺序在内部的dict依次查找。
# 什么时候使用ChainMap最合适?举个例子:应用程序往往都需要传入参数,参数可以通过命令行传入,
# 可以通过环境变量传入,还可以有默认参数。我们可以用ChainMap实现参数的优先级查找,即先查命令行参数,
# 如果没有传入,再查环境变量,如果没有,就使用默认参数。
# 构造缺省参数:
defaults = {
    'color': 'red',
    'user': 'guest'
}

# 构造命令行参数:
parser = argparse.ArgumentParser()
parser.add_argument('-u', '--user')
parser.add_argument('-c', '--color')
namespace = parser.parse_args()
command_line_args = {k: v for k, v in vars(namespace).items() if v}

# 组合成ChainMap:
combined = ChainMap(command_line_args, os.environ, defaults)

# 打印参数:
print('color=%s' % combined['color'])
print('user=%s' % combined['user'])

# Counter 计数器 Counter实际上也是dict的一个子类
c = Counter()
for ch in 'programming':  # 统计字符在字符串中出现的次数
    c[ch] += 1
print(c)

打印结果:
Counter({'m': 2, 'g': 2, 'r': 2, 'o': 1, 'i': 1, 'p': 1, 'a': 1, 'n': 1})

接下来是加解密相关的 比如base64,md5,sha1,以及Hmac等
先说base64,base64虽说可以用于加解密,但是其实他最大的作用还是来自于存储二进制数据,比如像图片这样的数据,在数据库不好保存,如果能将图片弄成字符串保存起来,那就方便多了,base64就方便多了,虽然我认为这多此一举

# 加密的时候可以传入 字符串 二进制数据比如字节
a1 = base64.urlsafe_b64encode(b'i\xb7\x1d\xfb\xef\xff')  # 加密
a2 = base64.urlsafe_b64decode(a1)  # 解密
print(a1)
print(a2)
b1 = base64.urlsafe_b64encode('choushabi'.encode('utf-8'))
b2 = base64.urlsafe_b64decode(b1).decode('utf-8')
print(b1)
print(b2)

打印结果:
b'abcd--__'
b'i\xb7\x1d\xfb\xef\xff'
b'Y2hvdXNoYWJp'
choushabi

接着说MD5,md5保存的数据通常不需要去解密,因为MD5是对任意长度的数据data计算出固定长度的摘要digest,
目的是为了发现原始数据是否被人篡改过,并不是为了还原数据本身

md5 = hashlib.md5()
# 如果数据量很大,可以分块多次调用update(),最后计算的结果是一样的:
md5.update('how to use md5 in python hashlib?'.encode('utf-8'))
md5.update('how to use md5 in '.encode('utf-8'))
md5.update('python hashlib?'.encode('utf-8'))
print(md5.hexdigest())

打印结果:
8d7f266bcebe4d9b68611c1eb4b02ef8

sha1算法:

sha1 = hashlib.sha1()
# 如果数据量很大,可以分块多次调用update(),最后计算的结果是一样的:
sha1.update('how to use md5 in python hashlib?'.encode('utf-8'))
sha1.update('how to use md5 in '.encode('utf-8'))
sha1.update('python hashlib?'.encode('utf-8'))
print(sha1.hexdigest())

打印结果:
3cf633a8ce84eaa50424878cb86e86559439d44a

#Hmac算法:Keyed-Hashing for Message Authentication。
它通过一个标准算法,在计算哈希的过程中,把key混入计算过程中。
#和我们自定义的加salt算法不同,Hmac算法针对所有哈希算法都通用,无论是MD5还是SHA-1。
#采用Hmac替代我们自己的salt算法,可以使程序算法更标准化,也更安全。
#Python自带的hmac模块实现了标准的Hmac算法。我们来看看如何使用hmac实现带key的哈希。
#传入的key和message都是bytes类型,str类型需要首先编码为bytes

h = hmac.new(b'666', 'python hashlib?'.encode('utf-8'), digestmod='MD5')
h.update('python hashlib?'.encode('utf-8'))
print(h.hexdigest())

打印结果:
288892e386d820cf8768001d170e3f31

itertools
#itertools提供了非常有用的用于操作迭代对象的函数。

import itertools

# count()会创建一个无限的迭代器,所以上述代码会打印出自然数序列
natuals = itertools.count(1)
for n in natuals:
    if n < 5:
        print(n)
    else:
        break

print('- - - - -分割线- - - - -')

# cycle()会把传入的一个序列无限重复下去:停不下来
cs = itertools.cycle('ABC')
sum_s = 0
for c in cs:
    if sum_s < 5:
        print(c, '- - -', sum_s)
        sum_s += 1
    else:
        break

print('- - - - -分割线- - - - -')

nc = itertools.repeat('A', 5)
for n in nc:
    print('repeat', n)
# 无限序列只有在for迭代时才会无限地迭代下去,如果只是创建了一个迭代对象,
# 它不会事先把无限个元素生成出来,事实上也不可能在内存中创建无限多个元素。
# 无限序列虽然可以无限迭代下去,但是通常我们会通过takewhile()等函数根据条件判断来截取出一个有限的序列:
natuals2 = itertools.count(1)
ns = itertools.takewhile(lambda x: x < 10, natuals2)
for n in ns:
    print(n)

print('- - - - -分割线- - - - -')

# chain()可以把一组迭代对象串联起来,形成一个更大的迭代器:
for xx in itertools.chain('ABC', 'XYZ'):
    print(xx)

print('- - - - -分割线- - - - -')

# groupby()把迭代器中相邻的重复元素挑出来放在一起:
for key, group in itertools.groupby('AAABBBCCAAA'):
    print(key, list(group))

print('- - - - -分割线- - - - -')

# 实际上挑选规则是通过函数完成的,只要作用于函数的两个元素返回的值相等,
# 这两个元素就被认为是在一组的,而函数返回值作为组的key。如果我们要忽略大小写分组
for key, group in itertools.groupby('AaaBBbcCAAa', lambda x: x.upper()):
    print(key, list(group))

打印结果:
1
2
3
4
- - - - -分割线- - - - -
A - - - 0
B - - - 1
C - - - 2
A - - - 3
B - - - 4
- - - - -分割线- - - - -
repeat A
repeat A
repeat A
repeat A
repeat A
1
2
3
4
5
6
7
8
9
- - - - -分割线- - - - -
A
B
C
X
Y
Z
- - - - -分割线- - - - -
A ['A', 'A', 'A']
B ['B', 'B', 'B']
C ['C', 'C']
A ['A', 'A', 'A']
- - - - -分割线- - - - -
A ['A', 'a', 'a']
B ['B', 'B', 'b']
C ['c', 'C']
A ['A', 'A', 'a']

request网络请求
#urllib的request模块可以非常方便地抓取URL内容,

# 也就是发送一个GET请求到指定的页面,然后返回HTTP的响应:
# 这是一个GET请求
with request.urlopen('https://www.easy-mock.com/mock/5cbec5d8bfb3b05625e96633/dreamlf/urllibTest') as f:
    data = f.read()
    print('请求状态Status:', f.status, f.reason)
    for k, v in f.getheaders():
        print('请求头%s:%s' % (k, v))
    print('返回的数据data:', data.decode('utf-8'))
    print('返回的数据封装成对象:', json.loads(data.decode('utf-8')))

如若要模拟浏览器发起请求的话,要在请求中添加一个header

# 模拟浏览器发起get请求
req = request.Request('http://www.douban.com/')
req.add_header('User-Agent',
               'Mozilla/6.0 (iPhone; CPU iPhone OS 8_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/8.0 Mobile/10A5376e Safari/8536.25')
with request.urlopen(req) as f2:
    data = f2.read()
    print('请求状态Status:', f2.status, f2.reason)
    for k, v in f2.getheaders():
        print('请求头%s:%s' % (k, v))
    print('返回的数据data:', data.decode('utf-8'))

如果要以POST发送一个请求,只需要把参数data以bytes形式传入。

# 模拟post请求
email = input('Email:')
passwd = input('passwd:')
# post请求参数
login_data = parse.urlencode([('username', email),
                              ('password', passwd),
                              ('entry', 'mweibo'),
                              ('client_id', ''),
                              ('savestate', '1'),
                              ('ec', ''),
                              ('pagerefer',
                               'https://passport.weibo.cn/signin/welcome?entry=mweibo&r=http%3A%2F%2Fm.weibo.cn%2F')])
req2 = request.Request('https://passport.weibo.cn/sso/login')
req2.add_header('Origin', 'https://passport.weibo.cn')
req2.add_header('User-Agent',
                'Mozilla/6.0 (iPhone; CPU iPhone OS 8_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/8.0 Mobile/10A5376e Safari/8536.25')
req2.add_header('Referer',
                'https://passport.weibo.cn/signin/login?entry=mweibo&res=wel&wm=3349&r=http%3A%2F%2Fm.weibo.cn%2F')
with request.urlopen(req2, login_data.encode('utf-8')) as f3:
    print('Status:', f.status, f.reason)
    for k, v in f.getheaders():
        print('%s: %s' % (k, v))
    print('Data:', f.read().decode('utf-8'))

#通过代理访问某网站
#如果还需要更复杂的控制,比如通过一个Proxy去访问网站,我们需要利用ProxyHandler来处理

# 传入一个dict
proxy_handler = request.ProxyHandler({'http': 'http://www.example.com:3128/'})
proxy_auth_handler = request.ProxyBasicAuthHandler()
proxy_auth_handler.add_password('realm', 'host', 'username', 'password')
oper = request.build_opener(proxy_handler, proxy_auth_handler)
with oper.open('') as f4:
    pass

request作为python内置的模块访问网络模块有很多缺点:
因为它用起来比较麻烦,而且,缺少很多实用的高级功能。
更好的方案是使用requests。它是一个Python第三方库,处理URL资源特别方便

你可能感兴趣的:(Python)