1. 程式人生 > >反爬蟲繞過初級——新增http header和gzip解壓處理

反爬蟲繞過初級——新增http header和gzip解壓處理

  這陣子在學習爬蟲,做練習需要一個禁止爬蟲且只需新增Header就能繞過的網站。運氣不錯,找到一個HTTPS協議的,考慮到該網站內容比較special(人類進步的階梯^_^),所以本文會把網站的相關資訊碼掉。
  python處理http協議部分,本文采用的是urllib.request,沒有用Requests。通過相關網站介紹可知,如果採用這個庫,本文中各個實現的程式碼會少些,也不會遇到我後面處理的gzip解壓縮問題。不過對於我這種新手來說,有時適當踩些坑有利於學習,畢竟“朝抵抗力最大的路徑走”,收穫的東西會更多。
  在做Demo時,Python提示–> urlopen error unknown url type: https,也就是不支援https協議。隨後查到是安裝Python時,系統沒有安裝openssl-devel導致,因此需重新安裝openssl-devel庫 –>具體可以參考

python內建的urllib模組不支援https協議的解決辦法。不同於文章介紹的,我的系統是Ubuntu,而Ubuntu採用的安裝指令是下面這兩條。

sudo apt-get install openssl
sudo apt-get install libssl-dev

  安裝好openssl-devel庫後,重新安裝一遍Python,採用如下程式碼測試,不再提示不支援,也確認該網站是禁止爬蟲的。 

#!/usr/local/bin/python3
#-*- coding: utf-8 -*-
import urllib.request

url='https://abc.de/'
urllib.request.urlretrieve(url, 'test.html'
)

403 forbidden錯誤

  這個網站真是練爬蟲第一關的不錯選擇,對付這個網站的反爬蟲策略,解法是通過urllib.request中新增http請求頭部欄位,實現模擬瀏覽器訪問,具體程式碼如下。下面的這些欄位都是通過chrome的F12抓下來的,刪除了一部分:

#!/usr/local/bin/python3
#-*- coding: utf-8 -*-
import urllib.request

url='https://abc.de/'
req = urllib.request.Request(url)
req.add_header('Host', 'abc.de')
req.add_header('Connection'
,'keep-alive') req.add_header('Cache-Control','max-age=0') req.add_header('Upgrade-Insecure-Request','1') req.add_header('User-Agent','Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36') req.add_header('Accept','text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8') req.add_header('Accept-Encoding', 'gzip, deflate, sdch, br') req.add_header('Accept-Language','zh-CN,zh;q=0.8,en;q=0.6') data = urllib.request.urlopen(req).read() print(data)

  實際測試繞過成功,不再提示403 forbidden了。不過出現新的問題,抓下來的資料是一大波encode的資料。一開始我以為是編碼問題,於是根據網頁的charset資訊加了data.decode(‘utf-8’),但提示報錯,隨後嘗試其他各種編解碼處理方式都沒有用。

繞過反爬出現亂碼

  無計之下,重新回來看response header,在看到content-encoding欄位的時候,才想起還有一個么蛾子,所以google解決方案,隨後參考Python 抓取網頁亂碼原因分析新增如下程式碼

header資訊

  專欄程式碼實現不能直接套用,有錯誤,因此新增調整程式碼如下:

#-*- coding: utf-8 -*-
import urllib.request
import gzip
import io 

data = urllib.request.urlopen(req)
encoding = data.getheader('Content-Encoding')
content = data.read()
if encoding == 'gzip':
    buf = io.BytesIO(content)
    gf = gzip.GzipFile(fileobj=buf)
    content = gf.read()

#with open('test.html',"wb") as fb:
#    fb.write(data)

print(content)

  調整後測試效果如下,成功繞過反爬策略和實現gzip解壓,解決了資料無法識別的問題。

繞過成功

  考慮到上面新增header的方式比較麻煩,而參考書中提供的另一種方式也半斤八兩,所以我嘗試了另一種方式,具體程式碼如下。測試時也發現網站,去除Accept-Language會導致繞過失敗,依舊返回403錯誤。這也就說明,該網站是通過多個欄位來判別是否為爬蟲訪問,所以以後處理的時候,可以儘量把正常訪問時瀏覽器提交欄位都提交一遍,避免不必要的麻煩。

#!/usr/local/bin/python3
#-*- coding: utf-8 -*-
import urllib.request
import gzip
import io 

'''[TEST]'''
url = 'https://abc.de/'

Headers = {
        'Host':'abc.de',
        'Connection':'keep-alive',
        'Cache-Control':'max-age=0',
        'Upgrade-Insecure-Request':'1',
        'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36',
        'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
        'Accept-Encoding':'gzip, deflate, sdch, br',
        'Accept-Language':'zh-CN,zh;q=0.8,en;q=0.6'
}

req = urllib.request.Request(url, None, Headers)
data =urllib.request.urlopen(req).read()
print(data)