大廠在用的Python反爬蟲手段,破了它!

来源:https://www.cnblogs.com/7758520lzy/archive/2020/04/02/12622448.html
-Advertisement-
Play Games

SVG 映射反爬蟲 SVG 是用於描述二維矢量圖形的一種圖形格式。它基於 XML 描述圖形,對圖形進行放大或縮小操作都不會影響圖形質量。矢量圖形的這個特點使得它被廣泛應用在 Web 網站中。 接下來我們要瞭解的反爬蟲手段正是利用 SVG 實現的,這種反爬蟲手段用矢量圖形代替具體的文字,不會影響用戶正 ...


SVG 映射反爬蟲

SVG 是用於描述二維矢量圖形的一種圖形格式。它基於 XML 描述圖形,對圖形進行放大或縮小操作都不會影響圖形質量。矢量圖形的這個特點使得它被廣泛應用在 Web 網站中。

接下來我們要瞭解的反爬蟲手段正是利用 SVG 實現的,這種反爬蟲手段用矢量圖形代替具體的文字,不會影響用戶正常閱讀,但爬蟲程式卻無法像讀取文字那樣獲得 SVG 圖形中的內容。由於 SVG 中的圖形代表的也是一個個文字,所以在使用時必須在後端或前端將真實的文字與對應的 SVG 圖形進行映射和替換,這種反爬蟲手段被稱為 SVG 映射反爬蟲。

6.3.1 SVG 映射反爬蟲繞過實戰

示例 6:SVG 映射反爬蟲示例。

網址:http://www.porters.vip/confusion/food.html

任務:爬取美食商家評價網站頁面中的商家聯繫電話、店鋪地址和評分數據,頁面內容如圖 6-15

所示。

圖 6-15 示例 6 頁面

在編寫 Python 代碼之前,我們需要確定目標數據的元素定位。在定位過程中,發現一個與以往不同的現象:有些數字在 HTML 代碼中並不存在。例如口味的評分數據,其元素定位如圖 6-16 所示。

圖 6-16 評分數據中口味分數元素定位

根據頁面顯示內容,HTML 代碼中應該是 8.7 才對,但實際上我們看到的卻是:

   
1 <span class="item">口味:<d class="vhkjj4"></d>.7</span>

HTML 代碼中有數字 7 和小數點,但沒有 8 這個數字,似乎數字 8 的位置被 d 標簽占據。而商家電話號碼處的顯示就更奇怪了,一個數字都沒有。商家電話對應的 HTML 代碼如下:

   
1 2 3 4 5 6 7 8 9 10 11 12 <div class="col more">         電話:    <d class="vhkbvu"></d>    <d class="vhk08k"></d>    <d class="vhk08k"></d>    <d class="">-</d>    <d class="vhk84t"></d>    <d class="vhk6zl"></d>    <d class="vhkqsc"></d>    <d class="vhkqsc"></d>    <d class="vhk6zl"></d> </div>

包含很多的 d 標簽,難道它使用 d 標簽進行占位,然後用元素進行覆蓋嗎?我們可以將 d 標簽的數量和數字的數量進行對比,發現它們的數量是相同的,也就是說一對 d 標簽代表一個數字。

每一對 d 標簽都有 class 屬性,有些 class 屬性值是相同的,有些則不同。我們再將 class 屬性值與數字進行對比,看一看能否找到規律,如圖 6-17 所示。

圖 6-17 class 屬性值和數字的對比

從圖 6-17 中可以看出,class 屬性值和數字是一一對應的,如屬性值 vhk08k 與數字 0 對應。根據這個線索,我們可以猜測每個數字都與一個屬性值對應,對應關係如圖 6-18 所示。

圖 6-18 數字與屬性值對應關係

瀏覽器在渲染頁面的時候就會按照這個對應關係進行映射,所以頁面中顯示的是數字,而我們在 HTML 代碼中看到的則是這些 class 屬性值。瀏覽器在渲染時將 HTML 中的 d 標簽與數字按照此關係進行映射,並將映射結果呈現在頁面中。映射邏輯如圖 6-19 所示。

