1. 字体反爬技术原理剖析当你爬取某些网站时可能会遇到页面显示正常但代码中却是乱码或特殊编码的情况。这往往是字体反爬在作祟。字体反爬的核心原理是网站通过自定义字体文件通常是TTF/WOFF格式对关键文本进行渲染使得HTML源码中的字符与实际显示内容不一致。举个例子招聘网站显示的薪资15K在源码中可能是K。这种技术利用了字体文件的字形映射特性每个Unicode码点对应特定字形而爬虫无法直接获取这种映射关系。提示TTF(TrueType Font)是苹果和微软共同开发的字体标准WOFF(Web Open Font Format)则是专为网页优化的字体格式。2. 破解流程设计完整的破解流程包含以下关键步骤2.1 获取字体文件首先需要从网页中提取字体文件。常见方法有分析CSS中的font-face规则检查网络请求中的woff/ttf资源使用正则匹配字体URL如https://example.com/fonts/xxxx.woffimport requests from fontTools.ttLib import TTFont font_url https://example.com/fonts/xxxx.woff font_data requests.get(font_url).content with open(target_font.woff, wb) as f: f.write(font_data)2.2 解析TTF文件使用fontTools库解析字体文件获取字符编码与字形名称的映射关系font TTFont(target_font.woff) cmap font.getBestCmap() # 获取最佳编码映射表 print(cmap) # 输出示例{100486: uni1886, 100483: uni1883, ...}2.3 生成字形图像将每个字符转换为图片便于OCR识别from PIL import Image, ImageDraw, ImageFont def save_glyph_as_image(char_code, glyph_name): img Image.new(RGB, (100, 100), (255, 255, 255)) draw ImageDraw.Draw(img) font ImageFont.truetype(target_font.woff, 70) text chr(char_code) # Unicode码转字符 draw.text((15, 15), text, fontfont, fill(0, 0, 0)) img.save(fglyphs/{glyph_name}.png)3. OCR识别与映射构建3.1 使用ddddocr识别图像安装高性能OCR库pip install ddddocr识别生成的字符图片import ddddocr ocr ddddocr.DdddOcr(show_adFalse) mapping {} for img_path in os.listdir(glyphs): with open(fglyphs/{img_path}, rb) as f: res ocr.classification(f.read()) char_code int(img_path.split(.)[0][4:], 16) # 从文件名提取Unicode mapping[char_code] res3.2 建立最终映射表将识别结果与原始编码关联final_mapping {} for code, name in cmap.items(): if code in mapping: final_mapping[code] mapping[code] print(final_mapping) # 输出示例{100486: 2, 100483: 7, ...}4. 实战案例招聘网站薪资解密假设目标网站的薪资显示为K处理流程如下4.1 提取加密文本from lxml import html page requests.get(https://jobs.example.com/123) tree html.fromstring(page.content) salary_text tree.xpath(//span[classsalary]/text())[0] # 获取K4.2 文本替换def decrypt_text(encrypted_text, mapping): result [] for char in encrypted_text: code ord(char) result.append(mapping.get(code, char)) # 未匹配的字符保留原样 return .join(result) real_salary decrypt_text(salary_text, final_mapping) print(real_salary) # 输出15K5. 方案优化与注意事项5.1 性能优化技巧缓存机制对已解析的字体文件建立本地缓存批量处理使用多线程加速图像生成和OCR识别预加载模型初始化时加载OCR模型避免重复加载from concurrent.futures import ThreadPoolExecutor def process_glyph(img_path): # 处理单个字符图像 pass with ThreadPoolExecutor(max_workers4) as executor: executor.map(process_glyph, os.listdir(glyphs))5.2 常见问题解决字形相似误识别调整OCR参数或添加后处理规则ocr ddddocr.DdddOcr(betaTrue) # 启用更精确的识别模式动态字体每次访问时检查字体文件是否变化复合字形处理包含多个轮廓的复杂字形6. 进阶自动化监控与更新对于定期更换字体文件的网站可以建立自动化监控系统定时抓取页面检查字体更新自动触发解析流程验证新映射表的准确性更新到生产环境import schedule import time def monitor_job(): # 实现监控逻辑 pass schedule.every(6).hours.do(monitor_job) while True: schedule.run_pending() time.sleep(60)我在实际项目中发现某些网站会随机切换多套字体文件。针对这种情况可以建立字体特征库当检测到新字体时自动匹配已有解决方案大幅降低处理成本。