ttf 文件反爬
想寫這篇文章的起源是在一個技術(shù)群里,有人討論去哪網(wǎng)(手機端)的反爬:請求下來的數(shù)字跟瀏覽器上的數(shù)字有規(guī)律的不同蛤售,查看字體文件之后烘豹, 發(fā)現(xiàn)字體文件中的數(shù)字位置顛倒了..., 后有朋友老冀爬取汽車之家精品貼也出現(xiàn)了類似的情況胆敞,不太清楚這種反爬的成本着帽, 但憑直覺將來這種反爬措施可能越來越普遍, 拿汽車之家為例竿秆, 遂記錄之启摄!源碼在最后!幽钢!
1. 開發(fā)者模式查看網(wǎng)頁內(nèi)容
2. 下載網(wǎng)頁源碼保存至本地查看
3. 通過fontTools進(jìn)行解析字庫文件
# 解析字體庫
font = TTFont('fonts.ttf')
# 讀取字體的映射關(guān)系
uni_list = font['cmap'].tables[0].ttFont.getGlyphOrder() # 參數(shù)'cmap' 表示漢字對應(yīng)的映射 為unicode編碼
print(uni_list)
打印的結(jié)果為:['.notdef', 'uniECD5', 'uniEC83', 'uniED37', 'uniECE5', 'uniED98', 'uniEC58', 'uniEDFA', 'uniECB9', 'uniED6D', 'uniED1B', 'uniEDCE', 'uniED7D', 'uniEC3C', 'uniECEF', 'uniEC9E', 'uniED51', 'uniEE04', 'uniEDB3', 'uniEC72', 'uniEC20', 'uniECD4', 'uniED87', 'uniED35', 'uniEDE9', 'uniECA8', 'uniEC56', 'uniED0A', 'uniECB8', 'uniED6B', 'uniEC2B', 'uniEDCD', 'uniEC8C', 'uniED40', 'uniECEE', 'uniEDA1', 'uniED4F', 'uniEE03', 'uniECC2']
需要注意的是:.notdef 并不是漢字的映射, 而是表示字體家族名稱匪燕。真是數(shù)據(jù)是從下標(biāo) 1 開始蕾羊。
fontTools庫詳解: https://darknode.in/font/font-tools-guide/
4. 將映射列表轉(zhuǎn)換成utf-8的類型
utf_list = [eval(r"u'\u" + x[3:] + "'") for x in uni_list[1:]]
5. 通過軟件查看字庫的對應(yīng)的映射關(guān)系 font creator
# 得到字符列表
word_list = [u'一', u'七', u'三', u'上', u'下', u'不', u'九', u'了', u'二', u'五', u'低', u'八', u'六',
u'十', u'的', u'著', u'近', u'遠(yuǎn)', u'長', u'右', u'呢', u'和', u'四', u'地', u'壞', u'多',
u'大', u'好', u'小', u'少', u'短', u'矮', u'高', u'左', u'很', u'得', u'是', u'更']
參考資料:
知乎作者謝俊杰的文章
fontTools庫詳解
github fonttools庫詳解
總注:汽車之家的字庫對應(yīng)的字形順序是不變的,只有映射的unicode的編碼在改變帽驯, 用這種方法是可以處理的龟再。 但應(yīng)對unicode編碼在變, 字形的順序也在改變尼变, 這種方法是無法解決的利凑。具體的處理辦法, 將在下一篇文中介紹嫌术。
本人水平有限哀澈, 如有錯誤歡迎提出指正!如有參考度气, 請注明出處8畎础!禁止抄襲磷籍,遇抄必肛J嗜佟!院领!
源碼:
# coding:utf-8
import re
import requests
from lxml import etree
from fontTools.ttLib import TTFont
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 "
"Safari/537.36 "
}
url = 'https://club.autohome.com.cn/bbs/thread/1d0784305887ec3f/72381110-1.html#pvareaid=102410'
# 請求內(nèi)容
response = requests.get(url, headers=headers)
response_html = response.content.decode('gbk')
# xpath 獲取帖子內(nèi)容
response_xml = etree.HTML(response_html)
content_list = response_xml.xpath('//div[@xname="content"]//div[@class="tz-paragraph"]//text()')
content_str = ''.join(content_list)
print(content_str)
# 獲取字體的連接文件
fonts_ = re.search(r",url\('(//.*\.ttf)?'\) format",response_html).group(1)
# 請求字體文件弛矛, 字體文件是動態(tài)更新的
fonts_url = 'https:'+fonts_
response = requests.get(fonts_url, headers=headers).content
# 講字體文件保存到本地
with open('fonts.ttf', 'wb') as f:
f.write(response)
# 解析字體庫
font = TTFont('fonts.ttf')
# 讀取字體的映射關(guān)系
uni_list = font['cmap'].tables[0].ttFont.getGlyphOrder()
# 轉(zhuǎn)換格式
utf_list = [eval(r"u'\u" + x[3:] + "'") for x in uni_list[1:]]
# 被替換的字體的列表
word_list = [u'一', u'七', u'三', u'上', u'下', u'不', u'九', u'了', u'二', u'五', u'低', u'八', u'六',
u'十', u'的', u'著', u'近', u'遠(yuǎn)', u'長', u'右', u'呢', u'和', u'四', u'地', u'壞', u'多',
u'大', u'好', u'小', u'少', u'短', u'矮', u'高', u'左', u'很', u'得', u'是', u'更']
#遍歷需要被替換的字符
for i in range(len(utf_list)):
content_str = content_str.replace(utf_list[i], word_list[i])
print (content_str)