python经常使用模块

 

  python模块能够分为内建模块和第三方模块。css

 

内建模块

datetime

  引入方式以下:html

 from datetime import datetime

 

  如上所示,咱们就能够引入datetime模块。获取当前时间java

>>> t = datetime.now()
>>> print(t)
2018-03-28 16:19:14.755376

  这里获取的是本地时间。python

  

  因为datetime是一个类,咱们能够进行构造,传入相应参数便可:linux

>>> t = datetime(2018, 3, 28, 16, 20, 30)
>>> print(t)
2018-03-28 16:20:30
>>> t = datetime(2018, 3, 28, 16, 20)
>>> print(t)
2018-03-28 16:20:00
>>> t = datetime(2018, 3, 28, 16)
>>> print(t)
2018-03-28 16:00:00

  如上所示,咱们能够看到,传入6个参数能够构造出确切的时间,而若是只有5个参数,则s默认为0,;只有4个参数,m也默认为0。但最少要有3个参数表示年月日。nginx

 

  转化为时间戳(timestamp)。 咱们以前获取的都是北京事件,比UTC时间(格林威治时间)早了8个小时。可是时间戳在世界的任何一个角落都是相同的,因此时间戳比较经常使用。而转化也很是简单,调用timestamp()方法便可:web

>>> t = datetime.now()
>>> print(t)
2018-03-28 16:25:05.835699
>>> t.timestamp()
1522225505.835699

  如上,timestamp是浮点数,转化的时间戳是浮点数。 算法

  

    从时间戳转化为当地时间。既然能够从当地时间转化为时间戳,那咱们天然也能够从时间戳转化为当地时间:spring

>>> t.timestamp()
1522225505.835699
>>> stamp = t.timestamp()
>>> stamp
1522225505.835699
>>> t = datetime.fromtimestamp(stamp)
>>> t
datetime.datetime(2018, 3, 28, 16, 25, 5, 835699)
>>> print(t)
2018-03-28 16:25:05.835699

  如上所示,咱们就很轻松地从时间戳转换为了本地时间 ,固然,也能够从时间戳转换为UTC时间,以下:
数据库

>>> t = datetime.utcfromtimestamp(stamp)
>>> print(t)
2018-03-28 08:25:05.835699

  

  另外,在字符换和当地时间之间也能够相互转换,这里再也不介绍。  

  

  且时间也能够进行加减的,引入timedelta模块就能够了,以下所示:

>>> from datetime import datetime, timedelta
>>> now = datetime.now()
>>> print(now)
2018-03-28 16:32:14.057271
>>> print(now + timedelta(hours = 10))
2018-03-29 02:32:14.057271
>>> print(now + timedelta(days = 10))
2018-04-07 16:32:14.057271
>>> print(now + timedelta(days = -2))
2018-03-26 16:32:14.057271
>>> print(now + timedelta(days = 1, hours = 5))
2018-03-29 21:32:14.057271

  如上所示,咱们能够看出,引入timedelta模块以后,咱们就能够进行时间的加减了。 参数能够是日、时、分、秒等。

    

  

Collections

  这是python的一个内建模块,提供了不少有用的集合类。

  好比namedtupple。这个类的字面意思就很好理解,即命名的tupple。 好比咱们但愿定义个点,使用p = (1, 2)可是并无实际的意义,这时咱们就能够用namedtupple,以下:

>>> from collections import namedtuple
>>> Point = namedtuple('Point', ['x', 'y'])
>>> p = Point(1, 2)
>>> p.x
1
>>> p.y
2

  如上所示,namedtuple是一个函数,用来建立一个自定义的tuple对象,而且规定了tuple元素的个数,根据属性而不是属性来引用tuple的元素。

  

 

 deque

  使用list存储数组时,咱们使用list.append()和list.pop()都是从list的末尾进行插入和删除,其余位置的删除都是效率比较低的,而deque的appendleft()方法和popleft()方法能够实现从List的头部插入和删除,效率更高一些。 

>>> from collections import deque
>>> d = deque([5, 63, 85])
>>> d.appendleft(8)
>>> d
deque([8, 5, 63, 85])
>>> d.popleft()
8
>>> d
deque([5, 63, 85])

  如上所示,可见穿件一个deque数据结构,只须要在调用deque()函数,参数为一个list。

  

 

defaultDict

   咱们知道对于一个dict,若是说不存在某一个kv,那么在访问时就会出现KeyError,以下:

>>> k['wayn']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'wayn'

  可是若是咱们引入了 defaultdict,那么咱们就能够指定不存在的状况下怎么返回了,以下:

>>> from collections import defaultdict
>>> d = defaultdict(lambda: '不存在这个key')
>>> d['wayne'] = 22
>>> d['wayne']
22
>>> d['hedy']
'不存在这个key'

   这样的提示会更加有好一些。

 

