常见反爬措施--动态字体反爬
通过对数据的获取,我们已经掌握了一些简单的反爬措施,但是获取到的数据都是加密的,无法直接读取其中的信息。那么我们该怎么解决呢?
只有通过对加密字体的解密,再将解密字体和加密字体进行replace即可。现在,我们还是以实习僧为例,来看一下其中的解密流程是怎样的。
一、解密前的了解。
首先,观察到数据改成了json类型展示到网页上,我们通过后台管理工具观察XHR发现有一些数据的字体是加密的。如下图所示。
那么想要解密字体,就必须找到字体字样文件,这里直接点击字体选项,捕获字体文件,一般是file?开头的文件就是解密字体文件。
在标头中找到链接,打开链接下载即可。
在这里,我们需要一个可视化查看字体的软件:High-Logic FontCreator。打开该文件如下图所示。
可以确定的是,这就是我们所需要的字体解密文件。
接下来我们需要通过这个解密文件做两个事情:
1、通过python读取该文件,获取加密前的数字,进行模拟加密过程,获取同样的加密密文。
2、手动整体该文件可视化中呈现的字体对应关系。如:“年”:uni5E74。
大致流程图如下:
二、开始解密
首先,导入需要读取解密字体样式的模块。
from fontTools.ttLib import TTFont
将字体解密文件直接放进python中
读取字体文件的加密前的样式
font = TTFont('file')
cont = font.getBestCmap()
print(cont)
打印打码如下:
通过我们对上述加密字体的观察发现,加密字体中的,是经uni70所对应的57717通过16进制加密(hex())后,再将其中开头0转为&#表示得来的。如图:
那么接下来我们只需要通过字体文件中的glyf锁定密文前所指向的值,如:‘uni70’。
glyf = font['glyf']
glyfmap = {
0: glyf['uni30'],
1: glyf['uni31'],
2: glyf['uni32'],
3: glyf['uni33'],
4: glyf['uni34'],
5: glyf['uni35'],
6: glyf['uni36'],
7: glyf['uni37'],
8: glyf['uni38'],
9: glyf['uni39'],
'p': glyf['uni70'],
'P': glyf['uni50'],
'Y': glyf['uni59'],
'T': glyf['uni54'],
'H': glyf['uni48'],
'O': glyf['uni4f'],
'y': glyf['uni79'],
't': glyf['uni74'],
'h': glyf['uni68'],
'o': glyf['uni6f'],
'n': glyf['uni6e'],
'工': glyf['uni5DE5'],
'程': glyf['uni7A0B'],
'师': glyf['uni5E08'],
'生': glyf['uni751F'],
'端': glyf['uni7AEF'],
'前': glyf['uni524D'],
'网': glyf['uni7F51'],
'月': glyf['uni6708'],
'软': glyf['uni8F6F'],
'联': glyf['uni8054'],
'银': glyf['uni94F6'],
'行': glyf['uni884C'],
'件': glyf['uni4EF6'],
'政': glyf['uni653F'],
'人': glyf['uni4EBA'],
'互': glyf['uni4E92'],
'三': glyf['uni4E09'],
'作': glyf['uni4F5C'],
'告': glyf['uni544A'],
'个': glyf['uni4E2A'],
'市': glyf['uni5E02'],
'广': glyf['uni5E7F'],
'天': glyf['uni5929'],
'五': glyf['uni4E94'],
'设': glyf['uni8BBE'],
'年': glyf['uni5E74'],
'周': glyf['uni5468'],
'招': glyf['uni62DB'],
'聘': glyf['uni8058'],
'场': glyf['uni573A'],
'财': glyf['uni8D22'],
'四': glyf['uni56DB'],
'计': glyf['uni8BA1'],
'会': glyf['uni4F1A'],
'一': glyf['uni4E00'],
'X': glyf['uni58'],
'L': glyf['uni4c'],
'd': glyf['uni64'],
'|': glyf['uni6c'],
'x': glyf['uni78'],
'C': glyf['uni43'],
'G': glyf['uni47'],
'K': glyf['uni4b'],
'S': glyf['uni53'],
'W': glyf['uni57'],
'c': glyf['uni63'],
'g': glyf['uni67'],
'k': glyf['uni6b'],
's': glyf['uni73'],
'w': glyf['uni77'],
'B': glyf['uni42'],
'F': glyf['uni46'],
'N': glyf['uni4e'],
'R': glyf['uni52'],
'V': glyf['uni56'],
'Z': glyf['uni5a'],
'b': glyf['uni62'],
'f': glyf['uni66'],
'j': glyf['uni6a'],
'r': glyf['uni72'],
'v': glyf['uni76'],
'z': glyf['uni7a'],
'A': glyf['uni41'],
'J': glyf['uni4a'],
'E': glyf['uni45'],
'I': glyf['uni49'],
'M': glyf['uni4d'],
'Q': glyf['uni51'],
'U': glyf['uni55'],
'a': glyf['uni61'],
'e': glyf['uni65'],
'i': glyf['uni69'],
'm': glyf['uni6d'],
'q': glyf['uni71'],
'u': glyf['uni75'],
}
只要可视化工具中所对应的glyf['uni70']与字体文件中读取到的glyf['uni70']相等,那么就将密文替换为可视化工具中所打出的对应关系glyfmap字典中的键,即&#e175换成‘P’。
具体代码如下:
cont = font.getBestCmap()
for data,name in cont.items():
hex_data=hex(data)
name = glyf[name]
for data_new,name_new in glyfmap.items():
if name_new == name:
name55 = name55.replace(hex_data,str(data_new))
在这里,由于涉及到翻页,将代码放进了类中进行调用。完整代码如下:
import requests
from fontTools.ttLib import TTFont
font = TTFont('file')
glyf = font['glyf']
glyfmap = {
0: glyf['uni30'],
1: glyf['uni31'],
2: glyf['uni32'],
3: glyf['uni33'],
4: glyf['uni34'],
5: glyf['uni35'],
6: glyf['uni36'],
7: glyf['uni37'],
8: glyf['uni38'],
9: glyf['uni39'],
'p': glyf['uni70'],
'P': glyf['uni50'],
'Y': glyf['uni59'],
'T': glyf['uni54'],
'H': glyf['uni48'],
'O': glyf['uni4f'],
'y': glyf['uni79'],
't': glyf['uni74'],
'h': glyf['uni68'],
'o': glyf['uni6f'],
'n': glyf['uni6e'],
'工': glyf['uni5DE5'],
'程': glyf['uni7A0B'],
'师': glyf['uni5E08'],
'生': glyf['uni751F'],
'端': glyf['uni7AEF'],
'前': glyf['uni524D'],
'网': glyf['uni7F51'],
'月': glyf['uni6708'],
'软': glyf['uni8F6F'],
'联': glyf['uni8054'],
'银': glyf['uni94F6'],
'行': glyf['uni884C'],
'件': glyf['uni4EF6'],
'政': glyf['uni653F'],
'人': glyf['uni4EBA'],
'互': glyf['uni4E92'],
'三': glyf['uni4E09'],
'作': glyf['uni4F5C'],
'告': glyf['uni544A'],
'个': glyf['uni4E2A'],
'市': glyf['uni5E02'],
'广': glyf['uni5E7F'],
'天': glyf['uni5929'],
'五': glyf['uni4E94'],
'设': glyf['uni8BBE'],
'年': glyf['uni5E74'],
'周': glyf['uni5468'],
'招': glyf['uni62DB'],
'聘': glyf['uni8058'],
'场': glyf['uni573A'],
'财': glyf['uni8D22'],
'四': glyf['uni56DB'],
'计': glyf['uni8BA1'],
'会': glyf['uni4F1A'],
'一': glyf['uni4E00'],
'X': glyf['uni58'],
'L': glyf['uni4c'],
'd': glyf['uni64'],
'|': glyf['uni6c'],
'x': glyf['uni78'],
'C': glyf['uni43'],
'G': glyf['uni47'],
'K': glyf['uni4b'],
'S': glyf['uni53'],
'W': glyf['uni57'],
'c': glyf['uni63'],
'g': glyf['uni67'],
'k': glyf['uni6b'],
's': glyf['uni73'],
'w': glyf['uni77'],
'B': glyf['uni42'],
'F': glyf['uni46'],
'N': glyf['uni4e'],
'R': glyf['uni52'],
'V': glyf['uni56'],
'Z': glyf['uni5a'],
'b': glyf['uni62'],
'f': glyf['uni66'],
'j': glyf['uni6a'],
'r': glyf['uni72'],
'v': glyf['uni76'],
'z': glyf['uni7a'],
'A': glyf['uni41'],
'J': glyf['uni4a'],
'E': glyf['uni45'],
'I': glyf['uni49'],
'M': glyf['uni4d'],
'Q': glyf['uni51'],
'U': glyf['uni55'],
'a': glyf['uni61'],
'e': glyf['uni65'],
'i': glyf['uni69'],
'm': glyf['uni6d'],
'q': glyf['uni71'],
'u': glyf['uni75'],
}
# 寻找对应关系
class Shi_Xiseng(object):
def __init__(self):
self.url="https://www.shixiseng.com/app/interns/search/v2?"
self.headers={
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36"
}
def data_parse(self):
for i in range(1,10):
params={
"build_time": "1679799002643",
"page": i,
"type": "intern",
"keyword": "python爬虫",
"area": "",
"months": "",
"days": "",
"degree": "",
"official": "",
"enterprise": "",
"salary": "-0",
"publishTime": "",
"sortType": "",
"city": "全国",
"internExtend": "",
}
response = requests.get(url=self.url,headers=self.headers,params=params).json()
# print(response)
response_list=response['msg']['data']
for data in response_list:
city = data['city']
cname = data['cname']
name55 = str(data['name']).replace("&#","0")
name = self.jie_mi(name55)
maxsal = self.jie_mi(str(data['maxsal']).replace("&#","0"))
minsal = self.jie_mi(str(data['minsal']).replace("&#","0"))
month_num = self.jie_mi(str(data['month_num']).replace("&#","0"))
print(city,cname,name,maxsal,minsal,month_num)
def jie_mi(self,name55):
cont = font.getBestCmap()
for data,name in cont.items():
hex_data=hex(data)
name = glyf[name]
for data_new,name_new in glyfmap.items():
if name_new == name:
name55 = name55.replace(hex_data,str(data_new))
return name55
if __name__ == '__main__':
d=Shi_Xiseng()
d.data_parse()
效果:
ps:字体文件具有时效性,有的是需要定期更换(即重新下载一遍放进python中读取就可以了)。
那么到这里,关于动态字体的解密示例就结束了...希望可以帮助到你。