网页字体加密本质是前端隐藏数字的障眼法,python通过解析映射关系或定位原始数据源绕过渲染层;判断方式包括检查textcontent与innertext差异、@font-face引用、伪元素content值及span class命名规律;woff映射提取依赖fonttools读取cmap并结合css或js中的unicode映射规则;动态svg/canvas场景需分析js行为而非ocr;requests+beautifulsoup能否直接获取真实数字取决于数据是否存在于初始html、script内json、注释、meta标签或ajax接口中。

网页字体加密(如自定义 WebFont、SVG 字体映射、CSS 伪元素混淆)不是“密码学意义上的加密”,而是前端刻意隐藏数字文本的障眼法——Python 本身不破解字体,而是绕过渲染层,直接解析映射关系或提取原始数据。关键在定位真实数据源,而非暴力解密字形。
怎么判断页面用的是哪种字体混淆方式?
先打开浏览器开发者工具(F12),定位到疑似被混淆的数字区域:
- 右键「检查元素」,看
textContent是否为空或为乱码(如),而innerText显示正常数字 → 多为 Unicode 私有区 + 自定义字体(.woff/.ttf) - 查看 computed 样式中是否引用了
@font-face,字体文件 URL 通常含.woff、.ttf或.svg - 搜索 HTML 源码里是否有
<style></style>块定义了::before/::after伪元素 +content: "\e612"→ 这是 CSS 字体图标映射 - 若数字由多个
<span></span>拼接,且每个 span 的 class 名含num-0、glyph-3等 → 很可能是 SVG symbol 映射或 JS 动态替换
如何从 .woff 字体文件提取字符映射表?
下载字体文件(右键「Open in new tab」或 curl 下载),用 Python 解析其 cmap 表(字符码→字形ID映射)和 glyf 表(字形轮廓),但真正实用的是反向查 glyph name → 数字含义。常用做法是结合字体文件 + 页面 CSS 中的 Unicode 映射规则:
- 用
fonttools读取 woff:安装pip install fonttools,运行from fontTools.ttLib import TTFont - 加载后获取 cmap:
font = TTFont("xxx.woff"); cmap = font.getBestCmap()→ 返回 dict,如{0xe612: 'uniE612'} - 再查 glyph 名称对应的实际数字:常见套路是字体 designer 把
uniE612的字形画成 “3”,然后在 CSS 里写.num-3::before { content: "\e612" };所以需人工/脚本比对 glyph 名称与页面 class 名或 JS 变量名 - 更稳的方式:抓包看页面 JS 是否加载了映射 JSON(如
fontMapping = {"\uE612": "3", "\uE613": "5"}),这比解析字体快得多
遇到动态生成的 SVG 字体或 canvas 渲染怎么办?
这类场景 Python 无法直接“识别图像中的数字”,必须放弃 OCR 思路,转而分析 JS 行为:
- 禁用 JavaScript 后刷新页面,若数字消失 → 说明数字由 JS 动态注入,搜 JS 文件里的
document.write、innerHTML、textContent赋值逻辑 - 在 Sources 面板全局搜索
charCode、String.fromCharCode、atob、eval,常有 base64 编码的映射表或数组字面量 - 若用
<canvas></canvas>绘制数字,检查 canvas 上下文调用栈,找fillText参数 —— 它的第二个参数往往是真实字符串,只是被字体遮盖;断点调试可捕获 - 不要用
pytesseract对截图 OCR:精度低、易受字号/抗锯齿干扰,且违反多数网站 robots.txt 和 ToS
requests + BeautifulSoup 能直接拿到真实数字吗?
有时能,有时不能,取决于数据是否存在于初始 HTML 中:
- 如果数字在
<script></script>标签内以 JSON 形式存在(如var data = {price: "399"}),用re.search(r'var data = (.*?);', html)提取后json.loads()即可 - 如果数字藏在注释里(
<!-- price: 399 -->),BeautifulSoup 默认不解析注释,要用soup.find(string=lambda text: isinstance(text, Comment)) - 如果页面依赖 Ajax 加载,
requests拿到的只是骨架 HTML,需分析 Network 面板里的 XHR/Fetch 请求,复现 headers(尤其是X-Requested-With、Cookie)再请求真实接口 - 别忽略
meta标签:有些站点把关键数据塞进<meta name="price" content="399">,直接soup.find("meta", attrs={"name": "price"})["content"]
真正麻烦的不是解析字体,而是字体背后那层 JS 逻辑——它可能每次加载都生成新映射、校验 referer、甚至调用 WebAssembly 解密函数。这时候 Python 就得让位给 playwright 或 Pyppeteer 执行真实渲染并 hook JS 变量,而不是硬啃字体二进制。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











