python爬虫:某网站价格数字加密破解

文章目录

  • 前言
  • 一、案例
  • 二、破解流程
    • 1.原理
    • 2.找到woff文件
    • 3.分析woff文件
    • 4.代码实现
        • 1.转化woff文件
        • 2.绘图并ocr识别
        • 3.映射数据
  • 三、总结


前言

有时我们在进行网页抓取采集数据时,有些重要的数据比如说价格,数量等信息会进行加密,通过复制或者简单的采集是无法采集到编码后的文字内容的,现在貌似有不少网站都有采用这种反爬机制,作为爬虫工程师,还是要了解甚至掌握这个技巧的。

一、案例

在这里插入图片描述

在某网站商品价格展示,打开F12 ,数字和符号是做了替换,显示为ȜŽŏŏŕŏŏ,所以如果我们想获取所看到的价格就要花些功夫。

二、破解流程

1.原理

其实这就是CSS反爬,CSS字体反爬是一种通过使用自定义字体和字符映射来保护页面内容的技术。在这类技术中,网页上的文本并非直接展示为标准字符,而是通过特殊设计的字体显示。这样,即使爬虫抓取到页面源代码,获得的却是字体文件的引用,而不是实际的字符内容。
通常,这些字体文件是通过 JavaScript 动态加载的,而且在字体文件中,每个字符与其对应的可视形态之间存在一个映射关系。只有浏览器能够正确渲染这些映射,爬虫则无法直接读取到有效的文本内容,需要我们间接获取解析处理。

2.找到woff文件

第一种方法,通过标签class的属性值,例如上图中class值:fontf04dfc98 全局搜索:
在这里插入图片描述

第二种方法:也是全局搜索font-face,也是同样的效果

3.分析woff文件

把上图带有woff字样的链接下载到本地,使用FontEditor打开woff文件,链接地址:https://font.qqe2.com/index.html?src=www.jspoo.com
在这里插入图片描述
发现这上面的字符串跟网页的ȜŽŏŏŕŏŏ不一样,那我们尝试点击预览按钮,切换eot字体如下图:
在这里插入图片描述
会弹出另一个窗口,两个窗口内容进行比较
在这里插入图片描述
我们是不是已经发现了网页的不规范数字1对应Ȝ,这是不是就对应上了,接下来就是代码实现这个流程的问题

4.代码实现

1.转化woff文件
from fontTools.ttLib import TTFont
font = TTFont('tansoole.woff')
font.saveXML('tansoole.xml')

运行代码并打开部分标签,如图:
在这里插入图片描述