OrderdDict  

  使用dict时,key是无序的,没法肯定key的顺序,而OrderdDict会根据你插入的顺序肯定key的顺序,因此OrderdDict是有序的。这里就不举例了。

 

 

Counter

  counter是一个计数器,它是一个dict,咱们能够统计一个字符串中字符出现的次数:

from collections import Counter
c = Counter()
for i in 'computerscience':
  c[i] = c[i] + 1

print(c)
# Counter({'c': 3, 'e': 3, 'o': 1, 'm': 1, 'p': 1, 'u': 1, 't': 1, 'r': 1, 's': 1, 'i': 1, 'n': 1})

  如上所示,显然c[i]的默认值为0,这样,就能够统计每个字符出现的个数了,最后的结果是一个dict。 

  另外,Couter的使用更加方便的是直接使用构造函数,传入一个字符串便可,以下

>>> from collections import Counter
>>> c = Counter('computerscience')
>>> c
Counter({'c': 3, 'e': 3, 'o': 1, 'm': 1, 'p': 1, 'u': 1, 't': 1, 'r': 1, 's': 1, 'i': 1, 'n': 1})

  这样会更加简便一些。

  

  

 

base64

  在个人这篇文章中介绍了base64的相关知识。简单的说base64就是将二进制文件或者其余文件使用64中字符来表示,可是base64编码以后的字符数是原来的1.3倍左右。 且使用base64编码能够做为cookie等保护性的字符,而后须要使用时再解码就能够了。

  python中的base64模块就能够自动完成这个任务而不须要本身查表来完成了,以下所示:

>>> base64.b64encode(b'hedy')
b'aGVkeQ=='
>>> base64.b64decode('aGVkeQ==')
b'hedy'

  如上所示,就完成了base64编码和解码的过程。

  若是使用base64编码以后做为url的一部分也是能够的,可是base64编码获得的时a-zA-Z0-9/-=,其中的/和=可能会影响正常的url,因此咱们可使用特殊的编码方式即urlsafe_b64encode,这种方式能够将/和=转化为其余的字符_等:

>>> base64.urlsafe_b64encode(b'abcd.dfzfasd89\xff')
b'YWJjZC5kZnpmYXNkODn_'
>>> base64.urlsafe_b64decode('YWJjZC5kZnpmYXNkODn_')
b'abcd.dfzfasd89\xff'

  如上所示,经过这种方式,咱们就能够很好的利用base64编码解决问题了。

 

 

struct

   python中的struct模块提供了bytes和二进制数据之间的转换。 好比struct的pack函数把任意数据类型变成bytes:

>>> import struct
>>> struct.pack('>I', 10240099)
b'\x00\x9c@c'

 

  

 

hashlib

  在python的hashlib中提供了SHA1和MD5摘要算法。 而摘要算法的做用是经过一个函数将任意长度的数据转换为长度固定的数据串。

举个例子,你写了一篇文章,内容是一个字符串'how to use python hashlib - by Michael',并附上这篇文章的摘要是'2d73d4f15c0db7f5ecb321b6a65e5d6d'。若是有人篡改了你的文章,并发表为'how to use python hashlib - by Bob',你能够一会儿指出Bob篡改了你的文章,由于根据'how to use python hashlib - by Bob'计算出的摘要不一样于原始文章的摘要。

  所以摘要算法的做用是经过使用摘要算法函数f()对任意长度的数据data生成固定长度的摘要digest,来判断原来的数据是否被修改。而且这个摘要算法是单向的,便可以经过数据生成digest,可是很难经过digest推到原来的数据,因此对原始数据一个bit的修改,就会致使digest的巨大变化。

  以下是MD5摘要算法的使用:

>>> import hashlib
>>> md5 = hashlib.md5()
>>> md5.update('wayne zhu is handsome'.encode('utf-8'))
>>> md5.hexdigest()
'a05db2b83183e5ae872644492db99636'
>>> md5_1 = hashlib.md5()
>>> md5_1.update('wayne zhu is handsome'.encode('utf-8'))
>>> md5_1.hexdigest()
'a05db2b83183e5ae872644492db99636'
>>> md5_2 = hashlib.md5()
>>> md5_2.update('hedy zhu is handsome'.encode('utf-8'))
>>> md5_2.hexdigest()
'6549b4c53f96b973199e829b9dd0d8e9'
>>> md5_3 = hashlib.md5()
>>> md5_3.update('wayne zhu is'.encode('utf-8'))
>>> md5_3.update(' handsome'.encode('utf-8'))
>>> md5_3.hexdigest()
'a05db2b83183e5ae872644492db99636'

  如上所示,每次对于一个数据使用md5算法,咱们就使用hashlib.md5()进行建立;接着使用update()函数来添加要进行md5算法的字符串; 最后咱们使用hexdigest()就能够生成32bit的16进制表示的摘要算法。

       而且咱们能够发现,将字符串中的几个字符修改以后生成的md5算法发生了很大的改变。另外,hexdigest函数是强制生成16进制的摘要算法,若是是digest呢?以下:

>>> import hashlib
>>> md5_4 = hashlib.md5()
>>> md5_4.update('wayne zhu is handsome'.encode('utf-8'))
>>> md5_4.digest()
b'\xa0]\xb2\xb81\x83\xe5\xae\x87&DI-\xb9\x966'

  通过比较发现,即便这里咱们使用的时digest,可是生成的仍是16进制的,而且这里使用\x来表示16进制,由于这里是字符串; 若是是数字,通常用0x做为前缀,表示这是16进制的数。

 

    接下来要说的SHA1和md5的用法是彻底同样的,只是内部的实现算法有区别,以下所示:

>>> import hashlib
>>> sha1 = hashlib.sha1()
>>> sha1.update('wayne zhu is handsome'.encode('utf-8'))
>>> sha1.hexdigest()
'2691709dbb47703edeb943da91a013ee6e5814d0'

  如上所示,咱们能够看到,sha1的用法的确如出一辙,可是sha1算法生成的是160bit的二进制位,这里用了40个16进制位来表示。但sha1的摘要更长,理论上会更加安全一点。而sha256和sha512计算的摘要更长,因此也更安全,可是生成的时间也更慢了,效率也就更低了。以下:

>>> import hashlib
>>> sha256 = hashlib.sha256()
>>> sha256.update('wayne zhu is handsome'.encode('utf-8'))
>>> sha256.hexdigest()
'a14319c1476ccca97be9bdfc6f485ece52e2fa40dc5fa61afc05c2ccd9c33352'

  如上是sha256的算法摘要。

>>> import hashlib
>>> sha512 = hashlib.sha512()
>>> sha512.update('wayne zhu is handsome'.encode('utf-8'))
>>> sha512.hexdigest()
'bf3ac43d83af78dd13d5ffaebdc4e2fdd9f080673f8f6bc9bc904fd28182048716469951fc9b88a65d20e8f81c1f62c2fd7c6fce8bcedd45430ffd24603be5a7'

  以下是sha512的算法摘要,更为复杂了。

  注意:有没有可能对于不一样的数据使用算法获得的摘要相同呢?这是有可能的,由于他们都是将无限的数据映射到有限的摘要中,因此必定是有这种状况出现的,这就是碰撞可是这是很是困难的

  

摘要算法应用

  任何容许用户登陆的网站都会储存用户名和密码,那么如何存储用户名和密码呢,方法固然是存储到数据库表中,以下所示:

name password
michael 123456
bob abc999
alice alice2008

  

   可是,这有一个问题是,这个用户名和密码是存储在数据库中的,若是数据库被黑客攻击,那么黑客就能够获取到全部用户的用户名和密码而直接登陆;或者管理员能够获取到后台的这些数据。不管是谁,他们一旦获取就会形成极大的损失,因此,咱们通常是将用户登陆的密码先使用摘要算法生成摘要,而后存储到数据库中; 当用户进行登陆的时候,会再一次的生成摘要,而后和数据库中存储到的摘要进行比对,就能够判断密码生成是否正确了,以下所示:

username password
michael e10adc3949ba59abbe56e057f20f883e
bob 878ef96e86145580c38c87f0410ad153
alice 99b1c2188db85afee403b1536010c2c9

 

  那么,使用了摘要算法以后就能保证安全了,这是不必定的,好比黑客获取到了全部的用户名和密码以后,能够对于一些常见的密码推理获得摘要,如111111/222222/8888888等,而后再去匹配,因此,通常网站但愿用户将本身的密码设置的尽可能复杂一些。不过,为了不这种问题,开发人员仍是能够作一些工做的,好比对于密码加salt,而后再获取摘要,只要黑客不知道咱们所加的salt是什么,就很难经过上述方法得到密码。 

 

 

itertools

  itertools模块提供了不少操做迭代对象的函数。  

  

(1)itertools.count()

  这个函数能够从某个指定的数开始迭代,以下:

>>> import itertools
>>> t = itertools.count(1)
>>> for i in t:
...     print(i)
...
1
2
3
4
5
6
7
8

  这个函数运行到咱们按下Ctrl + C才会中止。若是count中接受的是5,那么这个迭代器就是从5开始的了。

 

  

(2)itertools.cycle()

  这个函数会让传入的参数这个序列无限的循环下去

