博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
python字体反爬详解--以查策网字体为例
阅读量:3936 次
发布时间:2019-05-23

本文共 3971 字,大约阅读时间需要 13 分钟。

python字体反爬的一种解决方案

文章目录

版权声明

请注意:本文章为原创文章,未经本人许可,任何人不得转载和借鉴

问题

目前越来越多的网站升级了应对爬虫的反制手段和措施,网站使用自定义字体或者人们常说的字体反爬,就是其中一种。

描述

这里我们以查策网()为例

打开查策网的某一篇政策文章:
在这里插入图片描述
看起来都很正常,但是当我们点击右键、打开检查,或者F12

在这里插入图片描述

可以发现,【申报条件】这个板块里面的文字,和源代码里的文字完全不一样;
比如“申请企业应具备以下条件:”,代码里则对应为:“者合册第应具步以督法快:”;
即使你选中文字,再把它们复制出来,文字粘贴后依然为:“者合册第应具步以督法快:”。

解决方案

解决该问题的一种基本思路是:构建源字体与替换字体的对应关系

比如上文提到的句子:
者合册第应具步以督法快替换为申请企业应具备以下条件
其中: > | > | >
假如我们能有这样的一个对应字典

change_font = {
'者': '申', '合': '请', '册': '企', ... , }

那么我们就能够将网站爬到的所有字体,都替换成正确的文字。

实操过程

1、找到网站的字体文件(ccw.ttf)

F12打开检查后,点击Network,刷新我们刚才访问的政策链接,在众多链接中,找到网站的字体文件链接()

在这里插入图片描述
然后在浏览器中打开该链接,并保存到本地

2、使用百度字体编辑器

接下来,我们需要用到百度的在线字体编辑器,网址为:

打开该网站后,点击左上角的打开,然后上传刚才保存的查策网的字体文件
在这里插入图片描述
打开后:
在这里插入图片描述
这时候我们就能看到查策网的网站字体和编码对应的关系
在这里插入图片描述

3、fontTools库

3.1

接下来我们使用python解析字体的常用库:fontTools

>>>from fontTools.ttLib import TTFont>>>FONT_FILE = r'C:\Users\17337\Downloads\ccw.ttf'>>>font_file = TTFont(FONT_FILE)>>>for k, v in font_file['cmap'].getBestCmap().items():>>>    print(k, v)33 ampersand35 greater36 c37 asciitilde38 H40 q41 S......39069 uni989D39318 uni999639564 uni9A8C39640 uni9AD840857 uni9F99>>>

这里getBestCmap返回的是一个unicode cmap字典,即编码和图形的对应关系。

请注意:这里key为字体的编码,value为每个字体对应的独特的id值,这里为了方便理解,我们可以把这个value理解成字体的注释

3.2

结合展示的字体,我们可以随便找一个字体作为切入点,比如刚才打印的最后一对键值对

40857 uni9F99

编码为:40857 ,注释为:uni9F99

在我们刚才打开的百度字体编辑器的第三页,有一个字体【八】正好也是uni9F99
在这里插入图片描述
除了注释uni9F99对上了,还有其他我们能着手的点吗?
仔细看【八】这个【$9F99】,和我们的编码【40857】
一个看起来像是16进制,一个看起来像是十进制,这两个数字有关联吗

>>>hex(40857)  # 十进制转十六进制'0x9f99'

答案是:字体编辑器的上面这个编码【$9F99】,正是【40857】的十六进制表示。

所以,现在我们知道了,【uni9F99】这个注释对应的字体就是【八】,也能通过fontTools找到这个对应关系,但是我们现在还不知道的是:哪个源代码的字体要替换成【八】

3.3

回到我们刚才打开的政策网页,【申报材料】里,正好也有一个【八】

在这里插入图片描述
很显然,源代码的【龙】字,实际展示时,为【八】这个汉字
所以,源代码里:要替换成
那么前端代码在处理和展示的时候,怎么知道要替换成,或者说替换成这个字体图形?
显然是有一套通用的处理规则,我们现在就是要找出这套转换规则
从【龙】这个汉字入手:
【龙】utf8编码为【\xe9\xbe\x99】
【龙】gbk编码为【\xc1\xfa】
【龙】的Ascii数值为【40857】

>>>ord('龙')40857

40857!刚才我们使用getBestCmap返回的字典,【40857】正好对应的值是【uni9F99】,对应的字体正好是【八】!

所以汉字【龙】> ord(‘龙’) > 40857

3.4

现在我们只剩最后一个问题:

如何批量构建,类似于这种【40857/$9F99/uni9F99】与【八】的对应关系?
答案是:手动构建!
当然,也不是完全手动构建类似 {‘uni9F99’: ‘八’, ‘six’: ‘6’, … ,} 这种字典
有一种取巧的方式:
fontTools库的getGlyphOrder() 方法,可以获取字体文件的所有字体注释
该方法返回的字体注释的列表,与百度字体编辑器展示的顺序是一模一样的

>>>font_file.getGlyphOrder()['.notdef', 'nine', 'eight', 'three', 'four', 'seven', ..., 'uni9662', 'uni660E']

在这里插入图片描述

下图为手动构建的完整的FONT_LIST(要对应百度字体编辑器)

在这里插入图片描述
上文所说的手动构建,就是指,把百度字体编辑器展示的字体,一个一个对应着写到一个列表里,保存起来,以后若是网站字体又有所更新,只需要修改相应的元素即可。
所以这里我们只需要手动按顺序构建字体对应的列表FONT_LIST,即可生成对应的字典

>>>FONT_LIST = [' ', '9', '8', '3', '4', '7', ..., '明', '局', '第']>>>font_dict = dict(zip(font_file.getGlyphOrder(), FONT_LIST))>>>font_dict{
'.notdef': ' ', 'nine': '9', 'eight': '8', 'three': '3', 'four': '4', 'seven': '7', ... 'uni7B2C': '业', 'uni3007': '院', 'uni4E1A': '⚪', 'uni5C40': '明', 'uni9662': '局', 'uni660E': '第'}

这个font_dict有什么用呢,这还要和前文的getBestCmap方法配合起来使用

>>>replace_dict = {
}>>>for code, value in font_file['cmap'].getBestCmap().items():>>> before_replace = chr(code) # 源代码的汉字字符串>>> after_replace = font_dict[value] # 需要替换的汉字字体>>> replace_dict[before_replace] = after_replace>>>replace_dict{
'!': '&', '#': '>', '$': 'c', '%': '~', '&': 'H', '(': 'q', ... '革': '策', '项': '不', '须': '制', '额': '司', '首': '免', '验': '省', '高': '天', '龙': '八'}

这个replace_dict就是我们最终的用来替换文本的字典了。

到此,我们的实操就结束了,下面进入整体流程的代码部分。

完整代码

from fontTools.ttLib import TTFontFONT_FILE = r'C:\Users\17337\Downloads\ccw.ttf'FONT_LIST = [' ', '9', '8', '3', '4', '7', ..., '明', '局', '第']def get_font():    font_file = TTFont(FONT_FILE)    font_dict = dict(zip(font_file.getGlyphOrder(), FONT_LIST))  # 注释和真实字体的对应关系字典    return {
chr(k): font_dict[v] for k, v in font_file['cmap'].getBestCmap().items()}def change(text): replace_dict = get_font() return ''.join([replace_dict.get(each, each) for each in text]) if text else ''def test(): chace_str = '者合册第应具步以督法快:' result = change(chace_str) print('转换前:"{}", 转换后:"{}"'.format(chace_str, result))if __name__ == '__main__': test()

运行结果

在这里插入图片描述

讨论

文章中,本人提供了一种字体反爬的解决方案,当然,也有该方案的缺陷:

1.需要手动构建FONT_LIST列表,比较花费时间
2.适用于查策网,但不一定适用于其他网站,不能作为一种普适的字体反爬的解决方案

感谢您的观看!

你可能感兴趣的文章
ElasticSearch + Canal搭建搜索系统(整理中)
查看>>
Centos系统安装MySQL(整理)
查看>>
Ubuntu 下PostgreSQL、postgis安装与配置
查看>>
postgresql计算两点距离(经纬度地理位置)
查看>>
postgres多边形存储--解决 Points of LinearRing do not form a closed linestring
查看>>
postgresql+postgis空间数据库总结
查看>>
spring 之 Http Cache 和 Etag(转)
查看>>
JAVA8-用lamda表达式和增强版Comparator进行排序(转)
查看>>
基于Lucene查询原理分析Elasticsearch的性能(转)
查看>>
依赖多个项目,重复jar包不同版本冲突解决
查看>>
阿里 weex--前端整合开源框架(记录)
查看>>
spring event的事件驱动模型(转)
查看>>
阿里开源在线诊断工具-Arthas(阿尔萨斯)
查看>>
kubernetes(整理中)
查看>>
Deepin 下安装 Docker
查看>>
Github骚操作(转)
查看>>
滴滴出行基于RocketMQ的改造分享(转)
查看>>
redis之lua整理
查看>>
alibaba-nacos之config、discovery
查看>>
介绍Jib - 更好地构建Java Docker镜像(转)
查看>>