python网络爬虫实战-字體反爬

大家好,我是python网络爬虫这门课程的主要讲师geo

字體反爬(Font Anti-Scraping)是一種比較常見的反爬蟲技術,主要目的是阻止爬蟲直接提取網頁上的文字內容,特別是用於顯示重要數據(如價格、評論、電話號碼)時。

什麼是字體反爬?

簡單來說,網站開發者不使用標準的字體來顯示某些文字,而是使用自定義的 Web 字體

當你用瀏覽器訪問網頁時,瀏覽器會下載這個字體文件(通常是 .woff.woff2.ttf 格式),然後根據這個文件來正確地顯示文字。

但在 HTML 原始碼中,你看到的可能不是正常的文字,而是一串亂碼特殊編碼,例如:

  • HTML 原始碼: <span class="price">&#xe02a;&#xe02b;</span>
  • 瀏覽器顯示: 12

這是因為在網站的自定義字體文件中,編碼 &#xe02a; 映射到的是數字 1 的圖形,而 &#xe02b; 映射到的是數字 2 的圖形。爬蟲如果只解析 HTML 原始碼,就只能拿到一堆無法理解的編碼,無法得到真正的數字。


如何用 Python 破解字體反爬?

破解字體反爬的核心思路是還原編碼和字符的映射關係。這通常需要三個步驟:

步驟 1:找到並下載字體文件

使用瀏覽器的開發者工具(F12),切換到「Network」(網路)標籤,重新載入網頁。在列表中尋找副檔名為 .woff.woff2.ttf 的文件。這些文件通常很小,並且可能被 CSS 文件引用。下載這個字體文件。

步驟 2:解析字體文件,建立映射表

在 Python 中,我們可以使用 fontTools 這個強大的庫來解析字體文件。這個庫能夠讀取字體文件內部結構,特別是 cmap (Character to Glyph Mapping) 表,這個表記錄了編碼與字形之間的對應關係。

from fontTools.ttLib import TTFont

# 加載你下載的字體文件
font = TTFont('my_custom_font.woff')

# 獲取字體中的 cmap 表
# 通常 bestCmap() 能找到最合適的映射表
cmap = font.getBestCmap()

# 打印 cmap 表內容,你會看到類似 {編碼: 字形名稱} 的字典
print(cmap)

這一步會得到一個字典,例如:{57386: 'glyph00001', 57387: 'glyph00002', ...},其中 57386 就是 &#xe02a; 的十進位表示。

步驟 3:建立正確的映射字典並替換

光有編碼和字形的對應關係還不夠,我們還需要知道每個字形究竟代表什麼字符(例如 glyph00001 到底代表 1 還是 A)。

有兩種方法來建立最終的映射字典:

  1. 手動建立: 觀察網頁上顯示的正常文字和原始碼中的亂碼,手動建立一個映射字典。例如,如果 &#xe02a; 在網頁上顯示為 1,那麼字典就是 {'&#xe02a;': '1'}
  2. 自動識別: 對於簡單的數字反爬,可以把所有字形渲染出來,然後用 OCR(光學字符識別)來識別每個字形代表的數字,但這比較複雜。更常見的做法是,字形名稱本身可能帶有提示,比如 uniE02A,可以從中提取出編碼。
# 假設你已經建立好了從原始碼編碼到正確字符的映射
mapping = {
    '&#xe02a;': '1',
    '&#xe02b;': '2',
    '&#xe02c;': '3',
    # ... 其他映射
}

# 抓取到的原始 HTML 文本
scrambled_text = "商品價格為 &#xe02a;&#xe02b; 元"

# 遍歷映射字典,進行替換
for scrambled_char, correct_char in mapping.items():
    scrambled_text = scrambled_text.replace(scrambled_char, correct_char)

print(f"解析後的文本:{scrambled_text}")
# 輸出:解析後的文本:商品價格為 12 元

字體反爬的本質是數據混淆,它將可見的字符和原始數據分離。應對它的關鍵是找到並解析字體文件,還原這個被網站「打亂」的映射關係,然後才能正確地提取數據。這比直接提取 HTML 原始碼要複雜得多,但對於有規律的反爬來說是有效的解決方案。