圖 6-19 映射邏輯

我們的爬蟲代碼可以按照同樣的邏輯實現映射功能,在解析 HTML 代碼時將 d 標簽的 class 屬性值取出來,然後進行映射即可得到頁面中顯示的數字。如何在爬蟲代碼中實現映射關係呢?實際上網頁中使用的是“屬性名數字”這種結構,Python 中內置的字典正好可以滿足我們的需求。我們可以用 Python 代碼測試一下,代碼如下:

   
1 2 3 4 5 6 7 8 9 # 定義映射關係 mappings = {'vhk08k': 0, 'vhk6zl': 1, 'vhk9or': 2,    'vhkfln': 3, 'vhkbvu': 4, 'vhk84t': 5,    'vhkvxd': 6, 'vhkqsc': 7, 'vhkjj4': 8,    'vhk0f1': 9} # HTML 中得到的屬性值 html_d_class = 'vhkvxd' # 將映射後的結果列印輸出 print(mappings.get(html_d_class))

這段代碼的邏輯是:首先定義屬性值與數字的映射關係,然後假設一個 HTML 中 d 標簽的屬性值,接著將這個屬性值的映射結果列印出來。代碼運行後得到的結果為:

   
1 6

運行結果說明映射這種方法是可行的。接著我們試一試將商家的聯繫電話映射出來:

   
1 2 3 4 5 6 7 8 9 10 11 12 13 # 定義映射關係 mappings = {'vhk08k': 0, 'vhk6zl': 1, 'vhk9or': 2,             'vhkfln': 3, 'vhkbvu': 4, 'vhk84t': 5,             'vhkvxd': 6, 'vhkqsc': 7, 'vhkjj4': 8,             'vhk0f1': 9} # 商家聯繫電話 class 屬性 html_d_class = ['vhkbvu', 'vhk08k', 'vhk08k',                 '', 'vhk84t', 'vhk6zl',                 'vhkqsc', 'vhkqsc', 'vhk6zl']   phone = [mappings.get(i) for i in html_d_class] # 將映射後的結果列印輸出 print(phone)

運行結果為:

   
1 [4, 0, 0, None, 5, 1, 7, 7, 1]

我們使用映射的方法得到了商家聯繫電話,說明 SVG 映射反爬蟲已經被我們繞過了。

6.3.2 大眾點評反爬蟲案例

這種映射手段不僅僅出現在本書的示例中,在大型網站中也有應用。大眾點評是中國領先的本地生活信息及交易平臺,也是全球最早建立的獨立第三方消費點評網站。大眾點評不僅為用戶提供商戶信息、消費點評及消費優惠等信息服務,同時提供團購、餐廳預訂、外賣和電子會員卡等 O2O(Online To Offline)交易服務。大眾點評網站也使用了映射型反爬蟲手段,打開瀏覽器並訪問 https://www.dianping.com/shop/14741057,頁面如圖 6-20 所示。

圖 6-20 大眾點評商家信息頁

大眾點評的商家信息頁主要用於展示消費者對商家的各項評分、商家電話、店鋪地址和推薦菜品等。我們可以看一看商家電話或評分的 HTML 代碼,如圖 6-21 所示。

圖 6-21 商家電話 HTML 代碼

大眾點評中的商家號碼並不是全部使用 d 標簽代替,其中有部分使用了數字。但是仔細觀察一下就可以發現商家號碼的數量等於 d 標簽數量加上數字的數量,說明 d 標簽的 class 屬性值與數字也有可能是一一對應的映射關係。感興趣的同學可以使用示例 6 中的方法,嘗試映射大眾點評案例中的數字。

如果這種手段的繞過方法這麼簡單的話,那麼它早就被淘汰了,為什麼連大眾點評這樣的大型網站都會使用呢?我們繼續往下看,大眾點評的商家營業時間部分的 HTML 代碼如圖 6-22 所示。

圖 6-22 大眾點評商家營業時間

