今天在使用python爬蟲時遇到一個奇怪的問題,使用的是自帶的urllib庫,在解析網頁時獲取到的為b'\x1f\x8b\x08\x00\x00\x00\x00...等十六進制數字,嘗試使用chardet來檢查編碼格式時發現encoding為None,因為以前一直用的是requests庫,所以沒有仔細注意過這個問題,經過詳細搜索后分析如下(下面代碼是修改后加入gzip的):
轉載注明http://www.cnblogs.com/RainLa/p/8057367.html
一.HTTP 內容協商
有時候,同一個 URL 可以提供多份不同的文檔,這就要求服務端和客戶端之間有一個選擇最合適版本的機制,這就是內容協商
HTTP 的內容協商的其中一種方式:服務端根據客戶端發送的請求頭中某些字段自動發送最合適的版本。可以用於這個機制的請求頭字段又分兩種:內容協商專用字段(Accept 字段)、其他字段
字段情況,詳見下表:
請求頭字段 | 說明 | 響應頭字段 |
---|---|---|
Accept | 告知服務器發送何種媒體類型 | Content-Type |
Accept-Language | 告知服務器發送何種語言 | Content-Language |
Accept-Charset | 告知服務器發送何種字符集 | Content-Type |
Accept-Encoding | 告知服務器采用何種壓縮方式 | Content-Encoding |
例如客戶端發送以下請求頭:
Accept-Encoding:gzip,deflate,br
表示支持采用 gzip、deflate 或 br 壓縮過的資源
瀏覽器的響應頭可能是這樣的:
Content-Encoding: gzip
二.服務器返回response-header中Content-Encoding:gzip
可以發現是服務器使用了壓縮算法,而且壓縮算法為gzip,而且gzip壓縮算法的特點是以1f8b開頭,具體字節順序分析為(下面解釋摘抄自http://blog.csdn.net/jison_r_wang/article/details/52068962,本人實際測試過,都對應的上,不過原作者解釋的很好,所以直接摘抄過來)
0000 0000h, 0~1,開始的兩個字節是標識符1F8B;
0000 0000h, 2,CM (Compression Method),壓縮方式,08表示deflate算法;
0000 0000h, 3,FLG (FLaGs),標志位,十六進制08,即二進制0000 1000,從右往左分別是bit0~bit7,現在bit3置位,對應FNAME,即該gzip頭后面的擴展部分是帶着原始文件名的;
0000 0000h,4~7,這四個字節是時間,分別是十六進制“38 DA 71 57”,這是存儲的順序,我們轉換成人們正常讀取的順序“57 71 DA 38”,將其轉換成時間,先把5771DA38轉換成十進制即1467079224,轉換為時間為2016/6/28 10:0:24
0000 0000h, 8,XFL (eXtra FLags),十六進制02,這個地方我也有點糊塗,但我估計應該是用的XFL = 4 - compressorused fastest algorithm;
0000 0000h, 9,00,即0 - FAT filesystem (MS-DOS, OS/2,NT/Win32),我用的是win7,也是對應的。
0000 0000h, a~00000010h, 1,共8個字節,存儲的是原始文件的文件名“abc.txt”,末尾還有個'\0'表示結束,從這里可以看出,這個文件名只是個文件名,沒攜帶路徑信息。從這里往后,就是實際的壓縮數據信息了;
0000 0030h, b~e,這四個字節是CRC32校驗碼,分別是十六進制“45 2D F1 80”,這是存儲的順序,我們轉換成人們正常讀取的順序“80 F1 2D 45”,原文件內容為“abcabcabcdeabcdefghijklmnopqrstopqrstuvvvvabcabcabcdeabcdefghijklmnopqrstuv”,使用CRC計算器算得結果如下圖所示
0000 0030h, f~0000 0040h, 2,這四個字節是原始文件的大小,分別是十六進制“4B 00 00 00”,這是存儲的順序,我們轉換成人們正常讀取的順序“00 00 00 4B”,即十進制的75,原始文件大小75字節,這也與文件信息對應。
三.在觀察request-header中Accept-Encoding:gzip, deflate, sdch, br發現了四種不同的壓縮算法,現總結如下:
1.gzip是一種數據格式,默認且目前僅使用deflate算法壓縮data部分;deflate是一種壓縮算法,是huffman編碼的一種加強。在nginx中gzip默認的使用deflate壓縮,apache中因為歷史原因分為mod_deflate 和mod_gzip 兩個模塊,不管使用mod_gzip 還是mod_deflate,此處返回的信息都一樣。因為它們都是實現的gzip壓縮方式。Apache 1.x系列沒有內建網頁壓縮技術,所以才去用額外的第三方mod_gzip 模塊來執行壓縮。而Apache 2.x官方在開發的時候,就把網頁壓縮考慮進去,內建了mod_deflate 這個模塊,用以取代mod_gzip。雖然兩者都是使用的Gzip壓縮算法,它們的運作原理是類似的。其他區別見http://www.webkaka.com/tutorial/server/2015/021013/
2.sdch是Shared Dictionary Compression over HTTP的縮寫,即通過字典壓縮算法對各個頁面中相同的內容進行壓縮,減少相同的內容的傳輸。如:一個網站中一般都是共同的頭部和尾部,甚至一些側邊欄也是共同的。之前的方式每個頁面打開的時候這些共同的信息都要重新加載,但使用SDCH壓縮方式的話,那些共同的內容只用傳輸一次就可以了。sdch主要分為3個部分:首次請求,下載字典,之后的請求。
3.br就是 Brotli(摘抄自https://segmentfault.com/a/1190000009383543)
Brotli is a generic-purpose lossless compression algorithm that compresses data using a combination of a modern variant of the LZ77 algorithm, Huffman coding and 2nd order context modeling, with a compression ratio comparable to the best currently available general-purpose compression methods. It is similar in speed with deflate but offers more dense compression.
Brotli 是基於LZ77算法的一個現代變體、霍夫曼編碼和二階上下文建模。Google軟件工程師在2015年9月發布了包含通用無損數據壓縮的Brotli增強版本,特別側重於HTTP壓縮。其中的編碼器被部分改寫以提高壓縮比,編碼器和解碼器都提高了速度,流式API已被改進,增加更多壓縮質量級別。
與常見的通用壓縮算法不同,Brotli使用一個預定義的120千字節字典。該字典包含超過13000個常用單詞、短語和其他子字符串,這些來自一個文本和HTML文檔的大型語料庫。預定義的算法可以提升較小文件的壓縮密度。
使用Brotli替換Deflate來對文本文件壓縮通常可以增加20%的壓縮密度,而壓縮與解壓縮速度則大致不變。
四.nginx使用br
安裝與配置過程
安裝需要用到開發工具
CentOS,如下
yum groupinstall 'Development Tools'
Ubuntu,如下
sudo apt-get install autoconf libtool automake
這次的教程實踐環境是CentOS 7,已經在linpx.com上實現了
下面開始正式的教程
安裝libbrotli
cd /usr/local/src/ git clone https://github.com/bagder/libbrotli cd libbrotli ./autogen.sh ./configure make && make install
安裝ngx_brotli
cd /usr/local/src/ git clone https://github.com/google/ngx_brotli cd ngx_brotli && git submodule update --init
下載Nginx
這里使用 nginx-1.10.3
cd /usr/local/src
wget http://nginx.org/download/nginx-1.10.3.tar.gz tar -xvzf nginx-1.10.3.tar.gz && rm -rf nginx-1.10.3.tar.gz
獲取Nginx Arguments
nginx -V
整理新的Arguments
根據獲取到的configure arguments和上面軟件的位置,重新整理configure arguments
然后再加上 --add-module=/usr/local/src/ngx_brotli
開始安裝和編譯
cd /usr/local/src/nginx-1.10.3 ./configure [這里是你的原Arguments] --add-module=/usr/local/src/ngx_brotli make && make install
檢查是否安裝正常
nginx -V nginx -t
找到Nginx的全局配置文件
如果檢測安裝正常的話,可以開始配置,該配置文件一般為 nginx.conf
在合適的位置插入下面代碼
#Brotli Compression brotli on; brotli_comp_level 6; brotli_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript image/svg+xml;
再次檢測是否正常
nginx -t
重啟Nginx
如果正常的話,恭喜你,你已經配置完成了,重啟一下Nginx即可
CentOS 6.x:
service nginx restart
CentOS 7.x:
systemctl restart nginx
檢查是否生效
打開你的網頁,用chrome開發者工具調試,在Network那,發現有content-encoding:br
可能的報錯
如果在測試或者重載時, Nginx 報錯如下:
nginx: error while loading shared libraries: libbrotlienc.so.1: cannot open shared object file: No such fileor directory
解決方法是把對應的庫文件在 /lib(64) 或者 /usr/lib(64) 中做上軟鏈接:
$ ln -s /usr/local/lib/libbrotlienc.so.1 /lib64 # 32 位系統 $ ln -s /usr/local/lib/libbrotlienc.so.1 /lib
解決:
需要重新對nginx編譯安裝:
1
|
[root@localhost ~]
# tar zxvf nginx-1.8.1.tar.gz
|
進入nginx目錄,修改src/http/ngx_http_header_filter_module.c:
1
|
[root@localhost nginx
-
1.8
.
1
]
# vim src/http/ngx_http_header_filter_module.c
|
修改:
1
2
3
4
5
6
7
|
內容:
static char ngx_http_server_string[]
=
"Server: nginx"
CRLF;
static char ngx_http_server_full_string[]
=
"Server: "
NGINX_VER CRLF;
更改為:
static char ngx_http_server_string[]
=
"Server: X-Web"
CRLF;
static char ngx_http_server_full_string[]
=
"Server:X-Web "
CRLF;
|
編譯安裝:
1
2
|
[root@localhost nginx
-
1.8
.
1
]
# ./configure --prefix=/data/nginx --with-http_stub_status_module
[root@localhost nginx
-
1.8
.
1
]
# make && make install
|
重啟nginx:
1
|
[root@localhost sbin]
# service nginx restart
|
驗證: