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運行環境。這樣就能夠解決不一樣版本的衝突問題了。

相關文章
相關標籤/搜索