【動圖詳解】經過 User-Agent 識別爬蟲的原理、實踐與對應的繞過方法

開篇

隨着 Python 和大數據的火熱,大量的工程師一擁而上,爬蟲技術因爲易學、效果顯著首當其衝的成爲了你們追捧的對象,爬蟲的發展進入了高峯期,所以給服務器帶來的壓力則是成倍的增長。企業或爲了保證服務的正常運轉或爲了下降壓力與成本,不得不使出各類各樣的技術手段來阻止爬蟲工程師們毫無節制的向服務器索取資源,咱們將這種行爲稱爲『反爬蟲』。php

『反爬蟲技術』是互聯網技術中爲了限制爬蟲而產生的技術總稱,而反爬蟲的繞過則是全部爬蟲工程師要面對的問題,也是中高級爬蟲工程師面試中最關注的方面。python

問題所在

可是在平時的交流中,筆者發現大多數的初級爬蟲工程師只會拿着網上別人寫的技術文章唾沫橫飛,除了知道在請求的時候僞造瀏覽器請求頭信息中的 User-Agent 之外,對於:linux

  • 爲何要這麼作?
  • 這麼作有什麼好處?
  • 我能夠用別的方法實現麼?
  • 它的原理是怎麼樣的?
  • 它是如何識別個人爬蟲的?
  • 我應該用什麼方式繞過它?

一無所知。若是你既不知道原理又不知道實現方式,那麼當目標網站稍微調整一下反爬蟲策略的時候,你仍是一臉懵逼nginx

對,就是一臉懵逼。web

做者心聲

我也在嘗試着,可以將這樣的知識分享出來,讓你們在閒暇之餘可以經過這篇文章學習到反爬蟲知識中比較簡單的反爬蟲原理和實現方法,再熟悉他的繞過操做。好比 User-Agent 反爬手段,瞭解它的原理而且親手實現反爬蟲,再親手繞過它。或許經過這個小小的案例,就能夠打開你思惟的大門、撬開你思路的下水道。 面試

正文

上面是空談,下面是實踐。一位偉人曾經表達過這麼一個意思:編程

管你黑貓白貓,抓不到老鼠的貓,它就不是個好貓後端

什麼是 User-Agent

User Agent中文名爲用戶代理,簡稱 UA,它是一個特殊字符串頭,使得服務器可以識別客戶使用的操做系統及版本、CPU 類型、瀏覽器及版本、瀏覽器渲染引擎、瀏覽器語言、瀏覽器插件等。一些網站經常經過判斷 UA 來給不一樣的操做系統、不一樣的瀏覽器發送不一樣的頁面,所以可能形成某些頁面沒法在某個瀏覽器中正常顯示,但經過假裝 UA 能夠繞過檢測。瀏覽器向服務器發起請求的流程圖,能夠用下圖表示:瀏覽器

這裏以火狐瀏覽器和谷歌瀏覽器爲例,UA 的格式或者說表現形式是這樣的:bash

Firefox 的 User-Agent:

Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:63.0) Gecko/20100101 Firefox/63.0
複製代碼

Chrome 的 User-Agent:

Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36
複製代碼

User-Agent 在網絡請求中充當什麼角色?

在網絡請求當中,User-Agent 是標明身份的一種標識,服務器能夠經過請求頭參數中的 User-Agent 來判斷請求方是不是瀏覽器、客戶端程序或者其餘的終端(固然,User-Agent 的值爲空也是容許的,由於它不是必要參數)。

瀏覽器的角色,如上圖方框中所示,那麼 User-Agent 的角色,就是代表身份。

爲何反爬蟲會選擇 User-Agent 這個參數呢?

從上面的介紹中,能夠看出它是終端的身份標識。意味着服務器能夠清楚的知道,這一次的請求是經過火狐瀏覽器發起的,仍是經過 IE 瀏覽器發起的,甚至說是不是應用程序(好比 Python )發起的。

