背景交代
在反爬圈子的一個大類,涉及的網站其實蠻多的,目前比較常被爬蟲coder欺負的網站,貓眼影視,汽車之家,大衆點評,58同城,天眼查......還是蠻多的,技術高手千千萬,總有五花八門的反爬技術出現,對于爬蟲coder來說,幹!就完了,反正也996了~
作為一個系列的文章,那免不了,依舊拿貓眼影視“學習”吧,為什麼?因為它比較典型~
貓眼影視
打開貓眼專業版,正常操作,谷歌浏覽器,開發者工具,抓取DOM節點,
https://piaofang.maoyan.com/?ver=normal
注意下圖所有的數字位置,在DOM結構中,都是方塊。

字型反爬掃盲
字型反爬,是一種常見的反爬技術,網站采用了自定義的字型檔案,在浏覽器上正常顯示,但是爬蟲抓取下來的資料要麼就是亂碼,要麼就是變成其他字元。采用自定義字型檔案是CSS3的新特性,熟悉前端的同學可能知道,就是
font-face屬性
。
一些重要破解素材的收集
找到
font-family
屬性,檢視設定的内容,發現是cs字型,這明顯是自定義字型了,在網頁中檢索
cs
在頁面的HTML源碼中找到了字型的定義
注意檔案的開頭是base64 表示檔案進行過base64編碼,需要進行解碼,然後在儲存成ttf字型檔案
上述截圖中有個woff格式
Web開放字型格式(Web Open Font Format,簡稱WOFF) 是一種網頁所采用的字型格式标準。此字型格式發展于2009年,現在正由網際網路聯盟的Web字型工作小組标準化,以求成為推薦标準。此字型格式不但能夠有效利用壓縮來減少檔案大小,并且不包含加密也不受DRM(數位著作權管理)限制。
解碼操作
import base64
font_face = "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"
print(len(font_face))
b = base64.b64decode(font_face)
with open('font.ttf','wb') as f:
f.write(b)
對于ttf檔案的處理,有3種方式,第一種使用
軟體 FontCreator
可以直接打開ttf檔案,第二種使用Python第三方庫
fontTools
,借用這個庫也可以操作ttf檔案,第三種使用百度的fontstore,
http://fontstore.baidu.com/static/editor/index.htmlFontCreator 軟體查找這個就比較簡單了
你可以自行百度尋找,也可以直接打開我的百度網盤下載下傳
連結: https://pan.baidu.com/s/1ZyWwk37hNeo0vIsTqdK2fg 提取碼: kk2h
安裝完畢,直接試用即可,也可以采用國家支援的和諧方法,進行和諧
查閱一下sources裡面的html編碼
數字進行比對
順便把這個地方的編碼對應關系記錄一下,友善後續操作
'uniE481': '7',
'uniE0AA': '4',
'uniF71E': '9',
'uniE767': '1',
'uniE031': '5',
'uniE4BD': '2',
'uniF2AA': '3',
'uniE2E3': '6',
'uniE3C9': '8',
'uniEA65': '0'
數字比對完全沒有問題3.69億
開始編碼破解字型反爬
有的網頁嵌套了多套字型,增加了反爬的成本,屆時自行研究即可
利用fontTools可以擷取每一個字元對象,這個對象你可以簡單的了解為儲存着這個字元的形狀資訊。
而且編碼可以作為這個對象的id,具有一一對應的關系。
類似貓眼電影,多套字型對應的字元的編碼是變化的,但是字元的形狀是不變的,也就是說這個對象是不變的。
通過fontTools進行解析字庫檔案
安裝fonttools
pip install fonttools
fontTools庫詳解:
https://darknode.in/font/font-tools-guide/基本使用
from fontTools.ttLib import TTFont
font = TTFont('font.ttf')
font.saveXML('01.xml')
打開 xml 檔案
開頭顯示的是全部編碼,注意這裡的ID是編号,千萬不要當成對應的數字
下面對應的是字型資訊,計算機隻需要知道黑白像素點即可
注意事項,寫代碼的時候需要注意一下
關于貓眼的字型反爬做個總結
在實操中,你會發現貓眼電影,每次重新整理字元編碼都是變化的,但是字型的對象,也就是像素點是一緻的。
你可以通過第一次下載下傳一個字型檔案
base_font.ttf
,并把對應編碼的記下來,當第二次重新整理頁面之後,重新抓取字型檔案
online_font.ttf
,對比兩個字型檔案中的對象資訊,如果對象是一樣的,那麼就可以知道對應的數字了。
首次擷取字型檔案
# 本地已經下載下傳好的字型處理
base_font = TTFont('font.ttf') #打開本地的ttf檔案
base_uni_list = base_font.getGlyphOrder()[2:] # 擷取所有編碼,去除前2個,可檢視前文圖示
# 寫出第一次字型檔案的編碼和對應字型
origin_dict = {'uniE481': '7', 'uniE0AA': '4', 'uniF71E': '9', 'uniE767': '1', 'uniE031': '5', 'uniE4BD': '2','uniF2AA': '3', 'uniE2E3': '6', 'uniE3C9': '8', 'uniEA65': '0'}
擷取線上字型
# 擷取重新整理之後線上的字型
# 擷取字型檔案的base64編碼
online_ttf_base64 = re.findall(r"base64,(.*)\) format", response)[0]
online_base64_info = base64.b64decode(online_ttf_base64)
with open('online_font.ttf', 'wb')as f:
f.write(online_base64_info)
online_font = TTFont('online_font.ttf') # 網上動态下載下傳的字型檔案。
online_uni_list = online_font.getGlyphOrder()[2:]
for uni2 in online_uni_list:
obj2 = online_font['glyf'][uni2] # 擷取編碼uni2在online_font.ttf中對應的對象
for uni1 in base_uni_list:
obj1 = base_font['glyf'][uni1] # 擷取編碼uni1在base_font.ttf 中對應的對象
if obj1 == obj2: # 判斷兩個對象是否相等
dd = "&#x" + uni2[3:].lower() + ';' # 修改為Unicode編碼格式
if dd in response: # 如果編碼uni2的Unicode編碼格式 在response中,替換成origin_dict中的數字。
response = response.replace(dd, origin_dict[uni1])
response的擷取采用的是request子產品
url = 'https://piaofang.maoyan.com/?ver=normal'
headers = {
'User-Agent': '浏覽器UA',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
}
response = requests.get(url=url, headers=headers).content # 得到位元組
charset = chardet.detect(response).get('encoding') # 得到編碼格式
response = response.decode(charset, "ignore") # 解碼得到字元串
運作結果展示
關注微信公衆賬号:非大學程式員,回複0409擷取下載下傳位址