其实字体加密不难,我刚开始接触字体加密的时候应该和大部分人一样感到脑壳疼,这无聊的开发,为啥要写这么难,在我写过几个网站的字体反爬后就感觉并没有那么难 ,感觉字体反爬都是一个套路,我们以58同城二手车来介绍,(还有汽车之家的论坛,起点中文网(比较简单),大众点评,自如)
1, 首先我们看他源码
汽车的价格被加密了,我们首先想的就是字体加密,
2.查找加密文件
可以看到字体文件被base64加密成一长串字符串了,我们用正则吧字符串取下来 用base64解码成woff文件,然后再转化为xml文件供我们观察
3.通过xml文件,我们可以看到字体都是坐标,都是画出来的,我们放到专门的软件吧文件画出来
可以看到就是0-9的数字,多请求几次进行对比,我们发现他有相同的 也有不同点
相同:都是0-9,同一个数字的自型是一样的,也就是坐标
不同:同一个数字代表他的name不同
4 破解
我们通过一个字体文件 得出映射关系 这个关系是 ,数字和字形的关系
然后每次请求获取的字体文件 解析出 name属性,和字形 通过字形和你设定好的关系进行对比 找到数字
再通过name 在源网页中进行替换
这是我根据一个字体文件得到的,hex是字形的md5加密后的值
到这差不多就结束了 ,其实大部分都是这种的 简单的咱就不说了,还有那种没有任何规律的就直接用ocr识别吧 (我发布的文章里面也有,如果有好办法要教教我哦)
全部代码如下(代码很丑,没整理,凑活吧)
import requests
import base64
import re
from fontTools.ttLib import TTFont
from lxml import etree
from hashlib import md5
url = 'https://bj.58.com/baoma/?listfrom=dspadvert&PGTID=0d3036e0-0000-1e16-19b4-92f3e56b847f&ClickID=100#mainCon'
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36'
}
ret = requests.get(url=url,headers=headers)
ret.encoding='utf8'
with open('58.html','w',encoding='utf8') as f:
f.write(ret.text)
with open('58.html','r',encoding='utf8') as f:
ret = f.read()
ba64 = re.findall('base64,(.*?)\'\) forma',ret)[0]
b= base64.b64decode(ba64)
with open('1.woff','wb') as f:
f.write(b)
#
# font_dict = {
#
# '-': 0,
# '时': 1,
# '%': 2,
# '/': 3,
# '万':4,
# '+':5,
# '¥':6,
# '元':7,
# '起':8,
# '折':9
# }
base_font={'font':[
{'name':'-','value':'3','hex':'f9d6f8bfb0257137ad304bcae1009022'},
{'name':'时','value':'0','hex':'79a6e23d10c68d14e4ec507e6b02bbf2'},
{'name':'%','value':'5','hex':'7125656f5dd35120031671deec325dbe'},
{'name':'/','value':'7','hex':'927faa2e53d85d841839ec58daddb138'},
{'name':'万','value':'8','hex':'73b0b18ef35ebe5df363bccf4ea5e356'},
{'name':'+','value':'2','hex':'6d6f25ae791948b9b1b6538c4fd5a09b'},
{'name':'¥','value':'1','hex':'f3980be01c0bf2e821672497b680f59d'},
{'name':'元','value':'6','hex':'7c26f89c45f85da47fdb94e6edec97b7'},
{'name':'起','value':'4','hex':'e32ccaa22e9bfc82e927c8c4c5c7487e'},
{'name':'折','value':'9','hex':'415e4dc11caaf995d552a41238fed31d'},
]}
# font = TTFont('1.woff')
# # font.saveXML('1.xml')
# for i in font_dict:
# print('uni'+i[3:-1].zfill(4).upper())
# font_cmap = font['glyf'].glyphs.get('uni'+i[3:-1].zfill(4).upper()).data
# glpyh = md5(font_cmap).hexdigest()
# print(i,glpyh)
#.getBestCmap()
fot = {
'uni002D':'-',
'uni65F6':'时',
'uni0025':'%',
'uni002F':'/',
'uni4E07':'万',
'uni002B':'+',
'uni00A5':'¥',
'uni5143':'元',
'uni8D77':'起',
'uni6298':'折',
}
dic = {}
font = TTFont('1.woff')
font.saveXML('1.xml')
font_cmap = font['cmap'].getBestCmap()
uni_list = font_cmap.values()
print(uni_list)
font_n = TTFont('1.woff')
for i in uni_list:
f = font_n['glyf'].glyphs.get(i).data
glpyh = md5(f).hexdigest()
for j in base_font.get('font'):
if j.get('hex')==glpyh:
dic[fot[i]]=j['value']
print(dic)
with open('58.html','r',encoding='utf8') as f:
ret = f.read()
for i in dic:
ret = ret.replace(i,dic[i])
page_html = etree.HTML(ret)
lis = page_html.xpath('//*[@id="list"]/ul/li/div')
for li in lis:
name = ('-').join(li.xpath('../div[1]/a//text()')).replace('\n','').replace('\t','').replace(' ','')
# money = li.xpath('../div[2]//text()')
print(name)