字体反爬,是一种利用 CSS 特性和浏览器渲染规则实现的反爬虫手段。其高明之处在于,就算借助(Selenium 套件、Puppeteer 和 Splash)等渲染工具也无法拿到真实的文字内容。

这种反爬虫手段通常被用来保护页面中的关键数据,例如影片票房、外卖平台的商家电话、汽车门户上的车型报价或者是电商平台上商品的属性和价格。

关于字体反爬虫的介绍、实现和原理可以参考书籍《Python3 反爬虫原理与绕过实战》,也可以通过搜索引擎查找资料,本篇文章不再赘述。

本篇文章要解决的问题,是如何让程序准确的识别那些用自定义字体代替的文字。

本文将围绕网站 aHR0cHM6Ly9tYW95YW4uY29tL2ZpbG1zLzEyMTgwMjk= 进行讨论,具体目标如下图:

显然,页面中的用户评分、累计票房等内容是关键数据,它们也正是爬虫工程师们想要的东西。虽然人类的眼睛看到的是 9.4、14.05,但在浏览器开发者工具中它们却是 .、.。9.4 对应的 HTML 代码为:

<span class="stonefont">.</span>

而网页源代码中,却是另外一番景象:

<span class="stonefont">.</span>

有经验的朋友一眼就看出来了,这是字体反爬虫的手段!没有经验的朋友,请去阅读《Python3 反爬虫原理与绕过实战》。

这种字体反爬虫的破解思路为:

获取相关 CSS 文件中 ttf 或 woff 字体文件,通过 python 的 fontTools 模块建立字体对应关系。

但是当你分析本文给出的案例时,却发现页面使用的字体是实时动态变化的,无法建立确定的对应关系。这跟Python3 反爬虫原理与绕过实战》中提到的反爬虫思路很相似,很棘手!

但庆幸的是,遇到的字体反爬手段和《Python3 反爬虫原理与绕过实战》中介绍的不是完全相同的,有些手段并没有用上,还好还好。

接下来,将介绍基于深度学习中最简单的K-近邻算法来破解这种实时动态变化的字体反爬措施。先说一下破解的步骤:

  • 将页面用到的字体文件下载到本地
  • 通过字体编辑器查看该字体文件
  • 观察字体文件随机动态的现象,并记录变化规律
  • 得出变化规律的规则

以本文给出的案例网站为例,首先在浏览器开发者工具的 NetWork 一栏找到页面加载的字体文件(通常是 WOFF 格式),并将问价下载到本地。然后用字体编辑器(例如百度字体编辑器)查看字体文件,如下图:

接着用 fontTools 库将 WOFF 格式的文件转换为 XML,并查看坐标变化规律。例如数字 6 对应的特殊字符为 uniF5DE,其对应的坐标值如下:

另一个字体文件中,数字 6 对应的坐标值如下:

经过多次测试发现:同一数字的对象虽然不同,但是区别甚微,对象中每个坐标的差值较小。这样我们可以通过限定对象的坐标值差值在一定范围内就可以认为是两个相同的数字了。

接下来采用机器学习最简单的方法KNN算法经过简单的训练,即可将坐标分类。

那么什么是KNN算法呢?

简单的说,K-近邻算法采用策略不同特征值之间的距离方法进行分类。

工作原理:

存在一个样本数据集合,也称作训练样本集,并且样本集中每个数据都存在标签,即我们知道样本集中每一数据与所属分类的对应关系。输入没有标签的新数据后,将新数据的每个特征与样本集中数据对应的特征进行比较,然后算法提取样本集中特征最相似数据(最近邻)的分类标签。一般来说,我们只选择样本数据集中前k个最相似的数据,这就是k-近邻算法中 k 的出处,通常k是不大于20的整数。最后,选择 k 个最相似数据中出现次数最多的分类作为新数据的分类。

基于上述介绍,可以先制作一个样本数据集合,样本数据集合如下:

即从 XML 文件中提取相关数字的坐标。通过 KNN 算法,对输入的字体的坐标进行计算,标记其标签:

def classifyPerson(font):
# 完整代码将在文末获得
pass

通过 KNN 算法标记标签后,即可通过 replace 方法对源代码文件进行替换:

fonts = {}
for i in base_list:
# 完整代码将在文末获得

这里随意选取了多个目标地址,并验证了其正确输出,本文案例对应的数据如下:

{"电影名称": "少年的你", "用户评分": "9.4", "评分人数": "95.2 万", "累计票房": "7.32 亿"}

至此,字体反爬的问题就解决了。

更多关于字体反爬的思路和研究请翻阅《Python3 反爬虫原理与绕过实战》,本文中还有一些重要观点未提及,建议翻书补齐知识。

完整代码请关注微信公众号爬虫工程师之家,并回复 20191029,即可获得代码仓库的链接。

本文参考:

公众号爬虫工程师之家的文章《基于K-近邻算法,破解CSS动态混淆字体》

韦世东的新书《Python3 反爬虫原理与绕过实战》

作者:华为云享专家 夜幕韦世东

