偶然間知道到了字體反爬這個東西, 所以決定瞭解一下. 目標: https://maoyan.com/board/1 問題: 類似下圖中的票房數字無法獲取, 直接複製粘貼的話會顯示 □ 等無法識別的字元, 且網頁源碼中該類數字均被 .&# ...
偶然間知道到了字體反爬這個東西, 所以決定瞭解一下.
目標: https://maoyan.com/board/1
問題: 類似下圖中的票房數字無法獲取, 直接複製粘貼的話會顯示 □ 等無法識別的字元, 且網頁源碼中該類數字均被 . 之類的字元串代替.
解決:
出現這種情況的原因是因為網頁字體是在 CSS3 @font-face 規則中定義的, 我覺得這種字體就類似描點連線那種方式繪製出來的.
因為定義規則是動態隨機獲取的, 不能保證每次都是一個字體文件.
如下:
可以看到, 同一數字所對應的字元是不一樣的, 所以我們也就動態下載實時字體文件, 具體分析.
雖然每次對應的字元可能不一樣, 但是可以發現同一數字的字形是一樣的, 也就是"描點的坐標"應該相同.
事實證明在這個例子中是確實如此.
如下:
同一數字對象里的這些值是一樣的.
既然找到問題所在和規律了, 就可以直接開始寫代碼了.
1 import re 2 from urllib.request import urlretrieve, urlopen 3 from fontTools.ttLib import TTFont 4 5 6 def process_font(url): 7 # loc.woff是事先下載好的字體文件 8 # 可以通過font1.saveXML()來瞭解文件的結構, font1就像一個的字典, XML文件里的tag可以對font1用字典的方法獲取 9 font1 = TTFont('loc.woff') 10 # 使用百度的FontEditor手動確認本地字體文件name和數字之間的對應關係, 保存到字典中 11 loc_dict = {'uniE8B2': '5', 'uniF818': '3', 'uniECCC': '8', 'uniE622': '1', 'uniEC92': '2', 'uniF31A': '4', 12 'uniE86D': '9', 'uniE33C': '6', 'uniE1FA': '7', 'uniE13E': '0'} 13 # 獲取字元的name列表, 列印出來後發現第一個和最後一個name所對應的不是數字, 所以切片 14 uni_list1 = font1.getGlyphNames()[1: -1] 15 16 # 網頁源碼 17 rsp = urlopen(url).read().decode() 18 # 獲取動態的字體文件並下載 19 font_url = 'http://' + re.findall(r'url\(\'//(.*?\.woff)', rsp)[0] 20 # web字體文件落地名 21 filename = font_url.split('/')[-1] 22 # 下載web字體文件 23 urlretrieve(font_url, filename) 24 25 # 打開web字體文件 26 font2 = TTFont(filename) 27 # 獲取字元的name列表 28 uni_list2 = font2.getGlyphNames()[1: -1] 29 30 # web字體文件中name和num映射 31 new_map = {} 32 33 for uni2 in uni_list2: 34 # 獲取name 'uni2' 在font2中對應的對象 35 obj2 = font2['glyf'][uni2] 36 for uni1 in uni_list1: 37 # 獲取name 'uni1' 在font1中對應的對象 38 obj1 = font1['glyf'][uni1] 39 # 如果兩個對象相等, 說明對應的數字一樣 40 if obj1 == obj2: 41 # 將name鍵num值對加入new_map 42 new_map[uni2] = loc_dict[uni1] 43 44 # 將數字替換至源碼 45 for i in uni_list2: 46 pattern = '&#x' + i[3:].lower() + ';' 47 rsp = re.sub(pattern, new_map[i], rsp) 48 49 # 返回處理處理後的源碼 50 return rsp 51 52 53 if __name__ == '__main__': 54 # 貓眼國內實時票房top10 55 url = 'https://maoyan.com/board/1' 56 # 替換數字後的網頁源碼 57 res = process_font(url)
代碼里loc.woff文件是先下載好的, 通過它找到數字和"描點坐標"之間的對應關係. 這個文件大家可以自己提前下載, 並且手動找到對應關係.
這裡也提供了我下載的loc.woff文件, https://github.com/ysl125963/maoyan, 裡面的font.xml文件就是通過saveXML()方法得到的, 可以看到字體文件的具體結構.
這是第一次寫分享博客, 而且github也沒怎麼用過, 希望以後能堅持吧.