網站的頁面、動效和圖片等內容的呈現是藉助於瀏覽器的渲染功能實現的,瀏覽器是一個相對封閉的程序,由於它要確保數據的成功渲染,因此用戶沒法從瀏覽器中大規模的、自動化的獲取內容數據。

而爬蟲卻不是這樣的,爬蟲生來就是爲了獲取網絡上的內容並將其轉化爲數據。這是兩種大相徑庭的方式,你也能夠理解爲經過編寫代碼來大規模的、自動化的獲取內容數據,這是一種騷操做。

回到正題,爲何會選擇 User-Agent 這個參數呢?

由於編程語言都有默認的標識,在發起網絡請求的時候,這個標識在你絕不知情的狀況下,做爲請求頭參數中的 User-Agent 值一併發送到服務器。好比 Python 語言經過代碼發起網絡請求時, User-Agent 的值中就包含 Python 。一樣的,Java 和 PHP 這些語言也都有默認的標識。

反爬蟲的黑名單策略

既然知道編程語言的這個特色,再結合實際的需求,那麼反爬蟲的思路就出來了。這是一中黑名單策略,只要出如今黑名單中的請求,都視爲爬蟲,對於此類請求能夠不予處理或者返回相應的錯誤提示。

爲何用黑名單策略不用白名單策略?

現實生活中,瀏覽器類型繁多(火狐瀏覽器、谷歌瀏覽器、360 瀏覽器、傲遊瀏覽器、歐普拉瀏覽器、世界之窗瀏覽器、QQ 瀏覽器等),

想要將全部的瀏覽器品牌、類型以及對應的標識收集並放到名單中,那是不實際的,假如漏掉了哪種,那麼對網站來講是一種損失。

再者說來,不少的服務並不只僅開放給瀏覽器,有些時候這些服務以 API 的形式嚮應用程序提供服務,好比安卓軟件的後端 API ,爲安卓軟件程序提供數據服務,而軟件自己只承擔界面和結構的任務,而數據則從後端 API 獲取。這個時候,發起的請求中, User-Agent 就會變成 Android 。

以上就是不能使用白名單策略的緣由。

而黑名單在於簡單,當你但願屏蔽來自於 Python 代碼的請求或者來自於 Java 代碼的請求時,只須要將其加入黑名單中便可。

經過 Nginx 服務日誌來查看請求頭中的 User-Agent

Nginx 是一款輕量級的 Web 服務器/反向代理服務器及電子郵件(IMAP/POP3)代理服務器。其特色是佔有內存少,併發能力強,事實上 Nginx 的併發能力確實在同類型的網頁服務器中表現較好,使用 Nginx 企業有:百度、京東、新浪、網易、騰訊、淘寶等。

Nginx 的安裝與啓動

一般可使用系統自己的安裝工具(Centos 的 yum、Debian 系的 apt-get 以及 MacOS 的 brew)安裝 Nginx,以 linux 系統爲例,在終端中輸入:

sudo apt-get install nginx
複製代碼

接下來根據提示選擇,便可完成 Nginx 的安裝。

接着在終端經過命令:

sudo systemctl start nginx
複製代碼

便可啓動 Nginx 服務。

備註:因爲各個系統差異以及版本差別,安裝和啓動命令略有差異,解決辦法自行搜索

Nginx 的日誌

Nginx 爲用戶提供了日誌功能,其中記錄了每次服務器被請求的狀態和其餘信息,包括 User-Agent。 Nginx 的默認日誌存放路徑爲:

/var/log/nginx/
複製代碼

在終端經過命令

cd /var/log/nginx && ls
複製代碼

能夠進入到日誌存放目錄並列出目錄下的文件,能夠看到其中有兩個主要的文件,爲 access.logerror.log

它們分別記錄着成功的請求信息和錯誤信息。咱們經過 Nginx 的訪問日誌來查看每次請求的信息。

發起請求的幾種辦法

瀏覽器

Nginx 啓動後,默認監聽 80 端口,你只須要訪問 IP 地址或者域名便可。假設 IP 地址爲 127.0.0.1,那麼能夠在瀏覽器輸入:

http://127.0.0.1
複製代碼

回車後,瀏覽器就會向服務器發起請求,和你平時上網是同樣的。

Python 代碼

這裏咱們利用 Requests 庫來發起網絡請求。在本地新建一個名爲 gets.py的文件,其中代碼爲:

import requests
# 向目標發起請求,並打印返回的 http 狀態碼
resp = requests.get("http://127.0.0.1")
print(resp.status_code)
複製代碼

Postman

Postman是一款功能強大的網頁調試與發送網頁HTTP請求的工具(Postman下載地址),它能夠模擬瀏覽器,訪問指定的 Url 並輸出返回內容,實際使用以下圖所示:

Curl

這是一個利用URL語法在命令行下工做的傳輸工具,它不只支持 url 地址訪問還支持文件上傳和下載,因此能夠稱它爲綜合傳輸工具。他也能夠模擬瀏覽器,訪問指定的 Url,實際使用以下圖所示:

Nginx 日誌記錄結果

上面使用了 4 種方法來向服務器發起請求,那麼咱們看看 Nginx 的日誌中,記錄了什麼樣的信息。在終端經過命令:

sudo cat access.log
複製代碼

來查看日誌文件。能夠看到這幾回的請求記錄:

# 請求記錄
127.0.0.1 - - [04/Nov/2018:22:19:07 +0800] "GET / HTTP/1.1" 200 396 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36"
127.0.0.1 - - [04/Nov/2018:22:19:07 +0800] "GET /favicon.ico HTTP/1.1" 404 200 "http://127.0.0.1/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36"
127.0.0.1 - - [04/Nov/2018:22:20:36 +0800] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36"
127.0.0.1 - - [04/Nov/2018:22:27:14 +0800] "GET /z_stat.php?id=1256772952&web_id=1256772952 HTTP/1.1" 404 144 "http://appstore.deepin.org/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/538.1 (KHTML, like Gecko) deepin-appstore/4.0.9 Safari/538.1"
127.0.0.1 - - [04/Nov/2018:22:42:10 +0800] "GET / HTTP/1.1" 200 396 "-" "PostmanRuntime/7.3.0"
127.0.0.1 - - [04/Nov/2018:22:42:51 +0800] "GET / HTTP/1.1" 200 612 "-" "curl/7.60.0"
複製代碼

不管是 Python 仍是 Curl 或者瀏覽器以及 Postman 的請求,都被記錄在日誌文件中,說明 Nginx 能夠識別發起請求的終端類型。

實現反爬蟲

以前的理論和邏輯,在實驗中都獲得了驗證,那麼接下來咱們就經過黑名單策略將 Python 和 Curl 發起的請求過濾掉,只容許 Firefox 和 Postman 的請求經過,而且對被過濾的請求返回 403 錯誤提示。

反爬蟲的過程如上圖所示,至關於在服務器和資源之間創建了一道防火牆,在黑名單中的請求將會被當成垃圾丟棄掉。

配置 Nginx 規則

Nginx 提供了配置文件以及對應的規則,容許咱們過濾掉不容許經過的請求,本次反爬蟲咱們使用的就是它。Nginx 的配置文件一般放在/etc/nginx/目錄下,名爲nginx.conf,咱們經過查看配置文件來看一看,站點的配置文件在什麼地方。再經過系統自帶的編輯器(筆者所用系統自帶 Nano,其餘系統可能自帶 Vim)來編輯配置文件。在配置文件中找到站點配置文件地址(筆者所用電腦存放路徑爲/etc/nginx/sites-enable),再到站點配置文件中找到local級別的配置,並在其中加上一下內容:

if ($http_user_agent ~* (Python|Curl)) {
     return 403;
    }
複製代碼

這段配置的釋義是判斷請求中請求頭字符串中是否包含有 Python或者 Curl,若是包含則直接返回 403 錯誤,不然返回正常的資源。完成配置後保存,再經過命令:

sudo nginx -s reload
複製代碼