# 可以转化获取name值def extract_font_data_from_woff(woff_file_path):font = TTFont(woff_file_path)cmap = font.getBestCmap()code_to_name = {}for code, name in cmap.items():code_to_name[code] = namereturn code_to_namewoff_file_path = 'tansoole.woff'unicode_mapping = extract_font_data_from_woff(woff_file_path)print(unicode_mapping)#打印信息# {0: '.null', 29: '.null', 287: 'gbreve', 292: 'Hcircumflex', 298: 'Imacron', 335: 'obreve', 341: 'racute', 362: 'Umacron', 381: 'Zcaron', 453: 'uni01C5', 459: 'uni01CB', 540: 'uni021C', 548: 'uni0224', 550: 'uni0226'}# 转化对应eot对应关系
Mapping_tables = {}
for code, mapping in unicode_mapping.items():character_key = chr(code)character_value = mappingMapping_tables[character_key] = character_value
print(Mapping_tables)
# 打印信息
# {'\x00': '.null', '\x1d': '.null', 'ğ': 'gbreve', 'Ĥ': 'Hcircumflex', 'Ī': 'Imacron', 'ŏ': 'obreve', 'ŕ': 'racute', 'Ū': 'Umacron', 'Ž': 'Zcaron', 'Dž': 'uni01C5', 'Nj': 'uni01CB', 'Ȝ': 'uni021C', 'Ȥ': 'uni0224', 'Ȧ': 'uni0226'}
2.绘图并ocr识别
import os
import timeimport ddddocrfrom fontTools.ttLib.ttFont import TTFont
from fontTools.pens.svgPathPen import SVGPathPen
import matplotlib.pyplot as plt
import matplotlib.patches as patches
from matplotlib.path import Path
import matplotlib._color_data as mcddef ttf_to_char(font_file, glyph_set_name=None, temp_png_path="./"):# %matplotlib inline# 加载字体font = TTFont(font_file)# 7.1 生成PNG图片# 7.1.1 第一步提取绘制命令语句# 获取包含字形名称和字形对象的--字形集对象glyphsetglyphset = font.getGlyphSet()# print(glyphset.keys())# 获取pen的基类pen = SVGPathPen(glyphset)# 查找"马"的字形对象glyph = glyphset[glyph_set_name]# 绘制"马"的字形对象glyph.draw(pen)# 提取"马"的绘制语句commands = pen._commands# print(commands)total_commands = []command = []for i in commands:# 每一个命令语句if i == 'Z':# 以闭合路径指令Z区分不同轮廓线command.append(i)total_commands.append(command)command = []else:command.append(i)# 从'head'表中提取所有字形的边界框xMin = font['head'].xMinyMin = font['head'].yMinxMax = font['head'].xMaxyMax = font['head'].yMax# print("所有字形的边界框: xMin = {}, xMax = {}, yMin = {}, yMax = {}".format(xMin, xMax, yMin, yMax))# 所有字形的边界框: xMin = -12, xMax = 264, yMin = -47, yMax = 220preX = 0.0preY = 0.0# 笔的起始位置startX = 0.0startY = 0.0# 所有轮廓点total_verts = []# 所有指令total_codes = []# 转换命令for i in total_commands:# 每一条轮廓线verts = []codes = []for command in i:# 每一条轮廓线中的每一个命令code = command[0]  # 第一个字符是指令vert = command[1:].split(' ')  # 其余字符是坐标点,以空格分隔# M = 路径起始 - 参数 - 起始点坐标 (x y)+if code == 'M':codes.append(Path.MOVETO)  # 转换指令verts.append((float(vert[0]), float(vert[1])))  # 提取x和y坐标# 保存笔的起始位置startX = float(vert[0])startY = float(vert[1])# 保存笔的当前位置(由于是起笔,所以当前位置就是起始位置)preX = float(vert[0])preY = float(vert[1])# Q = 绘制二次贝塞尔曲线 - 参数 - 曲线控制点和终点坐标(x1 y1 x y)+elif code == 'Q':codes.append(Path.CURVE3)  # 转换指令verts.append((float(vert[0]), float(vert[1])))  # 提取曲线控制点坐标codes.append(Path.CURVE3)  # 转换指令verts.append((float(vert[2]), float(vert[3])))  # 提取曲线终点坐标# 保存笔的当前位置--曲线终点坐标x和ypreX = float(vert[2])preY = float(vert[3])# C = 绘制三次贝塞尔曲线 - 参数 - 曲线控制点1,控制点2和终点坐标(x1 y1 x2 y2 x y)+elif code == 'C':codes.append(Path.CURVE4)  # 转换指令verts.append((float(vert[0]), float(vert[1])))  # 提取曲线控制点1坐标codes.append(Path.CURVE4)  # 转换指令verts.append((float(vert[2]), float(vert[3])))  # 提取曲线控制点2坐标codes.append(Path.CURVE4)  # 转换指令verts.append((float(vert[4]), float(vert[5])))  # 提取曲线终点坐标# 保存笔的当前位置--曲线终点坐标x和ypreX = float(vert[4])preY = float(vert[5])# L = 绘制直线 - 参数 - 直线终点(x, y)+elif code == 'L':codes.append(Path.LINETO)  # 转换指令verts.append((float(vert[0]), float(vert[1])))  # 提取直线终点坐标# 保存笔的当前位置--直线终点坐标x和ypreX = float(vert[0])preY = float(vert[1])# V = 绘制垂直线 - 参数 - 直线y坐标 (y)+elif code == 'V':# 由于是垂直线,x坐标不变,提取y坐标x = preXy = float(vert[0])codes.append(Path.LINETO)  # 转换指令verts.append((x, y))  # 提取直线终点坐标# 保存笔的当前位置--直线终点坐标x和ypreX = xpreY = y# H = 绘制水平线 - 参数 - 直线x坐标 (x)+elif code == 'H':# 由于是水平线,y坐标不变,提取x坐标x = float(vert[0])y = preYcodes.append(Path.LINETO)  # 转换指令verts.append((x, y))  # 提取直线终点坐标# 保存笔的当前位置--直线终点坐标x和ypreX = xpreY = y# Z = 路径结束,无参数elif code == 'Z':codes.append(Path.CLOSEPOLY)  # 转换指令verts.append((startX, startY))  # 终点坐标就是路径起点坐标# 保存笔的当前位置--起点坐标x和ypreX = startXpreY = startY# 有一些语句指令为空,当作直线处理else:codes.append(Path.LINETO)  # 转换指令verts.append((float(vert[0]), float(vert[1])))  # 提取直线终点坐标# 保存笔的当前位置--直线终点坐标x和ypreX = float(vert[0])preY = float(vert[1])# 整合所有指令和坐标total_verts.append(verts)total_codes.append(codes)color_list = list(mcd.CSS4_COLORS)# 获取所有的轮廓坐标点total_x = []total_y = []for contour in total_verts:# 每一条轮廓曲线x = []y = []for i in contour:# 轮廓线上每一个点的坐标(x,y)x.append(i[0])y.append(i[1])total_x.append(x)total_y.append(y)if total_x == [[186.0, 186.0, 391.0, 391.0, 186.0]]:return '.'if total_x == [[0.0, 425.0, 569.0, 145.0, 0.0]]:return '/'# 创建画布窗口fig, ax = plt.subplots()# 按照'head'表中所有字形的边界框设定x和y轴上下限ax.set_xlim(xMin, xMax)ax.set_ylim(yMin, yMax)# 设置画布1:1显示ax.set_aspect(1)# 添加网格线# ax.grid(alpha=0.8,linestyle='--')# 画图# print(f"{glyph_set_name}======绘制图片=======")for i in range(len(total_codes)):# (1)绘制轮廓线# 定义路径path = Path(total_verts[i], total_codes[i])# 创建形状,无填充,边缘线颜色为color_list中的颜色,边缘线宽度为2patch = patches.PathPatch(path, facecolor='none', edgecolor=color_list[i + 10], lw=2)# 将形状添到图中ax.add_patch(patch)# (2)绘制轮廓点--黑色,点大小为10# ax.scatter(total_x[i], total_y[i], color='black',s=10)# 保存图片temp_path = f"{temp_png_path}/temp{int(time.time()*100000)}.png"plt.savefig(temp_path)plt.close()# print(f"{glyph_set_name}======保存图片=======")with open(temp_path, "rb") as f:content = f.read()# print(f"{glyph_set_name}=====DdddOcr开始识别文字=======")dddd = ddddocr.DdddOcr(show_ad=False)text = dddd.classification(content)if os.path.exists(temp_path):os.remove(temp_path)return textif __name__ == '__main__':# glyph_set_name 就是上图中的name值  这样映射关系都对应上了res = ttf_to_char('tansoole.woff',glyph_set_name='gbreve')print(res)
3.映射数据