>>> import itertools
>>> t = itertools.cycle('628')
>>> for i in t:
...     print(i)
...
6
2
8
6
2
8
6
2
8
6
2
8
6
2

  如上所示。

 

(3)itertools.repeat()

  会一直重复下去:

>>> import itertools
>>> r = itertools.repeat('abc')
>>> for i in r:
...     print(i)
...
abc
abc
abc
abc
abc
abc
abc
abc
abc

 

(4)itertools.takewhile()

 以前都是无限重复下去的,可是咱们不可能用这么多数据,因此须要在适当的时候截取出来,就要用到itertools.takewhile()函数了,他接受两个参数,第一个参数是一个lambda函数,第二个参数是以前的这些无限itertools:

>>> import itertools>>> r = itertools.count(1)
>>> l = itertools.takewhile(lambda x: x < 20, r)
>>> l
<itertools.takewhile object at 0x000002A73D0AE6C8>
>>> for i in l:
...     print(i)
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

  如上所示,经过这个函数,咱们就能够运用到实际中了。

 

(5)itertools.chain()

这个函数能够帮助咱们将多个可迭代对象串联起来,获得一个更大的可迭代对象:

>>> import itertools
>>> r = itertools.chain('abcd','1234')
>>> for i in r:
...     print(i)
...
a
b
c
d
1
2
3
4

 

 

(6)itertools.groupby()

  这个函数会将重复的部分自动分组,以下:

>>> import itertools
>>> for key,group in itertools.groupby('aaaabbbcccddddd'):
...     print(key, list(group))
...
a ['a', 'a', 'a', 'a']
b ['b', 'b', 'b']
c ['c', 'c', 'c']
d ['d', 'd', 'd', 'd', 'd']

 

经过上面知识点的学习,咱们能够求圆周率了:

def pi(N):
    ' 计算pi的值 '
    # step 1: 建立一个奇数序列: 1, 3, 5, 7, 9, ...

    # step 2: 取该序列的前N项: 1, 3, 5, 7, 9, ..., 2*N-1.

    # step 3: 添加正负符号并用4除: 4/1, -4/3, 4/5, -4/7, 4/9, ...

    # step 4: 求和:
    return 3.14

 

以下:

import itertools
N = 100000000
r = itertools.count(1)
l = itertools.takewhile(lambda x: x < N, r)
sum = 0
for i in l:
  if i % 2 == 1:
    sum = sum + 4/(2 * i - 1)
  else:
    sum = sum - 4/(2 * i - 1)
print(sum)

这样,在N比较大的时候,咱们能够获得一个很是精确的值:

3.141592663589326

 

 

 

urllib

  urllib提供了一系列操做url的功能。

get

  urllib模块中的request模块能够很是方便的抓取URL内容,也就是发送一个GET请求到指定的页面,而后返回HTTP的响应 。例如对于豆瓣的一个URL进行抓取:https://api.douban.com/v2/book/2129650,并返回响应:

from urllib import request

with request.urlopen('https://api.douban.com/v2/book/2129650') 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'))

  这里引入了urllib中的request,而后使用request的urlopen函数发送了get请求,这里使用with就能够省去try...finally的书写使得其更为简洁,而后获得的内容就都在f中了。

  经过f.read()能够获得get的内容,而后使用f.getheaders()获得响应头的kv对,经过for...in迭代出来便可 。最后打印时,咱们使用utf-8的编码方式进行decode便可。最终结果以下:

Status:  200 OK
Date: Wed, 28 Mar 2018 14:12:43 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 2058
Connection: close
Vary: Accept-Encoding
X-Ratelimit-Remaining2: 99
X-Ratelimit-Limit2: 100
Expires: Sun, 1 Jan 2006 01:00:00 GMT
Pragma: no-cache
Cache-Control: must-revalidate, no-cache, private
Set-Cookie: bid=5kcAzYhjXJ0; Expires=Thu, 28-Mar-19 14:12:43 GMT; Domain=.douban.com; Path=/
X-DOUBAN-NEWBID: 5kcAzYhjXJ0
X-DAE-Node: sindar7c
X-DAE-App: book
Server: dae
Data: {"rating":{"max":10,"numRaters":16,"average":"7.4","min":0},"subtitle":"","author":["廖雪峰"],"pubdate":"2007","tags":[{"count":21,"name":"spring","title":"spring"},{"count":13,"name":"Java","title":"Java"},{"count":6,"name":"javaee","title":"javaee"},{"count":5,"name":"j2ee","title":"j2ee"},{"count":4,"name":"计算机","title":"计算机"},{"count":4,"name":"编程","title":"编程"},{"count":3,"name":"藏书","title":"藏书"},{"count":3,"name":"POJO","title":"POJO"}],"origin_title":"","image":"https://img3.doubanio.com\/mpic\/s2552283.jpg","binding":"平装","translator":[],"catalog":"","pages":"509","images":{"small":"https://img3.doubanio.com\/spic\/s2552283.jpg","large":"https://img3.doubanio.com\/lpic\/s2552283.jpg","medium":"https://img3.doubanio.com\/mpic\/s2552283.jpg"},"alt":"https:\/\/book.douban.com\/subject\/2129650\/","id":"2129650","publisher":"电子工业出版社","isbn10":"7121042622","isbn13":"9787121042621","title":"Spring 2.0核心技术与最佳实践","url":"https:\/\/api.douban.com\/v2\/book\/2129650","alt_title":"","author_intro":"","summary":"本书注重实践而又深刻理论,由浅入深且详细介绍了Spring 2.0框架的几乎所有的内容,并重点突出2.0版本的新特性。本书将为读者展现如何应用Spring 2.0框架建立灵活高效的JavaEE应用,并提供了一个真正可直接部署的完整的Web应用程序——Live在线书店(http:\/\/www.livebookstore.net)。\n在介绍Spring框架的同时,本书还介绍了与Spring相关的大量第三方框架,涉及领域全面,实用性强。本书另外一大特点是实用性强,易于上手,以实际项目为出发点,介绍项目开发中应遵循的最佳开发模式。\n本书还介绍了大量实践性极强的例子,并给出了完整的配置步骤,几乎覆盖了Spring 2.0版本的新特性。\n本书适合有必定Java基础的读者,对JavaEE开发人员特别有帮助。本书既能够做为Spring 2.0的学习指南,也能够做为实际项目开发的参考手册。","price":"59.8"}

C:\Users\Administrator\Desktop>python foo.py
Status:  200 OK
Date: Wed, 28 Mar 2018 14:14:17 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 2058
Connection: close
Vary: Accept-Encoding
X-Ratelimit-Remaining2: 98
X-Ratelimit-Limit2: 100
Expires: Sun, 1 Jan 2006 01:00:00 GMT
Pragma: no-cache
Cache-Control: must-revalidate, no-cache, private
Set-Cookie: bid=27IsN2hIcec; Expires=Thu, 28-Mar-19 14:14:17 GMT; Domain=.douban.com; Path=/
X-DOUBAN-NEWBID: 27IsN2hIcec
X-DAE-Node: dis5
X-DAE-App: book
Server: dae
Data: {"rating":{"max":10,"numRaters":16,"average":"7.4","min":0},"subtitle":"","author":["廖雪峰"],"pubdate":"2007","tags":[{"count":21,"name":"spring","title":"spring"},{"count":13,"name":"Java","title":"Java"},{"count":6,"name":"javaee","title":"javaee"},{"count":5,"name":"j2ee","title":"j2ee"},{"count":4,"name":"计算机","title":"计算机"},{"count":4,"name":"编程","title":"编程"},{"count":3,"name":"藏书","title":"藏书"},{"count":3,"name":"POJO","title":"POJO"}],"origin_title":"","image":"https://img3.doubanio.com\/mpic\/s2552283.jpg","binding":"平装","translator":[],"catalog":"","pages":"509","images":{"small":"https://img3.doubanio.com\/spic\/s2552283.jpg","large":"https://img3.doubanio.com\/lpic\/s2552283.jpg","medium":"https://img3.doubanio.com\/mpic\/s2552283.jpg"},"alt":"https:\/\/book.douban.com\/subject\/2129650\/","id":"2129650","publisher":"电子工业出版社","isbn10":"7121042622","isbn13":"9787121042621","title":"Spring 2.0核心技术与最佳实践","url":"https:\/\/api.douban.com\/v2\/book\/2129650","alt_title":"","author_intro":"","summary":"本书注重实践而又深刻理论,由浅入深且详细介绍了Spring 2.0框架的几乎所有的内容,并重点突出2.0版本的新特性。本书将为读者展现如何应用Spring 2.0框架建立灵活高效的JavaEE应用,并提供了一个真正可直接部署的完整的Web应用程序——Live在线书店(http:\/\/www.livebookstore.net)。\n在介绍Spring框架的同时,本书还介绍了与Spring相关的大量第三方框架,涉及领域全面,实用性强。本书另外一大特点是实用性强,易于上手,以实际项目为出发点,介绍项目开发中应遵循的最佳开发模式。\n本书还介绍了大量实践性极强的例子,并给出了完整的配置步骤,几乎覆盖了Spring 2.0版本的新特性。\n本书适合有必定Java基础的读者,对JavaEE开发人员特别有帮助。本书既能够做为Spring 2.0的学习指南,也能够做为实际项目开发的参考手册。","price":"59.8"}

 

 

上面咱们使用的时request.urlopen()方法,而若是咱们但愿模拟一个请求,咱们可使用request.Request()方法,以下所示:

from urllib import request

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 f:
    print('Status:', f.status, f.reason)
    for k, v in f.getheaders():
        print('%s: %s' % (k, v))
    print('Data:', f.read().decode('utf-8'))

如上所示,咱们以前使用的是request.urlopen()获得的结果,而这里使用的是request.urlopen(request.request())的结果,也就是以前的函数接受了一个域名做为参数,而这里接受了一个request.Request()做为参数,而后咱们使用req.add_header()也能够模仿Ipone手机进行请求,结果以下:

Status: 200 OK
Date: Wed, 28 Mar 2018 14:23:39 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 11531
Connection: close
Vary: Accept-Encoding
X-Xss-Protection: 1; mode=block
X-Douban-Mobileapp: 0
Expires: Sun, 1 Jan 2006 01:00:00 GMT
Pragma: no-cache
Cache-Control: must-revalidate, no-cache, private
Set-Cookie: bid=6cgMQfk41-I; Expires=Thu, 28-Mar-19 14:23:39 GMT; Domain=.douban.com; Path=/
X-DOUBAN-NEWBID: 6cgMQfk41-I
X-DAE-Node: hador1
X-DAE-App: talion
Server: dae
Strict-Transport-Security: max-age=15552000;
X-Content-Type-Options: nosniff
Data:


<!DOCTYPE html>
<html itemscope itemtype="http://schema.org/WebPage">
    <head>
        <meta charset="UTF-8">
        <title>豆瓣(手机版)</title>
        <meta name="viewport" content="width=device-width, height=device-height, user-scalable=no, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0">
        <meta name="format-detection" content="telephone=no">
        <link rel="canonical" href="
http://m.douban.com/">
        <link href="https://img3.doubanio.com/f/talion/05520a911efa802a06abd2263b41ac0e2bf335c6/css/card/base.css" rel="stylesheet">

    <meta name="description" content="读书、看电影、涨知识、学穿搭...,加入兴趣小组,得到达人们的高质量生活经验,找到有相同爱好的小伙伴。">
    <meta name="keywords" content="豆瓣,手机豆瓣,豆瓣手机版,豆瓣电影,豆瓣读书,豆瓣同城">

  这样,咱们就获得了豆瓣手机版的html页面。

 

 

  一样,既然能够发送get请求,也是能够发送post请求的,咱们只须要把参数data以bytes的形式传送:

from urllib import request, parse

print('Login to weibo.cn...')
email = input('Email: ')
passwd = input('Password: ')
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')
])

req = request.Request('https://passport.weibo.cn/sso/login')
req.add_header('Origin', 'https://passport.weibo.cn')
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')
req.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(req, data=login_data.encode('utf-8')) as f:
    print('Status:', f.status, f.reason)
    for k, v in f.getheaders():
        print('%s: %s' % (k, v))
    print('Data:', f.read().decode('utf-8'))

  若是成功登录,得到以下响应:

Status: 200 OK
Server: nginx/1.2.0
...
Set-Cookie: SSOLoginState=1432620126; path=/; domain=weibo.cn
...
Data: {"retcode":20000000,"msg":"","data":{...,"uid":"1658384301"}}

  若是失败:

Data: {"retcode":50011015,"msg":"\u7528\u6237\u540d\u6216\u5bc6\u7801\u9519\u8bef","data":{"username":"example@python.org","errline":536}}

 

  若是更为复杂,咱们能够经过一个Proxy访问网站:

proxy_handler = urllib.request.ProxyHandler({'http': 'http://www.example.com:3128/'})
proxy_auth_handler = urllib.request.ProxyBasicAuthHandler()
proxy_auth_handler.add_password('realm', 'host', 'username', 'password')
opener = urllib.request.build_opener(proxy_handler, proxy_auth_handler)
with opener.open('http://www.example.com/login.html') as f:
    pass

  urllib提供的功能就是利用程序去执行各类HTTP请求。若是要模拟浏览器完成特定功能,须要把请求假装成浏览器。假装的方法是先监控浏览器发出的请求,再根据浏览器的请求头来假装,User-Agent头就是用来标识浏览器的

  

 

HTMLParser

  若是咱们要编写一个搜索引擎,第一步是用爬虫把目标网站的页面抓下来,第二步就是解析该HTML页面,看看页面的内容究竟是新闻、图片仍是视频。好比第一步已经完成,那么第二步如何解析HTML呢?

  python提供了HTMLParser来很是方便的解析HTML,只须要几行代码。

  找一个网页,例如https://www.python.org/events/python-events/,用浏览器查看源码并复制,而后尝试解析一下HTML,输出Python官网发布的会议时间、名称和地点。

from html.parser import HTMLParser
from urllib import request
import re