整個操做過程如上圖所示,讓 Nginx 服務器從新載入配置文件,使得剛纔的配置生效。

反爬蟲效果測試

重複上面訪問的步驟,經過瀏覽器、Python 代碼、Postman 工具和 Curl發起請求。從返回的結果就能夠看到,與剛纔是有所區別的。

  • 瀏覽器返回的是正常的頁面,說明沒有收到影響;
  • Python 代碼的狀態碼變成了 403,而不是以前的 200
  • Postman 跟以前同樣,返回了正確的內容;
  • Curl 跟 Python 同樣,沒法正確的訪問資源,由於它們發起的請求都被過濾掉了。

提示:你能夠繼續修改 Nginx 的配置來進行測試,最終會發現結果會跟如今的同樣:只要在黑名單中,請求就會被過濾掉而且返回 403 錯誤。

提示:這就是你平時編寫爬蟲代碼時,須要在請求頭中僞造瀏覽器的緣由。

繞過 User-Agent 方式的反爬蟲

經過上面的學習,咱們知道了 User-Agent 反爬蟲這種手段的原理,而且經過 Nginx 來實現了反爬蟲,接下來咱們一塊兒學習如何繞過這種反爬蟲措施。

Python 繞過反爬蟲

在 Requests 庫中,容許用戶自定義請求頭信息,因此咱們能夠在請求頭信息中將 User-Agent 的值改成瀏覽器的請求頭標識,這樣就可以欺騙 Nginx 服務器,達到繞過反爬蟲的目的。將以前的 Python 代碼改成:

import requests
# 僞造請求頭信息 欺騙服務器
headers = {"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:9527.0) Gecko/20100101 Firefox/9527.0"}
resp = requests.get("http://127.0.0.1", headers=headers)
print(resp.status_code)
複製代碼

代碼中咱們用到的是 Firefox 瀏覽器的請求頭信息,並且爲了更好的觀察效果,咱們能夠更改瀏覽器的版本號(改爲9527)以區分真實瀏覽器(這不會影響請求結果)。運行這個文件,看看獲得的返回結果:

200
複製代碼

不是 403 了,說明已經繞過了這種類型的反爬蟲(你看,這就是網上那些文章所寫的,須要修改請求頭信息才能繞過反爬蟲,如今你明白是怎麼回事了吧)。

練習:使用 Postman 再測試一下

一個測試也許不許確,你還能夠經過 Postman 再來測試一下,還記得怎麼作嗎?

  • 將須要過濾的標識(Postman)添加到 Nginx 的配置文件中
  • 重載配置文件,使其生效
  • 經過 Postman 發起請求看看是否會被過濾
  • 再次使用 Postman 工具,而且攜帶上瀏覽器的標識再發起請求,看看是否會被過濾

小提示:這個練習若是你本身來作的話,會更容易理解其中的原理,而且能夠加深你的映像。

總結

回顧一下,整篇文章的過程:

咱們從遇到的反爬蟲現象開始入手,接着學習了 User-Agent 這種反爬蟲策略的原理,而且經過 Nginx 實現了反爬蟲,最後經過 Python 代碼示例和 Postman 示例來驗證咱們的想法,最終清清楚楚、明明白白的瞭解到其中的原因,待目標改變了它的策略時,咱們也能夠清楚的知道可使用哪些方法來繞過。

思考:示例中,我僅僅是使用 Python 編寫爬蟲來演示,那麼 Java 寫的爬蟲呢?PHP 編寫的爬蟲呢?安卓端發起的請求呢?

你能夠依次測試,結果確定讓你小有收穫。

若是你是一名爬蟲愛好者或者初級爬蟲工程師,同時你但願提高本身的水平,咱們能夠一塊兒交流,掃碼關注吧!

在微信公衆號回覆『反爬蟲報告』便可得到下面這個反爬蟲結果報告文檔(PDF)

它會讓你看起來更專業

報告部分截圖:

報告的結構以下所示:

相關文章
相關標籤/搜索