k 近邻算法解决字体反爬手段|效果非常好的更多相关文章

  1. 使用K近邻算法改进约会网站的配对效果

    1 定义数据集导入函数 import numpy as np """ 函数说明:打开并解析文件,对数据进行分类:1 代表不喜欢,2 代表魅力一般,3 代表极具魅力 Par ...

  2. 02-16 k近邻算法

    目录 k近邻算法 一.k近邻算法学习目标 二.k近邻算法引入 三.k近邻算法详解 3.1 k近邻算法三要素 3.1.1 k值的选择 3.1.2 最近邻算法 3.1.3 距离度量的方式 3.1.4 分类 ...

  3. 第4章 最基础的分类算法-k近邻算法

    思想极度简单 应用数学知识少 效果好(缺点?) 可以解释机器学习算法使用过程中的很多细节问题 更完整的刻画机器学习应用的流程 distances = [] for x_train in X_train ...

  4. 机器学习实战 - python3 学习笔记(一) - k近邻算法

    一. 使用k近邻算法改进约会网站的配对效果 k-近邻算法的一般流程: 收集数据:可以使用爬虫进行数据的收集,也可以使用第三方提供的免费或收费的数据.一般来讲,数据放在txt文本文件中,按照一定的格式进 ...

  5. 从K近邻算法、距离度量谈到KD树、SIFT+BBF算法

    转载自:http://blog.csdn.net/v_july_v/article/details/8203674/ 从K近邻算法.距离度量谈到KD树.SIFT+BBF算法 前言 前两日,在微博上说: ...

  6. 1.K近邻算法

    (一)K近邻算法基础 K近邻(KNN)算法优点 思想极度简单 应用数学知识少(近乎为0) 效果好 可以解释机器学习算法使用过程中的很多细节问题 更完整的刻画机器学习应用的流程 图解K近邻算法 上图是以 ...

  7. 从K近邻算法谈到KD树、SIFT+BBF算法

    转自 http://blog.csdn.net/v_july_v/article/details/8203674 ,感谢july的辛勤劳动 前言 前两日,在微博上说:“到今天为止,我至少亏欠了3篇文章 ...

  8. Python爬虫入门教程 64-100 反爬教科书级别的网站-汽车之家,字体反爬之二

    说说这个网站 汽车之家,反爬神一般的存在,字体反爬的鼻祖网站,这个网站的开发团队,一定擅长前端吧,2019年4月19日开始写这篇博客,不保证这个代码可以存活到月底,希望后来爬虫coder,继续和汽车之 ...

  9. Python爬虫入门教程 63-100 Python字体反爬之一,没办法,这个必须写,反爬第3篇

    背景交代 在反爬圈子的一个大类,涉及的网站其实蛮多的,目前比较常被爬虫coder欺负的网站,猫眼影视,汽车之家,大众点评,58同城,天眼查......还是蛮多的,技术高手千千万,总有五花八门的反爬技术 ...

随机推荐

  1. nginx篇中级用法之反向代理(七层调度)

    环境: 两台后端web,一台代理服务器 web1:eth0:192.168.2.100/24   httpd做一个web web2:eth0:192.168.2.200/24   httpd做一个we ...

  2. CSPS模拟 97

    越来越弱了, 而且不如之前积极了,非常的颓废. 联赛前出现这种问题也是够我受的. T1 打表找规律失败.jpg 一直在找多项式规律,没找指数规律. T2 唉. T3 考虑到最多有n种颜色,考虑在线段树 ...

  3. 曹工杂谈:为什么很少需要改Spring源码,因为扩展点太多了,说说Spring的后置处理器

    前言 最近发了好几篇,都是覆盖框架源码,但是spring的代码,我是从没覆盖过,毕竟,如果方便扩展,没谁想去改源码,而spring就是不需要改源码的那个,真的是"对扩展开放,对修改关闭&qu ...

  4. Flash、RAM、ROM的区别

    一. ROM(Read Only Memory)    ROM(Read Only Memory),只读存储器.用来存储和保存数据.ROM数据不能随意更新,但是在任何时候都可以读取.即使是断电,ROM ...

  5. Java描述设计模式(19):模板方法模式

    本文源码:GitHub·点这里 || GitEE·点这里 一.生活场景 通常一款互联网应用的开发流程如下:业务需求,规划产品,程序开发,测试交付.现在基于模板方法模式进行该过程描述. public c ...

  6. Salesforce学习之路(十二)Aura组件表达式

    1. 表达式语法 在上篇文章组件属性示例中,新建了一个属性whom, 引用该属性时使用了表达式:{!v.whom},负责该属性的动态输出. 语法:{!expression} 上述示例中,我们的属性名称 ...

  7. lqb 基础练习 查找整数 (遍历)

    基础练习 查找整数 时间限制:1.0s   内存限制:256.0MB     问题描述 给出一个包含n个整数的数列,问整数a在数列中的第一次出现是第几个. 输入格式 第一行包含一个整数n. 第二行包含 ...

  8. nyoj 773-开方数 (pow)

    773-开方数 内存限制:64MB 时间限制:1000ms 特判: No 通过数:3 提交数:8 难度:3 题目描述: 现在给你两个数 n 和 p ,让你求出 p 的开 n 次方. 输入描述: 每组数 ...

  9. SpringBoot 源码解析 (七)----- Spring Boot的核心能力 - 自定义Servlet、Filter、Listener是如何注册到Tomcat容器中的?(SpringBoot实现SpringMvc的原理)

    上一篇我们讲了SpringBoot中Tomcat的启动过程,本篇我们接着讲在SpringBoot中如何向Tomcat中添加Servlet.Filter.Listener 自定义Servlet.Filt ...

  10. 领扣(LeetCode)翻转二叉树 个人题解

    翻转一棵二叉树. 示例: 输入: 4 / \ 2 7 / \ / \ 1 3 6 9 输出: 4 / \ 7 2 / \ / \ 9 6 3 1 备注:这个问题是受到 Max Howell的 原问题  ...