class MyHTMLParser(HTMLParser):
    flag = 0
    res = []
    is_get_data = 0

    def handle_starttag(self, tag, attrs):
        if tag == 'ul':
            fora attr in attrs:
                if re.match(r'list-recent-events', attr[1]):
                    self.flag = 1

        if tag == 'a' and self.flag == 1:
            self.is_get_data = 'title'

        if tag == 'time' and self.flag == 1:
            self.is_get_data = 'time'

        if tag == 'span' and self.flag == 1:
            self.is_get_data == 'addr'


    def handle_endtag(self, tag):
        if self.flag == 1 and tag == 'ul':
            self.flag = 0

    def handle_data(self, data):
        if self.is_get_data and self.flag == 1:
            if self.is_get_data == 'title':
                self.res.append({self.is_get_data: data})
            else:
                self.res[len(self.res) - 1][self.is_get_data] = data
            self.is_get_data = None

parser = MyHTMLParser()

with request.urlopen('https://www.python.org/events/python-events/') as f:
    data = f.read().decode('utf-8')

parser.feed(data)
for item in MyHTMLParser.res:
    print('------------')
    for k,v in item.items():
        print('%s : %s' % (k, v))

  最终的结果以下所示:

------------
title : PythonCamp 2018 - Cologne
time : 07 April – 09 April
------------
title : PyCon IT 9
time : 19 April – 23 April
------------
title : PyDays Vienna
time : 04 May – 06 May
------------
title : GeoPython 2018
time : 07 May – 10 May
------------
title : PyCon US 2018
time : 09 May – 18 May
------------
title : DjangoCon Europe 2018
time : 23 May – 28 May
------------
title : PyCon SK 2018
time : 09 March – 12 March
------------
title : PyCon PH 2018
time : 24 Feb. – 26 Feb.

  如上所示,搜索引擎也大体是这个原理,就是先获取到全部网页的HTML,而后在经过HTMLParser来获取到相关的内容 ,若是符合则展现在用户的浏览器中。 这便就是爬虫了。

 

 

 

经常使用第三方模块

Pillow

  PIL,即Python Imaging LIbrary, 即python图画库,是python平台事实上的图片处理标准库,可是PIL时间很长了,开发者又新出了Pillow代替之,若是已经安装了Anaconda,那么就已经包含了Pillow了。不然须要经过pip安装:

pip install pillow

  使用pillow操做图像,只须要以下所示:

from PIL import Image

#使用Image.open打开一个图片,才能操做
im = Image.open('c:/users/administrator/desktop/001.png')

#得到图像尺寸
w, h = im.size

#将图片缩小50%
im.thumbnail((w//10, h//10)) #这里接受的是一个tuple

#保存图片
im.save('c:/users/administrator/desktop/010.png')

  如上所示,引入Image类,而后使用open方法打开一个文件,接着经过size属性获取到大小,使用thumbnail接受一个tuple能够缩小图片,经过save方法保存图片。

  另外,咱们还能够对图片进行filter处理,以下:

from PIL import Image, ImageFilter

# 打开一个jpg图像文件,注意是当前路径:
im = Image.open('test.jpg')
# 应用模糊滤镜:
im2 = im.filter(ImageFilter.BLUR)
im2.save('blur.jpg', 'jpeg')


  因而,咱们能够发现python的能力仍是很强大的,能够处理操做系统的任何操做,如删除、添加、修改文件,这里还能够作到ps的效果。

 

  咱们常常能够在网站上看到验证码图片,这里,咱们就能够建立一个验证码图片:

from PIL import Image, ImageDraw, ImageFont, ImageFilter

import random

#产生随机字母
def rndChar():
    return chr(random.randint(65, 90))

#产生随机颜色1,用于填充背景
def rndColor():
    return (random.randint(64, 255), random.randint(64, 255), random.randint(64, 255))

#产生随机颜色2,用于填充文字,以便和背景区别开来
def rndColor2():
    return (random.randint(32, 69), random.randint(32, 69), random.randint(32, 69))

#图片的宽和高
height = 100
width = height * 4

#建立一个图片
image = Image.new('RGB', (width, height), (255, 255, 255))

#建立Font对象
font = ImageFont.truetype('c:/windows/fonts/Arial.ttf', 48)

#建立Draw对象,在以前建立的image图片上进行绘画
draw = ImageDraw.Draw(image)

#填充每个像素
for x in range(width):
    for y in range(height):
        # 对每一个点填充颜色,使用了draw对象
        draw.point((x, y), fill=rndColor())

#文字填充,使用了draw对象
for t in range(4):
    draw.text((height * t + 40, 25), rndChar(), font=font, fill=rndColor2())

#模糊处理
image = image.filter(ImageFilter.BLUR)
image.save('c:/users/administrator/desktop/code.png')

 如上所示,这里使用random模块产生随机数是很是方便的,而后使用Image能够建立图片,使用ImageDraw对象能够对图片进行绘画,最后就能够得到验证码图片了:
   

     

  上面使用的是英文,若是咱们但愿生成简体中文也是能够的,咱们在c:/windows/fonts下面找到合适的ttf文件,如Dent.ttf文件,替换掉Arial.ttf文件,而后在rndChar()的内容修改成:

#产生随机汉字
def rndHan():
    return chr(random.randint(28000, 30000))

 这样,咱们就能够获得汉字了,以下所示:

  

 

 

Requests模块

  以前使用了urllib模块,可是更为方便的是Request模块,处理url资源更为方便。若是已经安装了anaconda,那么Request模块就已经存在了,不然须要经过pip install requests进行安装。

  注意:以前的urllib时内建库,而这里的requests模块是第三方库,这个库更加方便使用。

>>> import requests
>>> r = requests.get('https://www.douban.com/')
>>> r.status_code
200
>>> r.text
'<!DOCTYPE HTML>\n<html lang="zh-cmn-Hans" class="">\n<head>\n<meta charset="UTF-8">\n<meta name="description" content="提供图书、电影、音乐唱片的推荐、评论和价格比较,以及城市独特的文化生活。">\n<meta name="keywords" content="豆瓣,广播,登 陆豆瓣">\n<meta property="qc:admins" content="2554215131764752166375" />\n<meta property="wb:webmaster" content="375d4a17a4fa24c2" />\n<meta

  如上所示,咱们引入requests模块以后,直接就能够发送一个get请求,而后经过status_code属性获得状态码,经过text属性得到内容。

  另外,对于get请求,咱们能够加入第二个参数,params,这是一个dict,以下:

>>> r = requests.get('https://www.baidu.com/s', params={'wd': 'python'})
>>> r.status_code
200
>>> r.url
'https://www.baidu.com/s?wd=python'

  另外,咱们还能够经过r.encoding来得到当前的编码格式。get请求中的第二个参数也能够是headers,即添加请求头,以下所示:

>>> r = requests.get('https://www.douban.com/', headers={'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit'})

 

  若是要发送post请求,只须要requests.post()方法便可,第一个参数为主机名,第二个参数为data,其值是一个dict,

>>> r = requests.post('https://accounts.douban.com/login', data={'form_email': 'abc@example.com', 'form_password': '123456'})

  

  

  

chardet库

  若是安装了anaconda,那么chardet就自动在其中了。不然就要再自行安装: pip install chardet。

  使用也很是简单,就是chardet.detect()进行检测,以下所示:

>>> import chardet
>>> chardet.detect(b'hello world!')
{'encoding': 'ascii', 'confidence': 1.0, 'language': ''}
>>> data = '白日依山尽,黄河入海流'.encode('gbk')
>>> chardet.detect(data)
{'encoding': 'GB2312', 'confidence': 0.99, 'language': 'Chinese'}
>>> data = '白日依山尽,黄河入海流'.encode('utf-8')
>>> chardet.detect(data)
{'encoding': 'utf-8', 'confidence': 0.99, 'language': ''}
>>> data = '最新の主要ニュース'.encode('euc-jp')
>>> chardet.detect(data)
{'encoding': 'EUC-JP', 'confidence': 0.99, 'language': 'Japanese'}

  如上所示,咱们经过chardet.detect()进行检测编码,就能够合理的使用相应的解码函数进行解码而不会出错、而且能够依据编码方式解决其余问题了。

 

 

 

psutil库

  用python来编写脚本简化平常的运维工做是Python的一个重要用途。在linux下,有许多系统命令可让咱们实时监控系统运行的状态,如ps、top、free等等,要获取这些胸信息,python能够经过subprocess模块低啊用并获取结果,但麻烦。 而python中使用psutil第三方模块获取系统信息会很方便,是系统管理员和运维小伙伴不可或缺的必备模块。

   这个库中有不少方法能够直接查看cpu、内存等内容,也能够获取到全部的进程线程,控制线程进程,因此作运维的,通常仍是很须要psutil库的。

 

 

virtuallenv

  在开发Python应用程序的时候,系统安装的Python3只有一个版本:3.4. 全部的第三方的包都会被Pip安装到python3的site-packages目录下。 若是咱们要开发多个应用程序,那这些应用程序就会提供一个python.

  就是系统的python3,可是若是应用A须要jinja2.7,而应用B须要jinja2.6怎么办?这样状况下,每一个应用可能须要拥有一套‘独立’的python运行环境。而Virtualenv就是用来为一个应用建立一套“隔离”的python运行环境。这样就能够解决不一样版本的冲突问题了。

相关文章
相关标签/搜索