最后将上图代码流程已经结果字典映射对应就有了我们所看到的值,如图所示:
在这里插入图片描述


三、总结

在字体反爬的路还有很长的路要走,本文也是笔者一些经验和不成熟的见解,也欢迎跟各位大佬一起交流学习!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/87361.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/87361.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

DigitalOcean 携手 AMD 推出 AMD Instinct™ MI300X GPU Droplet,加速 AI 创新

近日,DigitalOcean(NYS:DOCN)作为全球最简单易用的可扩展云平台,宣布与 AMD 建立合作,为 DigitalOcean 客户提供 AMD Instinct™ GPU,以 AMD Instinct™ MI300X GPU Droplet 的形式支持其 AI 工作负载。此举…

小白畅通Linux之旅-----DNS项目实战配置

目录 一、项目要求 1、正反向解析配置 2、主从配置 二、脚本编写配置 1、主服务器脚本编写 2、从服务器脚本编写 三、项目检测 1、正反向解析检测 (1)主服务器脚本启动 (2)测试主机配置 (3)正反…

Codigger:探索数字工作新架构

在软件开发与数字工作领域,技术迭代的脚步从未停歇,开发者和系统管理员都在寻找更高效的工具和平台。Codigger 作为一项创新技术成果,凭借其独特的定位和架构,在行业内逐渐崭露头角。 Codigger “分布式操作系统”,它…

微信中 qrcode 生成二维码长按无效果的解决方案

引言 我们先来看这样一段代码 <divid"qrcode"ref"qrcode"class"bind-code-img"style"height: 180px;width: 180px;margin-top: 22px;display: none; "></div> new QRCode("qrcode", {width: 210,height: 210,t…

《网络安全与防护》作业复习

填空题 1. 网络数据库与数据安全专项作业 填空题解析&#xff1a; 数据库安全的“三大核心目标”是 完整性&#xff1b;保密性&#xff1b;可用性 解释&#xff1a;数据库安全的三个核心目标是确保数据的完整性、保密性以及可用性&#xff0c;即保护数据不被篡改、未经授权访…

【windows常见文件后缀】

文件后缀解释css层叠样式表&#xff08;Cascading Style Sheets&#xff09;&#xff1a;用于描述HTML或XML&#xff08;包括如SVG、XHTML等XML方言&#xff09;文档的呈现样式&#xff0c;控制网页的布局、颜色、字体等视觉效果。jsJavaScript&#xff1a;一种轻量级的解释型或…

labelme启动报错动态链接库DLL初始化例程失败

安装 pip install labelme启动 labelmewin11python3.12&#xff0c;pycharm venv 安装&#xff1a; pip install labelme&#xff0c;启动labelme报错&#xff1a; 降级numpy&#xff0c;降级onnxruntime pip install “numpy<2.0” pip install onnxruntime1.18.0 再次cm…

Mybatis(javaweb第九天)

Mybatis基础操作 占位符&#xff1a;#{变量名} 注意事项&#xff1a;如果Mapper接口方法只有一个普通类型参数&#xff0c;属性名可以随便写 > Preparing: delete from emp where id? > Parameters: 1(Integer) 预编译SQL 不会将值直接放在SQL语句中&#xff0c;而是…

C#开发MES管理系统源码工业生产线数据采集WPF上位机产线执行系统源码

该源码是实际生产线运行的实际项目&#xff0c;全套源码。适合开发者学习参考&#xff0c;有需要源码可以联系博主

`ngx_otel_module` NGINX OpenTelemetry 分布式追踪实战

1. 模块简介 ngx_otel_module 为 NGINX&#xff08;开源版 1.25.3&#xff0c;商业版 1.23.4&#xff09;提供了 OpenTelemetry&#xff08;OTel&#xff09;分布式追踪支持&#xff0c;能够&#xff1a; 自动采集 HTTP 请求的生命周期 Span上下文传播&#xff1a;兼容 W3C t…

Vue+TypeScript 枚举(Enum)的使用规范

在 TypeScript 中&#xff0c;枚举&#xff08;Enum&#xff09;的命名应遵循以下规范&#xff0c;这些规范结合了 TypeScript 官方建议和行业最佳实践&#xff1a; 枚举命名规范&#xff08;TypeScript/Vue 项目&#xff09; 基本命名规则&#xff1a; 使用 PascalCase&#…

一个完整的LSTM风光发电预测与并网优化方案,包含数据处理、模型构建、训练优化、预测应用及系统集成实现细节

以下是一个完整的LSTM风光发电预测与并网优化方案,包含数据处理、模型构建、训练优化、预测应用及系统集成实现细节: 风光发电功率预测与并网优化系统 基于LSTM的时间序列预测与储能协同控制 第一部分:系统架构设计(1200字) 1.1 整体技术路线 #mermaid-svg-U5pxzefmzZ4s…

如何在 MX Linux 上安装 Mint 的 Cinnamon 桌面 UI

如何在 MX Linux 上安装 Mint 的 Cinnamon 桌面 UI 你是否想在 MX Linux 上安装流行的 Linux Mint Cinnamon 图形用户界面?那么这里有一个教程…… Cinnamon 是一个类似 Windows 7 的界面,它默认安装在 Linux Mint 操作系统中。它使 Mint 非常易于理解和使用,这也是 Mint …

OpenStack 入门

目录 简介 一、云计算与 OpenStack 基础概念 1.1 云计算概述 1.2 OpenStack 简介 二、OpenStack 单机环境部署 2.1 环境准备 2.2 部署前准备工作 2.3 在线部署 OpenStack&#xff08;Train 版本&#xff09; 三、通过 Dashboard 部署 OpenStack 的功能 3.1 登录 Dash…

【Git】关于项目开发分支的使用规范

背景 在项目开发过程中&#xff0c;往往一个优秀的产品都会出现不断的版本迭代&#xff0c;我时常在项目发布后对于如何结合后续更新的业务场景在分支上的应用没有一个很好的办法&#xff0c;一直也比较苦恼。目前项目的迭代场景如下&#xff0c;一个A项目&#xff0c;经过需求…

msquic的windows版本编译

首先确保安装cmake和powershell&#xff08;需要6以上&#xff0c;本人升级到了7.5&#xff09;&#xff0c;vs&#xff08;本人用的vs2022&#xff09; powershell&#xff0c;默认是5&#xff0c;会编译不成功&#xff0c;所以附带一个升级的流程 $PSVersionTable.PSVersion …

批量文件重命名工具 OncePower ,永久免费!

软件介绍 适用于Windows OncePower是一款Windows批量重命名工具&#xff0c;支持基本及高级匹配重命名&#xff0c;无需复杂正则。特色包括匹配修改、长度截取、日期命名、前缀后缀修改及TXT文件导入。支持保留特定内容、批量移动文件和删除空文件夹。可保存设置&#xff0c;…

Python入门Day6.1:异常处理

一、什么是异常&#xff08;Exception&#xff09;&#xff1f; 异常是指程序运行过程中出现的错误情况。比如&#xff1a; 打开一个不存在的文件0作为除数列表索引越界类型转换失败 二、基本结构&#xff1a;try...except try:# 可能出错的代码 except 错误类型:# 出错时执…

C++中的标准模板(STL)

C中的核心标准模板包含&#xff1a;容器、迭代器、算法、函数对象、适配器。 1.容器 容器提供了各种数据结构&#xff0c;包括向量(vector)、链表(list)、队列(queue)、栈(stack)、集合(set)、映射(map)等&#xff0c;可以根据实际需求选择合适的容器。 容器分为三大类&…

excel 待办日历软件(需要宏)特别推荐

Excel待办日历软件是一款基于Excel表格的日程管理工具&#xff0c;能够帮助用户更高效地管理待办事项和日程安排。用户可以在软件中创建不同的任务列表&#xff0c;以便更好地进行管理和跟踪。软件还提供了日历视图&#xff0c;用户可以直观地查看和安排每日的任务&#xff0c;…