從python爬蟲引發出的gzip,deflate,sdch,br壓縮算法分析


今天在使用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) 中做上軟鏈接:

  # 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

驗證:

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM