web爬蟲學習(六)——CSS反爬加密徹底破解

筆者認爲,數據的價值不僅僅只體現在企業中,個人也可以體會到數據的魅力,用技術力量探索行爲密碼,讓大數據助跑每一個人,歡迎直筒們關注我的公衆號,大家一起討論數據中的那些有趣的事情。

我的公衆號爲:livandata

0 慣性嘚瑟

剛開始搞爬蟲的時候聽到有人說爬蟲是一場攻堅戰,聽的時候也沒感覺到特別,但是經過了一段時間的練習之後,深以爲然,每個網站不一樣,每次爬取都是重新開始,所以,爬之前誰都不敢說會有什麼結果。

前兩天,應幾個小朋友的邀請,動心思玩了一下大衆點評的數據爬蟲,早就聽說大衆點評的反爬方式不一般,貌似是難倒了一片英雄好漢,當然也成就了網上的一衆文章,專門講解如何爬取大衆點評的數據,筆者一邊閱讀這些文章尋找大衆點評的破解思路,一邊爲大衆點評的程序員小哥哥們鳴不平,辛辛苦苦寫好的加密方式,你們這些爬蟲寫手們這是鬧哪樣?破解也就算了,還發到網上去,還發這麼多~    

筆者在閱讀完這些文章之後,自信心瞬間爆棚,有如此多的老師,還有爬不了的網站,於是,筆者信誓旦旦的開始了爬大衆點評之旅,結果,一上手就被收拾了,各個大佬們給出的爬蟲方案中竟然有手動構建對照表的過程,拜託,如果我想手動,還要爬蟲做什麼?別說手動,半自動都不行。

大家看到這裏或許頭上有些霧水了,什麼手動?什麼半自動?還對照表?大佬,你這是什麼梗?再不解釋一些我就要棄劇了,葛優都拉不回來~

大家先不要着急,靜一靜~,對照表後面會講,這裏只需要知道我遇到困難了,就可以了,不過諮詢了幾個大佬之後,好在解決了,革命的路上雖有羈絆,終歸還是有同志的~

 好,現在開始入正題,點評的程序員哥哥請不要寄刀片:

1 基礎環節

 大衆點評的數據爬蟲開始還是很正常的,各個題目、菜單基本上都可以搞下來:

代碼如下:

#!/usr/bin/env python
 # _*_ UTF-8 _*_
 # 個人公衆號:livandata
 import requests
 from lxml import etree
 
 header = {"Accept":"application/json, text/javascript",
           "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
           "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36",
           "Cookie":"cy=1; cye=shanghai; _lxsdk_cuid=16ca41d3344c8-050eb4ac8f1741-4d045769-1fa400-16ca41d3345c8; _lxsdk=16ca41d3344c8-050eb4ac8f1741-4d045769-1fa400-16ca41d3345c8; _hc.v=38ae2e43-608f-1198-11ff-38a36dc160a4.1566121473; _lxsdk_s=16ce7f63e0d-91a-867-5a%7C%7C20; s_ViewType=10"
           }
 url = 'http://www.dianping.com/beijing/ch10/g34060o2'
 response = requests.get(url, headers=header)
 data = etree.HTML(response.text)
 title = data.xpath('//*[@id="shop-all-list"]/ul/li[1]/div[2]/div[1]/a/@title')
 print(title)

爬取的結果爲:

            

按照常規的套路,爬蟲可以說是寫成了。但是,現在的網站大多使用了反爬,一方面擔心自己的服務器會被爬蟲搞的超負荷,另一方面也爲了保護自己的數據不被其他人獲取。 

        

大衆點評就是衆多帶反爬的網站中的佼佼者,使用了比較高級的反爬手法,他們把頁面上的關鍵數字隱藏了起來,增加了爬蟲難度,不信~你看:

2 CSS加密

我們用如下字段爬取商店的評論數:

data = etree.HTML(response.text)
title = data.xpath('//*[@id="shop-all-list"]/ul/li[1]/div[2]/div[2]/a[1]/b/svgmtsi[1]/text()')
print(title)

結果得到的卻是如下字段:

 一看傻了,這是什麼鬼?

我們緊接着審查了網站數據,看到的內容卻是:

這是什麼鬼?評論數呢?

 

查看了網站的源代碼:

       發現原來顯示點評數的字段顯示成了:

       這是爲什麼呢?

       好在網上的大神們給出瞭解答,這就是CSS加密。

       接下來我們就介紹如何破解CSS加密:

       我們把源代碼上加密的部分取下來觀察一下:

     <svgmtsi>&#xf784;</svgmtsi>

       我們發現了網上一直在討論的svgmtsi標籤,這個標籤是矢量圖的標籤,基本上意思就是顯示在這裏的文字是一個矢量圖,解析這個矢量圖需要到另外一個地方找一個對照表,通過對照表將編碼內容翻譯成人類可以識別的數字。

       那麼,對照表在哪裏呢?

       我們先記錄下標籤中的class值:shopNum(爲什麼記錄,先不要着急,後面會講到),然後在源代碼中查找svg,我們發現瞭如下內容: 

大寶藏被挖掘了。

這好像是個鏈接,我們點擊一下,發現頁面跳轉到了一個全新的水月洞天:

這真是個偉大的發現,他預示着我們的爬蟲找到了門路,我們在這個頁面上查找剛纔class中的值shopNum,然後,我們看到了如下內容:   

url("//s3plus.meituan.net/v1/mss_73a511b8f91f43d0bdae92584ea6330b/font/bc2c52b3.woff");}

.shopNum{font-family: 'PingFangSC-Regular-shopNum';}@font-face{font-family:

"PingFangSC-Regular-reviewTag";

src:url("//s3plus.meituan.net/v1/mss_73a511b8f91f43d0bdae92584ea6330b/font/07758223.eot");

      在這段代碼中距離shopNum最近的地方,我們找到一個woff文件。

      你沒有猜錯,這個woff文件就是我們的對照表。

      同樣的思路,這是一個網址,我們可以把他下載下來,把這個網址複製到瀏覽器的地址欄中,點回車,會跳出如下快樂的界面。

       下載完成後,我們在瀏覽器中打開woff的翻譯工具:

        http://fontstore.baidu.com/static/editor/index.html

       我們把&#xf784;前面的&#x去掉並替換成uni,後面的;去掉,得到字段爲:unif784。

        祕密揭曉了:

       是不是很眼熟?

       是不是很驚喜?

       是不是很意外?

       恭喜你,第一步成功了~

       這個編碼在woff文件中對應的值爲7。

       就是我們要找的親人~

3 woff文件處理

       事情到這裏其實就可以畫個句號了,因爲接下來的思路就變的非常簡單了,我們用上面的通用爬蟲下載下網站上所有編碼和對應的class值,然後根據class值找到對應的woff文件,再在woff文件中確定編碼對應的數字或漢字就可以。

      但是,當我們擴充這一思路的時候卻遇到了兩個問題:

1)如何讀取出woff文件中的數字,大衆點評有多個woff文件,怎麼對照讀取呢?難不成要一個個寫出來?根據前面網站裏的文章來講,對的,你猜的很準,這就是我文章一開始寫的半自動,崩潰了吧,好在筆者找到了新的方法,取代了半自動的問題,這個新的方法就是OCR識別,後面我會仔細講解。

2)頁面的編碼是變動的,你沒有看錯,&#xf784;這個值是會變的,好在這個事件沒有發生在大衆點評中,但是汽車之家、貓眼等網站使用的CSS加密會隨頁面的刷新發生變動,有沒有驚到你?

如果你只需要大衆點評,第二個問題幾乎可以不用考慮了,但是筆者認爲要做一個有理想的爬蟲,儘量多的獲取知識點纔是正確的,所以,筆者研究了汽車之家、貓眼、天眼等幾個用CSS加密的網站,找到了一個通用的方法,下面我們來介紹一下這個通用方法。

先看一下貓眼網站上編碼的動態效果:

如圖:

      我們先找到一個加密編碼,把他複製出來,看到的編碼如下:

      然後我們刷新一下頁面,再看源碼:

       不管你驚不驚,反正我是驚到了~

       針對這一變化,筆者心中產生了一個疑惑,如果說編碼會變,那瀏覽器是怎麼獲取到準確的值的呢?說明一定存在一個統一的方法供瀏覽器調用,於是,筆者重新研究了編碼的調用方式,驚奇的發現了其中的祕密:

       我們以如下兩個編碼來揭露這個今天大冪冪:

       &#xf0d5; -->unif0d5

       &#xe765;-->unie765

       這兩個字段都是表示數字中的1,那他們有什麼規律呢?

       我們首先解碼woff文件成xml格式:

from fontTools.ttLib import TTFont
 font = TTFont('e765.woff')
 font.saveXML('e765.xml')

      在pycharm中我們打開xml文件:

      找到unie765所在的位置:

       這一串代碼是字形座標,瀏覽器就是根據這個字形座標翻譯出我們能夠識別的漢字:1。

       同樣的思路,我們再去解析unif0d5的值,得到如下圖:


我們驚奇的發現,這兩個竟然一樣,是不是所有的值對應的字形座標都是唯一的呢,答案是肯定的,變化的只是上圖name中的編碼,座標與數字之間是一對一的,所以,我們的思路來了,我們只需要找到編碼所對應的字形座標,然後想辦法解析出這個字形座標所對應的數字就可以了。

4 完整思路

       問題展示基本上清楚了,我們接下來看一下怎麼自動化解決上面兩個問題:

       首先展示一下思路:


       這是在excel裏面畫的,大家可以只關注內容,忽略掉背景線。

       解釋一下上面的思路:

       首先:我們從頁面上獲取到文字編碼和woff文件,注意,這裏的字形編碼和woff文件一定要一起獲取,因爲每個編碼對應一個woff文件,一旦刷新頁面,編碼在woff文件中的對應關係就會變化,找不到對應的字形座標。

data = etree.HTML(response.text)
title = data.xpath('//*[@id="shop-all-list"]/ul/li[1]/div[2]/div[2]/a[1]/b/svgmtsi[1]/text()')
print(title)

       其次:我們把字形編碼轉化成uni開頭的編碼,並獲取到woff文件中的字形座標。

from fontTools.ttLib import TTFont
font = TTFont('f0d5.woff')
coordinate = font['glyf']['uniF0D5'].coordinates
print(coordinate)

       第三:用matplotlib解析這一座標,並保存成圖片。

#!/usr/bin/env python
 # _*_ UTF-8 _*_
 # 個人公衆號:livandata
from fontTools.ttLib import TTFont
import matplotlib.pyplot as plt
font = TTFont('f0d5.woff')
coordinate = font['glyf']['uniF0D5'].coordinates
coordinate = list(coordinate)
fig, ax = plt.subplots()
x = [i[0] for i in coordinate]
y = [i[1] for i in coordinate]
plt.fill(x, y, color="k", alpha=1)
# 取消邊框
for key, spine in ax.spines.items():
     if key == 'right' or key == 'top' or key == 'bottom' or key == 'left':
         spine.set_visible(False)
plt.plot(x, y)
# 取消座標:
plt.axis('off')
plt.savefig('uniF0D5.png')
plt.show()

       通過上面的解析,我們可以得到1的圖片:

      

       這個1好難看,不過好在解析出來了~

       第四:使用OCR解析這個數字:

# 圖片轉化成string:
try:
   from PIL import Image
except ImportError:
   import Image
import pytesseract
captcha = Image.open(r'uniF0D5.png')
print(captcha)
result = pytesseract.image_to_string(captcha, lang='eng', config='--psm 6 --oem 3 -c tessedit_char_whitelist=0123456789').strip()
print(result)

        自此,我們的文字就可以直接識別出來了,我們就再也不需要用半自動的小米加步槍了,我們可以直接使用衝鋒槍了

      不過需要注意的是使用OCR解碼文字需要一定的時間,耗時還是比較長的,如果經常使用這一思路,建議可以構建一個“字形座標:文字”的數據庫表,下次使用時解析出字形座標,直接到數據庫裏匹配對應的文字就可以了。

 

       介紹一篇OCR的文章吧,可以瞭解一下如何解析文字:

http://www.inimei.cn/archives/770.html

讚美時間

       每一位看到這篇文章的帥哥美女都是天上的星星,而且是最亮的一顆~   

       看都看到這裏了,加個關注再走唄~

       筆者堅持數據的力量,讓大數據賦能每個人~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章