1. 程式人生 > 實用技巧 >Python爬蟲技術--基礎篇--內建模組base64

Python爬蟲技術--基礎篇--內建模組base64

1.base64

Base64是一種用64個字元來表示任意二進位制資料的方法

用記事本開啟exejpgpdf這些檔案時,我們都會看到一大堆亂碼,因為二進位制檔案包含很多無法顯示和列印的字元,所以,如果要讓記事本這樣的文字處理軟體能處理二進位制資料,就需要一個二進位制到字串的轉換方法。Base64是一種最常見的二進位制編碼方法。

Base64的原理很簡單,首先,準備一個包含64個字元的陣列:

['A', 'B', 'C', ... 'a', 'b', 'c', ... '0', '1', ... '+', '/']

然後,對二進位制資料進行處理,每3個位元組一組,一共是3x8=24bit,劃為4組,每組正好6個bit:

這樣我們得到4個數字作為索引,然後查表,獲得相應的4個字元,就是編碼後的字串。

所以,Base64編碼會把3位元組的二進位制資料編碼為4位元組的文字資料,長度增加33%,好處是編碼後的文字資料可以在郵件正文、網頁等直接顯示。

如果要編碼的二進位制資料不是3的倍數,最後會剩下1個或2個位元組怎麼辦?Base64\x00位元組在末尾補足後,再在編碼的末尾加上1個或2個=號,表示補了多少位元組,解碼的時候,會自動去掉

Python內建的base64可以直接進行base64的編解碼:

>>> import base64
>>> base64.b64encode(b'binary\x00string')
b'YmluYXJ5AHN0cmluZw=='
>>> base64.b64decode(b'YmluYXJ5AHN0cmluZw==')
b'binary\x00string'

由於標準的Base64編碼後可能出現字元+/,在URL中就不能直接作為引數,所以又有一種"url safe"的base64編碼,其實就是把字元+/分別變成-_

>>> base64.b64encode(b'i\xb7\x1d\xfb\xef\xff')
b'abcd++//'
>>> base64.urlsafe_b64encode(b'i\xb7\x1d\xfb\xef\xff')
b'abcd--__'
>>> base64.urlsafe_b64decode('abcd--__')
b'i\xb7\x1d\xfb\xef\xff'

還可以自己定義64個字元的排列順序,這樣就可以自定義Base64編碼,不過,通常情況下完全沒有必要。

Base64是一種通過查表的編碼方法,不能用於加密,即使使用自定義的編碼表也不行

Base64適用於小段內容的編碼,比如數字證書籤名、Cookie的內容等。

由於=字元也可能出現在Base64編碼中,但=用在URL、Cookie裡面會造成歧義,所以,很多Base64編碼後會把=去掉:

# 標準Base64:
'abcd' -> 'YWJjZA=='
# 自動去掉=:
'abcd' -> 'YWJjZA'

去掉=後怎麼解碼呢?因為Base64是把3個位元組變為4個位元組,所以,Base64編碼的長度永遠是4的倍數,因此,需要加上=把Base64字串的長度變為4的倍數,就可以正常解碼了。

小結

Base64是一種任意二進位制到文字字串的編碼方法,常用於在URL、Cookie、網頁中傳輸少量二進位制資料

2.struct

準確地講,Python沒有專門處理位元組的資料型別。但由於b'str'可以表示位元組,所以,位元組陣列=二進位制str。而在C語言中,我們可以很方便地用struct、union來處理位元組,以及位元組和int,float的轉換。

在Python中,比方說要把一個32位無符號整數變成位元組,也就是4個長度的bytes,你得配合位運算子這麼寫:

>>> n = 10240099
>>> b1 = (n & 0xff000000) >> 24
>>> b2 = (n & 0xff0000) >> 16
>>> b3 = (n & 0xff00) >> 8
>>> b4 = n & 0xff
>>> bs = bytes([b1, b2, b3, b4])
>>> bs
b'\x00\x9c@c'

非常麻煩。如果換成浮點數就無能為力了。

好在Python提供了一個struct模組來解決bytes和其他二進位制資料型別的轉換

structpack函式把任意資料型別變成bytes

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

pack的第一個引數是處理指令,'>I'的意思是:

>表示位元組順序是big-endian,也就是網路序,I表示4位元組無符號整數

後面的引數個數要和處理指令一致。

unpackbytes變成相應的資料型別

>>> struct.unpack('>IH', b'\xf0\xf0\xf0\xf0\x80\x80')
(4042322160, 32896)

根據>IH的說明,後面的bytes依次變為I:4位元組無符號整數和H:2位元組無符號整數。

所以,儘管Python不適合編寫底層操作位元組流的程式碼,但在對效能要求不高的地方,利用struct就方便多了。

struct模組定義的資料型別可以參考Python官方文件:

https://docs.python.org/3/library/struct.html#format-characters

Windows的點陣圖檔案(.bmp)是一種非常簡單的檔案格式,我們來用struct分析一下。

首先找一個bmp檔案,沒有的話用“畫圖”畫一個。

讀入前30個位元組來分析:

>>> s = b'\x42\x4d\x38\x8c\x0a\x00\x00\x00\x00\x00\x36\x00\x00\x00\x28\x00\x00\x00\x80\x02\x00\x00\x68\x01\x00\x00\x01\x00\x18\x00'

BMP格式採用小端方式儲存資料,檔案頭的結構按順序如下:

兩個位元組:'BM'表示Windows點陣圖,'BA'表示OS/2點陣圖; 一個4位元組整數:表示點陣圖大小; 一個4位元組整數:保留位,始終為0; 一個4位元組整數:實際影象的偏移量; 一個4位元組整數:Header的位元組數; 一個4位元組整數:影象寬度; 一個4位元組整數:影象高度; 一個2位元組整數:始終為1; 一個2位元組整數:顏色數。

所以,組合起來用unpack讀取:

>>> struct.unpack('<ccIIIIIIHH', s)
(b'B', b'M', 691256, 0, 54, 40, 640, 360, 1, 24)

結果顯示,b'B'b'M'說明是Windows點陣圖,點陣圖大小為640x360,顏色數為24。