除了剛纔的數字映射之外,大眾點評還對中文進行了映射。此時如果按照示例 6 中人為地將 class 值和對應的文字進行映射的話,就非常麻煩了。試想一下,如果網頁中所有的文字都使用這種映射反爬蟲的手段,那麼爬蟲工程師要如何應對呢?對所有用到的文字進行映射嗎?

這不可能做到,其中要完成映射的包括 10 個數字、26 個英文字母和幾千個常用漢字。而且目標網站一旦更改文字的對應關係,那麼爬蟲工程師就需要重新映射所有文字。面對這樣的問題,我們必須找到文字映射規律,並且能夠使用 Python 語言實現映射演算法。如此一來,無論目標網站文字映射的對應關係如何變化,我們都能夠使用這套映射演算法得到正確的結果。

這種映射關係在網頁中是如何實現的呢?是使用 JavaScript 在頁面中定義數組嗎?還是非同步請求API 拿到 JSON 數據?這都有可能,接下來我們就去尋找答案。

6.3.3 SVG 反爬蟲原理

映射關係不可能憑空出現,一定使用了某種技術特性。HTML 中與標簽 class 屬性相關的只有 JavaScript 和 CSS。根據這個線索,我們需要繼續對示例 6 進行分析。案例中商家電話的 HTML 代碼為:

   
1 2 3 4 5 6 7 8 9 10 11 <div class="col more">電話:    <d class="vhkbvu"></d>    <d class="vhk08k"></d>    <d class="vhk08k"></d>    <d class="">-</d>    <d class="vhk84t"></d>    <d class="vhk6zl"></d>    <d class="vhkqsc"></d>    <d class="vhkqsc"></d>    <d class="vhk6zl"></d> </div>

我們可以隨意選擇一對 d 標簽,然後觀察它對應的 CSS 樣式有沒有可以深入分析的線索,如果沒有線索再看 JavaScript。 d 標簽的 CSS 樣式如下:

   
1 2 3 4 5 6 7 8 9 10 11 12 13 d[class^="vhk"] {    width: 14px;    height: 30px;    margin-top: -9px;    background-image: url(../font/food.svg);    background-repeat: no-repeat;    display: inline-block;    vertical-align: middle;    margin-left: -6px; } .vhkqsc {     background: -288.0px -141.0px; }

d 標簽樣式看上去沒有什麼特別之處,只是設置了 background 屬性的坐標值。但是上方 d 標簽的公共樣式中設置了背景圖片,我們可以複製背景圖片的地址,在瀏覽器的新標簽頁中打開,d 標簽背景圖如圖 6-23 所示。

圖 6-23 標簽背景圖

d 標簽的背景圖中全部都是數字,這些無序的數字共有 4 行。但這好像不是一張大圖片,我們查看該圖片頁面的源代碼,內容如圖 6-24 所示。

圖 6-24 圖片頁面源代碼

源代碼中前兩行表明這是一個 SVG 文件,該文件中使用 text 標簽定義文本, style 標簽用於設置文本樣式, text 標簽定義的文本正是圖片頁面顯示的數字。難道這些無序的數字就是我們在頁面中看到的電話號碼和評分數字?

除了 class 屬性值為 vhkbvu 的 d 標簽,其他標簽也使用了這個的 CSS 樣式,但每對 d 標簽的坐標定位都不同。它們的坐標定位如下:

   
1 2 3 4 5 6 7 8 9 .vhkbvu {     background: -386px -97px; } .vhk08k {     background: -274px -141px; } .vhk84t {     background: -176px -141px; }

坐標是定位數字的關鍵,要想知道坐標的計算方法,必須瞭解一些關於 SVG 的知識。

在本節開始的時候,我們簡單地瞭解了 SVG 的概念,知道 SVG 是基於 XML 的。實際上它是用文本格式的描述性語言來描述圖像內容的,因此 SVG 是一種與圖像解析度無關的矢量圖形格式。打開文本編輯器,併在新建的文件中寫入以下內容:

   
1 2 3 4 5 6 7 <?xml version="1.0" encoding="UTF-8" standalone="no"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/ DTD/svg11.dtd"> <svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/ 1999/xlink" width="250px" height="250.0px">     <text x='10' y='30'>hello,world</text> </svg>

