当前位置: 首页 > article >正文

字体反爬 fontTools | ddddocr

字体反爬

网站地址

aHR0cHM6Ly93d3cuc2hpdGl0b25nLmNuLw==

F12检查时, 元素内文本与实际显示文本不一致, 多半就是字体文件搞的鬼, 而不是js, 特别是字数长度相等时

image-20241102120758574

网络标签页筛选字体文件, 发现有个字体文件, 保存下来, 使用FontCreator 多功能字体设计制作编辑软件打开

image-20241102120927478

Ctrl+F 搜索原来的字 “做”, 发现搜出来的时个 “项” 字, 而这刚好对应

2、做护制图物燃好满() => 2、项目成本控制时指() 映射的第一个字

image-20241102121402933

由于找不到映射的字体信息, 只能通过OCR去识别出来, 不过这些字体还是很规范的, 识别还是挺准的; 而且识别一次就可以作缓存一直用了, 除非是动态字体文件可能需要每次请求识别.

最后构建出一个类似下面的字体映射表, 对原字符做替换就可以获取原本的字符文本了

{
  "做": "项",
  "护": "目",
  ....
}

Python代码实现如下

import os

from fontTools.ttLib import TTFont
from PIL import Image, ImageDraw, ImageFont
from io import BytesIO
import ddddocr
import shelve


def recognize_fonts(char, pil_font, ocr):
    """
    识别字体文件中的字符
    :param char: 原始字符
    :param pil_font: PIL 字体对象
    :param ocr: ocr 实例
    :return: OCR 识别的真实字符
    """
    img = Image.new("L", (100, 100), color=255)  # 白色背景
    draw = ImageDraw.Draw(img)
    # 指定字体对象绘制字符, 所以传入的字符"做"会根据错乱的字体文件被绘制成"项"
    draw.text((10, 10), char, font=pil_font, fill=0)  # 绘制字符到图像
    # 将图像保存到内存缓冲区
    buffer = BytesIO()
    img.save(buffer, format="PNG")
    buffer.seek(0)
    # OCR 识别字符
    return ocr.classification(buffer.read())


def save_mapping_table():
    """
    生成字体映射表
    :return:
    """
    mapping_table = shelve.open('mapping_table')
    # 加载字体文件
    font_path = "sfontstt.ttf"  # 替换为实际的字体文件路径
    tt_font = TTFont(font_path)
    # 创建 PIL 字体对象
    # 使用 fontTools 提取的字体文件在 Pillow 中创建字体对象
    buffer = BytesIO()
    tt_font.save(buffer)  # 保存字体文件到内存缓冲区
    buffer.seek(0)  # 重置缓冲区指针
    pil_font = ImageFont.truetype(buffer, size=48)  # 创建 PIL 字体对象
    # 初始化 OCR
    ocr = ddddocr.DdddOcr()
    # 获取字符映射
    cmap = tt_font['cmap'].getBestCmap()
    # 遍历字体文件中的字符映射
    for codepoint, glyph_name in cmap.items():
        char = chr(codepoint)  # 获取字符
        # 创建空白图像
        recognized_text = recognize_fonts(char, pil_font, ocr)
        # 20570 -> uni505A -> 做 -> 项
        # print(f"{codepoint} -> {glyph_name} -> {char} -> {recognized_text}")
        if char != recognized_text:
            mapping_table[char] = recognized_text
    # print(len(mapping_table.items()))  # 563
    mapping_table.close()


def decrypt_text(txt):
    # 判断是否已经生成映射表缓存
    if not os.path.exists('mapping_table.dat'):
        save_mapping_table()
    with shelve.open('mapping_table') as mapping_table:
        return ''.join([mapping_table.get(char, char) for char in txt])


if __name__ == '__main__':
    test_txt = ['观计厢辆蚀为量,级架对和体需观计据( )需观计。', '2、做护制图物燃好满()',
                '7、保启由拟稳速件录液回负从包绳方开,曳四或正需级采进择:①企变液速时备爆业;②附放已曳绳由了;③端购术制绳软了上其;④增门天修变录靠爆业。针动施几或正需,做护且量破相设司他计起口绳决策树。炉带求附放绳配空他,司投传负即同建求房或级第,简点由般绳概果对0.2,制图约31坏引;附杂由般绳概果对0.8,制图约49坏引。哪此计,必量本进择方开正需绳循佳决策路()。']
    for txt in test_txt:
        decrypted_text = decrypt_text(txt)
        print(decrypted_text)

测试识别结果没问题就OK了

image-20241102124109256


http://www.kler.cn/a/376319.html

相关文章:

  • RFID资产管理
  • 公众号黑名单(资源类)仅个人备份,便于查看
  • 【第几小】
  • 支付域——调拨系统设计
  • 坏块处理 ORA-01578: ORACLE data block corrupted (file # 3, block # 152588)
  • Linux之nfs服务器和dns服务器
  • 高德地图如何标注店铺名称和位置信息?
  • timm使用笔记
  • 20221403郑骁恒第八周预习报告
  • 基于单片机的智能婴儿监控系统设计(论文+源码)
  • Istio基本概念及部署
  • Vue Router 中 router、route 和 routes 的区别 - 2024最新版前端秋招面试短期突击面试题【100道】
  • 深度学习速通系列:如何使用bert进行超长中文文本命名实体识别
  • Jupyter lab 打开时默认使用 Notebook 而不是浏览器
  • springboot-starter 整合feignClient
  • 方差与协方差
  • 【销帮帮-注册/登录安全分析报告-试用页面存在安全隐患】
  • C++学习大纲
  • vue和django接口联调
  • Go Modules和 雅典项目
  • C++ ----------- 栈和队列
  • 【小白学机器学习25 】 用交叉表去理解自由度的计算
  • Markdown自学第二课之记笔记——HTML第一弹
  • go语言gin框架平滑关闭——思悟项目技术2
  • 【Spark中创建RDD的两种方式】Spark中如何获取sc对象、以及创建RDD的两种方式
  • 异步编程的利之Future模式深入解析(In Depth Analysis of Future Patterns)