【原创】针对动态字体反爬技术的解决方案
本项目的测试网站是某b糊
关于字体反爬
别的文章应该介绍的很详细我这里不多做赘述,简单来说就是针对字体文件做了混淆使得网页中的字形轮廓描述与本身的内容不匹配,导致爬取的数据出现“乱码”的情况
使用的工具和环境
Anaconda3
python 3.10.x
fontforge 2016(版本过高在服务器上面windows server 2012 上面跑不起来)
fontforge工具github仓库地址链接
稍微提一下关于某b糊的请求头
"User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1 Edg/116.0.0.0",
"Cookie": ""
这里爬取的是盐xuan的会员文章,用的cookie是冲过会员的cookie
使用手机端的ua能直接拿到数据,但是用网页端是没有办法拿到的,而且不能加其他请求头参数,加了就会拿不到数据,怪
关于fontforge 这个软件内置一个阉割的python环境
可以通过这个命令行激活这个环境来操作 fontforge这个软件如
ps: 这个阉割的python环境一般叫ffpython
second_sc.bat
@REM 这里是在Anaconda 虚拟环境运行的项目 因为老版本的fontforge奇怪的bug让我不得已这么去写
call D:\anaconda3\Lib\site-packages\virtualenv\activation\batch\activate.bat D:\anaconda3
@REM 激活环境
call conda activate zhihuV2
@REM 这一步是因为我写了一个调用fontforge的ffpython 字体文件转换图片的代码放在这个文件夹里
cd /d D:\ProjectFile\pythonProject\pythonProject\font_decode
@REM 设置为fontforge 安装根目录
call C:\Program Files (x86)\FontForgeBuilds\fontforge-console.bat
@REM 使用fontforge python api 运行script.py 文件
call fontforge -script D:\ProjectFile\Zhihu_Botv2\find_bot\script.py %1
script.py
import fontforge
import sys
import os
title = sys.argv[1]
Path = "D:/ProjectFile/pic_temp/"
if not os.path.exists((Path + title)):
os.makedirs((Path + title))
picpath = Path + title + "/"
F = fontforge.open("D:/ProjectFile/ttf_temp/" + title + "/" + title + "font.ttf")
for name in F:
filename = picpath + name + ".png"
F[name].export(filename)
通过以上调用就可以实现自动化的字体文件中的字体轮廓数据转换成图片
最后在通过 ocr 字体识别就可以得到正确的字形 字体编码的对应表
作者使用的是dddocr准确度也是非常高
# 这里是某个网站的json数据 获取字体文件
font = \
json_data["appContext"]["__connectedAutoFetch"]["manuscript"]["data"]["manuscriptData"][
"font"][
'base64']
# 将base64编码转换成 ttf 文件
with open((tempPath + title + '/' + title + 'font.ttf'), 'wb') as f:
f.write(base64.decodebytes(font[35:].encode()))
# 运行fontforge 脚本使用 ffpython 环境创建 pic_temp/(文章标题)
# 脚本会在文件夹中创建 爬取的字体 进行ttf2pic
bat_script_path = "second_sc.bat "
subprocess.run(['cmd', '/c', 'start', '', bat_script_path, title], shell=True)
# 等待图片生成完成 3 秒
sleep(3)
# 1.使用pic库将图片按照 字体库中的uni编码顺序 拼接成矩阵提高ocr成功概率
# 2.直接使用ddddocr 逐个识别 (√)
# ddddocr
pic_path = "D:/ProjectFile//pic_temp/" + title + "/"
path = os.listdir(pic_path)
res = dict()
for i in range(1, len(path)):
res[path[i][:7]] = img2text(pic_path + path[i])
# res 是所有 ttf2pic 图片 (uni编码 :pic) 键值对
# 根据字体文件生成,解码映射表 (测试时记得删除pic_temp中的相同文章ttf2pic文件)
values_list = []
font = TTFont((tempPath + title + "/" + title + 'font.ttf'))
glypid = font.getGlyphOrder()[1:]
for t in glypid:
values_list.append(res[t])
keys_list = []
true_dict = {}
Glyph = list(font.getGlyphOrder())
for i in range(1, len(Glyph)):
keys_list.append(chr(int(Glyph[i][3:], 16)))
true_dict = dict(zip(keys_list, values_list))
# 获取解码需要解码的文件全文 根据映射表进行置换
text = open(tempPath + title + "/" + title + "encode.txt", mode="r",
encoding="utf-8").read().translate(str.maketrans(true_dict))
with open((textPath + title + 'decode.txt'), mode='w', encoding='utf-8') as f:
f.write(text)
# 全文替换完成之后 文章爬取结束