將該文件保存為 test.svg,然後使用瀏覽器打開 test.svg 文件,顯示內容如圖 6-25 所示。

圖 6-25 test.svg 顯示內容

代碼前 3 行聲明文件類型,第 4 行~第 5 行定義了 SVG 內容塊和畫布寬高,第 6 行使用 text 標簽定義了一段文本並指定了文本的坐標。這段文本就是我們在瀏覽器中看到的內容,而代碼中的 x 坐標和 y 坐標則用於確定該文本在畫布中的位置,坐標規則如下。

  • 以頁面的左上角為零坐標點,即坐標值為 (0, 0)。
  • 坐標以像素為單位。
  • x 軸的正方向為從左到右,y 軸的正方向是從上到下。
  • n 個字元可以有 n 個位置參數。

如果字元數量大於位置參數數量,那麼沒有位置參數的字元將以最後一個位置參數為零坐標點,並按原文順序排列。

看上去並不是很好理解,我們可以通過修改代碼來理解坐標軸的定義。首先是 x 軸, text 標簽中的 x 代表列表字元在頁面中的 x 軸位置,test.svg 中的 x 值為 10,現在我們將其設為 0 ,保存後刷新網頁,頁面內容如圖 6-26 所示。

圖 6-26 x 為 0 時的 test.svg 顯示內容

x 的值為 0 時,文本緊貼瀏覽器左側。而 x 的值為 10 時,文本距離瀏覽器左側有一定的距離,這說明 x 的值能夠決定文字所在的位置。現在我們將代碼中 x 對應的值改為“10 50 30 40 20 60”(註意這裡特意將第 2個數字 20與第 5個數字互換了位置),這樣做是為了設定前 6個字元的坐標位置。

此時,第 1 個字元的位置參數為 10,第 2 個字元的位置參數為 50,第 3 個字元的位置參數為 30,以此類推,頁面中正常顯示的文字順序應該是:

   
1 holle,world

但是由於我們調換了第 2 個字元和第 5 個字元的位置參數,即字母 e 和字母 o 的位置互換,如圖 6-27

所示。

圖 6-27 設定多個 x 值的 svg

圖 6-27 中文字順序與我們猜測的順序是一樣的,這說明 SVG 中每個字元都可以有自己的 x 軸坐標值。y 與 x 同理,每個字元都可以有自己的 y 軸坐標值。雖然我們只設定了 6 個位置參數, svg 中的字元卻有 11 個,但沒有設定位置參數的字元依然能夠按照原文順序排序。在瞭解 SVG 基本知識之後,我們回頭看一下案例中所使用的 SVG 文件中坐標參數的設定,圖 6-23 中的字元與圖 6-24 圖片頁源代碼中的字元一一對應,且每個字元都設定了 x 軸的位置參數,而 y 軸則只有 1 個值。

在瞭解位置參數之後,我們還需要弄清楚字元定位的問題。瀏覽器根據 CSS 樣式中設定的坐標和元素寬高來確定 SVG 中對應數字。x 軸的正方向為從左到右,y 軸的正方向是從上到下,如圖 6-28 所示。

圖 6-28 SVG x 軸和 y 軸與位置參數的關係

而 CSS 樣式中的 x 軸與 y 軸是相反的,也就是說 CSS 樣式中 x 軸是負數向右的,y 軸是負數向下的,如圖 6-29 所示。

圖 6-29 CSS x 軸和 y 軸與位置參數的關係

所以當我們需要在 CSS 中定位 SVG 中的字元位置時,需要用負數表示。我們可以通過一個例子來理解它們的關係,現在需要在 CSS 中定點陣圖 6-30 中第 1 行的第 1 個字元的中心點。

圖 6-30 SVG

假設字元大小為 14 px,那麼 SVG 的計算規則如下。

  • 字元在x軸中心點的計算規則為:字元大小除以2,再加字元的x軸起點位置參數,即14÷2+0 等於 7。
  • 字元在 y 軸中心點的計算規則為:y 軸高度減字元 y 軸起點減字元大小,其值除以 2 後加上字元 y 軸起點位置參數,最後再加上字元大小數值的一半,即(38−0−14)÷2+0+7 等於 19。

最後得到 SVG 的坐標為:

   
1 x='7' y='19'

CSS 樣式的 x 軸和 y 軸與 SVG 是相反的,所以 CSS 樣式中對該字元的定位為:

   
1 -7px -19px

這樣就能夠定位到指定字元的中心點了。但是如果要在 HTML 頁面中完整顯示該字元,那麼還需要為 HTML 中對應的標簽設置寬高樣式,如:

   
1 2 width: 14px; height: 30px;

在瞭解了 SVG 與 CSS 樣式的關聯關係後,我們就能夠根據 CSS 樣式映射出 SVG 中對應的字元。

在實際場景中,我們需要讓程式能夠自動處理 CSS 樣式和 SVG 的映射關係,而不是人為地完成這些

工作。以示例 6 中的 SVG 和 CSS 樣式為例,假如我們需要用 Python 代碼實現自動映射功能,首先我

們就需要拿到這兩個文件的 URL,如:

   
1 2 url_css = 'http://www.porters.vip/confusion/css/food.css' url_svg = 'http://www.porters.vip/confusion/font/food.svg'

還有需要映射的 HTML 標簽的 class 屬性值,如:

   
1 css_class_name = 'vhkbvu'

接下來使用 Requests 庫向 URL 發出請求,拿到文本內容。對應代碼如下:

   
1 2
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 用vector實現鄰接表 vector <int> G[100]; //表示有100個頂點的圖的鄰接表 G[u].push_back(v); //從頂點u 向頂點v 畫邊,即在相當於創建一個二維數組G[100][i] //搜索與頂點u 相鄰的頂點v for( int i = 0; i < G[u]. ...
  • 作者:劉超 轉自【劉超的通俗雲計算】 什麼是雲計算 早在十年前,市場上就出現了很多和雲計算相關的崗位,當時正是雲計算技術最火熱的時代,不管是BAT還是華為等企業都開始佈局雲計算,於是OpenStack研發、容器研發、底層開發等相關崗位相應地也越來越多,雖然這幾年大數據和AI的風頭已經完全壓過了雲計算 ...
  • 前言 文的文字及圖片來源於網路,僅供學習、交流使用,不具有任何商業用途,版權歸原作者所有,如有問題請及時聯繫我們以作處理。 作者:李嘉圖 PS:如有需要Python學習資料的小伙伴可以加點擊下方鏈接自行獲取http://t.cn/A6Zvjdun 起因 今天有個朋友家裡wifi密碼忘了,沒有能連上的 ...
  • JDBC 前言 在學習了SQL語句後,我們肯定會思考如何使用資料庫里的數據。這個時候,我們便要學習JDBC來將資料庫與JAVA結合在一塊。 正題 什麼是JDBC? Java資料庫連接,(Java Database Connectivity,簡稱JDBC)是Java語言中用來規範客戶端程式如何來訪問數 ...
  • 面向對象編程基礎 一、面向對象概念 1.1 什麼是面向過程 ​ 就是分析出解決問題所需要的步驟,然後用函數把這些步驟一步一步實現,使用的時候一個一個依次調用就可以了。 ​ 生活中的的例子舉例。 1.2 什麼是面向對象 ​ 面向對象是把構成問題事務分解成各個對象,建立對象的目的不是為了完成一個步驟,而 ...
  • 點點這個鏈接免費獲取:本人免費整理了Java高級資料,涵蓋了Java、Redis、MongoDB、MySQL、Zookeeper、Spring Cloud、Dubbo高併發分散式等教程,一共30G,需要自己領取。傳送門:https://mp.weixin.qq.com/s/osB-BOl6W-ZLT ...
  • 我是李福春,我在準備面試,今天的題目是: mysql的redolog和binlog有什麼區別? 答: 如下麵的表格, redolog vs binlog 然後我們擴展一下,因為日誌主要是記錄的修改日誌,分別加深分析一下: redolog redolog是innodb存儲引擎特有的物理日誌,記錄的是數 ...
  • redis 實現限速器的幾種方式。 GET + INCR + EXPIRE 先獲取 key 的當前值,如果沒有超出限制再執行 INCR 增1,如果 key 不存在,使用 redis 的事務初始化 key 和過期時間。 偽代碼: count = redis.GET(key) if redis retu ...
一周排行
    -Advertisement-
    Play Games
  • 基於.NET Framework 4.8 開發的深度學習模型部署測試平臺,提供了YOLO框架的主流系列模型,包括YOLOv8~v9,以及其系列下的Det、Seg、Pose、Obb、Cls等應用場景,同時支持圖像與視頻檢測。模型部署引擎使用的是OpenVINO™、TensorRT、ONNX runti... ...
  • 十年沉澱,重啟開發之路 十年前,我沉浸在開發的海洋中,每日與代碼為伍,與演算法共舞。那時的我,滿懷激情,對技術的追求近乎狂熱。然而,隨著歲月的流逝,生活的忙碌逐漸占據了我的大部分時間,讓我無暇顧及技術的沉澱與積累。 十年間,我經歷了職業生涯的起伏和變遷。從初出茅廬的菜鳥到逐漸嶄露頭角的開發者,我見證了 ...
  • C# 是一種簡單、現代、面向對象和類型安全的編程語言。.NET 是由 Microsoft 創建的開發平臺,平臺包含了語言規範、工具、運行,支持開發各種應用,如Web、移動、桌面等。.NET框架有多個實現,如.NET Framework、.NET Core(及後續的.NET 5+版本),以及社區版本M... ...
  • 前言 本文介紹瞭如何使用三菱提供的MX Component插件實現對三菱PLC軟元件數據的讀寫,記錄了使用電腦模擬,模擬PLC,直至完成測試的詳細流程,並重點介紹了在這個過程中的易錯點,供參考。 用到的軟體: 1. PLC開發編程環境GX Works2,GX Works2下載鏈接 https:// ...
  • 前言 整理這個官方翻譯的系列,原因是網上大部分的 tomcat 版本比較舊,此版本為 v11 最新的版本。 開源項目 從零手寫實現 tomcat minicat 別稱【嗅虎】心有猛虎,輕嗅薔薇。 系列文章 web server apache tomcat11-01-官方文檔入門介紹 web serv ...
  • 1、jQuery介紹 jQuery是什麼 jQuery是一個快速、簡潔的JavaScript框架,是繼Prototype之後又一個優秀的JavaScript代碼庫(或JavaScript框架)。jQuery設計的宗旨是“write Less,Do More”,即倡導寫更少的代碼,做更多的事情。它封裝 ...
  • 前言 之前的文章把js引擎(aardio封裝庫) 微軟開源的js引擎(ChakraCore))寫好了,這篇文章整點js代碼來測一下bug。測試網站:https://fanyi.youdao.com/index.html#/ 逆向思路 逆向思路可以看有道翻譯js逆向(MD5加密,AES加密)附完整源碼 ...
  • 引言 現代的操作系統(Windows,Linux,Mac OS)等都可以同時打開多個軟體(任務),這些軟體在我們的感知上是同時運行的,例如我們可以一邊瀏覽網頁,一邊聽音樂。而CPU執行代碼同一時間只能執行一條,但即使我們的電腦是單核CPU也可以同時運行多個任務,如下圖所示,這是因為我們的 CPU 的 ...
  • 掌握使用Python進行文本英文統計的基本方法,並瞭解如何進一步優化和擴展這些方法,以應對更複雜的文本分析任務。 ...
  • 背景 Redis多數據源常見的場景: 分區數據處理:當數據量增長時,單個Redis實例可能無法處理所有的數據。通過使用多個Redis數據源,可以將數據分區存儲在不同的實例中,使得數據處理更加高效。 多租戶應用程式:對於多租戶應用程式,每個租戶可以擁有自己的Redis數據源,以確保數據隔離和安全性。 ...