You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

158 lines
17 KiB
Markdown

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 11反爬虫概述前端反爬虫是怎么做信息收集的
你好我是DS Hunter。
上一讲我们已经了解了前端反爬虫中最主要的动作key的加密但是除了这件事前端还可以完成更多的细节来辅助整个反爬虫动作。
例如信息收集它们虽然不会直接完成“拦截”的动作看起来也没有什么贡献但是对于工程师的生存以及“拦截”动作本身的指导和优化来说却有着不小的辅助功能。最后我们会把key的加密、信息收集这一切都聚集到规则引擎中统一收口。
这一讲,我们就把目光聚集在信息收集以及规则引擎这两大辅助部分,完成前端反爬虫的主要工作。
## 信息收集
我在[01讲](http://time.geekbang.org/column/article/480101)中,就强调过信息一直是战争的核心,而信息收集是反爬虫的重中之重。公司有爬虫的需求,是希望在信息战中取得胜利,进而赢得商业的战争。而反爬虫方“收集信息”需求的产生,是由于工程师们想在反爬虫这场战争中打赢。
那么,到底要收集什么信息、怎么收集信息呢?后续我们又要怎么利用这些信息呢?我们按照反爬虫的动作顺序,先从信息预收集的部分开始说起。
### 信息预收集
在信息预收集模块,我们需要收集用户特征用于分析,而收集这些信息的方法,都可以认为是收集模块。当然,因为用户特征信息会被送到服务端进行分析检测,所以这里我们收集了哪些数据,应该是一个秘密,尽可能让爬虫方不知道才好。这和后面我们提到的“埋点统计分析”中的普通埋点是不同的。普通埋点,不怕爬虫方知道。
我们在[《05通用且基本的检测规则》](http://time.geekbang.org/column/article/483022)里面说到的浏览器特征以及业务特征,其实都是前端的用户特征检测点。这里,我们主要聚焦在技术方面的浏览器特征分析。
浏览器特征核心其实就是DOM指纹。我们都知道DOM是一棵树所以每个节点都可以通过XPath来访问到。同时还有一部分对象放在了BOM上面也就是通过window来直接访问。那么具体的访问方式是什么呢我来帮你回顾一下。这里我们先规定一下虽然浏览器BOM和浏览器DOM是两个东西但是访问方式都差不多在下面同时出现的时候我们统称DOM了。虽然这样在学术上不正确但是其实并不影响我们交流。
window是我们整个DOM对象的根节点我们从这里出发理论上可以到达DOM对象的任何一个节点。理论上说我们也可以用Xpath来访问任意一个DOM节点。部分BOM对象即使不可达我们也可以仿照XPath给BOM做一个类似的定位符来标记访问信息。这样我们从window出发就可以遍历所有的对象了。
但是要注意的是整个树是存在循环引用的我们为了避免递归调用死循环必须进行重复节点检测。这个具体做法就不demo了检测重复节点可以说是经典面试题了属于基操。
当然我们不但可以通过上述的过程拉取整个window对象的信息还可以进一步进行特征提取例如取window对象的MD5——当然记得加盐直接取MD5很容易被猜出来。
我们还可以指定部分的XPath然后让这部分节点聚合在一起成为一个对象在浏览器端进行特征提取。这样我们就可以拿到一个用户指纹了。这个指纹可能防冲突并不好但是伪造难度也并不低。
我们之所以这么费事,非要提取一个指纹出来,而不是直接把信息上报,有以下几个原因:
1. **被破解几率低:**直接上报很容易被抓,而且因为是明文的,对方一旦知道了逻辑,伪造难度就下降了。
2. **保密程度高:**指纹是加盐的因此相同的信息其实上报的key是不一样的。但是服务端知道原始key是什么虽然MD5不可逆但是可以通过已有的key进行再运算。至于盐的上报可以夹杂在MD5结果里。不一定是insert也可以是replace因为少验证几位没什么大事。
3. **速度快、压力小**:获取指纹之后,传输数据量会大大降低。这样一方面能提升速度,一方面能降低服务器压力。
### 误伤统计收集
误伤统计收集则与普通信息不同。如果说信息预收集,信息来源是用户产生的,后面的埋点信息是反爬系统产生的,那么误伤统计则是一个中间地带。因此,信息预收集需要强加密,埋点统计需要弱加密,而误伤统计则落于两者之间,可以随意选一个加密强度。**当然了,这里的所有强、中、弱都是相对而言的,每一个部分的信息都至关重要。**
我们在[09讲](http://time.geekbang.org/column/article/486912)提到的误伤统计理论中讲过一个“打点法”也就是客户端每次访问写入一个Cookie然后在订单之类的页面进行拦截。这一讲的误伤统计收集同样使用这个方法。不过这一讲我们会就它的加密强度来讨论。由于拦截的过程中是直接读取Cookie的那么加密主要就是放在写Cookie的地方了。
低级别的加密是在Cookie里加入用户信息。再升级就可以增加不可逆加密以服务端有办法鉴别有效性为标准。注意我们提到不可逆加密的时候有的朋友经常认为不可逆加密就是不可逆的所以客户端肯定不能用但其实这是错误的想法。
如果在服务端验证时,我们的需求是解密出来的,那不可逆加密当然很难使用。如果我们只是鉴定它是否有效,或者已知入参是有限的,那么就可以使用不可逆加密了。
误伤统计收集与埋点不同,这个不会有高并发——如果有高并发岂不是你的误伤已经血流成河了。因此不用担心高并发无法处理的事情。
不过,如果出于谨慎考虑,也可以做一个熔断:当系统承接不了网络流量时,直接断掉误伤统计,同时熔断掉反爬需求即可。此外,还可以做成更谨慎的:反爬虫默认是断掉的,误伤统计系统定期给爬虫系统充值时间,这样一旦误伤统计系统跪了,反爬虫系统会自动回到默认值,也就是关闭状态。
### 埋点统计分析
如前面所说,埋点信息是非关键信息,因此可以不用特别强的加密。可能你会问:埋点统计是弱加密,那么,无加密不行吗?
答案是埋点统计可能也会被抓取也就是爬虫可能爬取埋点来影响你的统计和决策。不过由于要得到这个效果的过程是很漫长的所以大部分爬虫也不会死磕埋点。URL本身不可能被加密所以加密的就只有报文了。当然弱加密只是相对而言如果你的对手真的死磕你的埋点你也可以提升加密等级这个不能认死理。
那我们就来看看,埋点信息埋什么呢?这里主要分这么几类:
第一类,常规用户访问数据;
第二类,爬虫访问数据,包括爬虫类型,来源,数量,等等;
第三类部分测试策略的线上效果收集。这个在13讲会详细说明
**有了这些数据之后我们以后做效果检测或者说制作ROI报表就容易了很多。**严格来说埋点统计算是BI的一部分虽然只是出了几个报表。
实际上,这类报表的汇报意义远远大于实际意义。我在前面说过,我们的系统做了实时的熔断、实时的监控,因此埋点通常只是一些统计数据,用来衡量业务指标的。
但是要注意,汇报也是工作的一部分。在进阶篇的时候我们会提到相关技巧。
例如所有项目都要汇报ROI反爬也不例外。没有ROI支撑的项目光靠理想是活不下去的。而ROI的来源就是这些埋点数据。
* **埋点统计的痛点**
排除掉加密信息这个点之后,**埋点信息有几个最大的痛点:并发压力,数据存储压力以及读取速度。**
因为通常来说,这三样同时实现,几乎是不现实的。因此如果必须舍弃一样的话,我们会**选择舍弃读取速度。**因为如果能砍掉产品经理提出的“实时查看爬虫状态”这种无意义的需求的话,我们就可以完成这一切了。为什么说这个需求是无意义的呢?因为实时爬虫状态对于做出决策没有任何价值。有爬虫,系统拦截即可;无爬虫,系统运行即可。看得到,看不到,对公司没有任何影响。
这个主要的影响反倒是在技术侧,技术如果发现误伤较高,系统又没有自动熔断,那么需要手动熔断。当然,这个在误伤统计收集里面就做掉了。而误伤统计本身又没有高并发问题,相当于砍掉了并发压力,来实现需求。
最后怎么砍掉这个需求呢也是有技巧的你凭空砍掉产品经理一个需求严重影响他的KPI这是他难以接受的也必然会与你发生争议。而你给他换个需求就像上面一样把埋点监控换成误伤统计监控他能给老板交差了也就自然不会和你死磕。
* **埋点统计的实现方式**
因此我们的实现方式就很好理解了前端使用大量Server换取网络链接数同时聚合数据避免冲击后端收集模块。后端使用常规的高写入速度、低读取速度的存储方式来承接即可。大公司通常有成熟的系统但是小公司往往没有这个模块需要自己来实现。
读取数据的时候,因为是高写入速度、低读取速度,我们的读取速度用来换高并发和写入速度了,那就意味着不可能实时查看。而上面我们已经和产品砍掉了实时查看的需求,那么我们的查看方式就只有每日报表这一种了。**实际上,每日一次的报表足够使用了,如果真的有比较实时的要求,撑死也就是一个小时,再高就没有实际意义了。**
低读取速度的存储,应对一小时一次的读取,也是没有任何压力的。这个完全不用担心。
## 规则引擎
综合上一讲说到的key的加密以及这一讲的信息收集、埋点统计分析你可能意识到了一个问题我们线上需要大量的变更而变更就要发布发布就有流程。但是爬虫不等人等你变更发布完可能一天过去了爬虫都走人了。所以**我们需要一个能够实时变更生产规则的系统。这个系统,我们就称为它规则引擎。**
那么在反爬虫这个case里**规则引擎有三个主要构成部分,分别是信息收集模块、规则判断模块以及规则执行模块。**其中规则判断一般是在服务端或者BFF实现的而信息收集和规则执行都会在前端执行。因此我们主要来看这两点。
首先看信息收集模块的设计。
严格来说,**信息收集模块是流程的起点,因此对于状态机而言它没有前置状态。**
如前面所说,客户端收集的信息,会在客户端进行加密,然后传输过来,那么就可能是可逆加密与不可逆加密两种情况。因此,这里可能会有解密,也就是说会使用到对称加密架构,但也可能没有解密却有验证模块,这就会使用到不可逆加密了,不过这样做的缺点就是可能会丢失细节。
此外,**规则执行模块,这里依然取决于你面临的状况。**
有的系统针对反爬虫是无脑拦截的那么前端无需做什么事情针对服务的拦截响应做一个友好的兼容处理即可。但是有的系统设计比较重前端会进行很多操作比如前面提到的Cookie等等。这个时候规则引擎不再是状态机这里是纯粹的rule。客户端只要写rule的解释逻辑即可。
这里需要注意的是服务端如果增加了rule可能导致客户端不兼容需要考虑热更新的情况。例如服务端增加了ruleCDN也发布了但是客户已经几天没刷过页面了用的还是三天前的js代码。这时候需要考虑做客户端版本容差单独拉取rule规则执行。
最后,针对规则引擎部分,我们可以做个总结。其实面对“不等人”的爬虫,规则引擎存在的主要作用有四点:
第一,降低发布时间,提升响应速度。
第二,降低研发成本,避免每次都写代码变更。
第三,提升灵活性,更敏捷的对爬虫做出反应。
最后,基于规则而不是基于代码片段特性,可以降低出错的概率。
那么到这里,前端,这个反爬虫的主战场,能够做的事情就已经介绍完了。
## 小结
最后,我来给你做个总结吧。这一讲,我们讲解了前端的辅助工作,信息收集以及规则引擎。
信息预收集本质上相当于游戏里面的插眼帮助你有更好的视野来进行决策。但是我们都知道不能把眼镜插在太明显的地方否则很容易被人排掉这就是加密的意义所在。而完成预收集之后就是我们在上一讲一直讨论的key加解密以及混淆的过程了。
接着,在反爬虫动作完成后,不论是出于对效果的检测还是对自己的保护,我们都会进行误伤统计以及埋点统计的分析.。由于这个数据会用于复盘,对自己的决策十分重要,因此如果被爬虫知道了,他们一定会爬这个埋点统计接口来干扰你。所以,这个加密程度也可以根据情况适当调高一些。
最后,规则引擎帮助我们快速响应变化,避免贻误战机。
以上,前端反爬虫的所有动作,就算完成了。在文字的下方,我也为你准备了一张前端反爬虫的完成动作图,希望帮助你理解这两讲的关系。
![](https://static001.geekbang.org/resource/image/96/67/9615fc9103acc1f387689yyfa4736c67.jpg?wh=9000x4633)
## 思考题
好了,又到了愉快的思考题时间。还是三选一的老规矩,你可以任选一个问题在留言区和我一起讨论。
1. 规则引擎本质上跳了生产发布,而制定生产发布流程是为了降低线上变更风险。那么,如果测试质疑你在引入风险越过测试权限,如何回应呢?
2. 理论上说信息收集是越多越好的,但是过多了又会对系统造成较大的压力。那么如何评估需要收集哪些数据呢?
3. 收集的数据里不能包含用户隐私数据, 否则可能有法务风险,尤其是跨国项目。 那么, 如何保证自己收集的数据不会不小心包含用户隐私呢?
期待你在评论区的分享,我会及时回复你。今天诗句的下方,也有关于规则引擎的实现方式——状态机的探讨,如果你有精力,也可以和我一起在评论区讨论。反爬无定式,我们一起探索。
![](https://static001.geekbang.org/resource/image/ca/e3/ca394872a645a4b54fd19fd9baa039e3.jpg?wh=1500x1615)
## 规则引擎的实现方式:状态机
有些课程可能会用状态机这个词,其实规则引擎和状态机基本是一个意思。确切来说,大部分规则引擎是用状态机实现的。没做过的人可能觉得状态机这个词有点高大上,但是说穿了,状态机也不是什么神秘的东西。
现在正好是年初也许你正在刷题准备面试那么你一定会做到DP相关的题目所有题解都会和你说DP的核心是找到状态转移方程。注意这个词状态转移。这个词虽然是讲解DP的但却非常清晰地描述了**状态机的核心:状态,以及转移。**状态state名词转移也就是action。你的系统能支持这两个事情基本足够了。
简单地说你的系统存在各种节点state在每个state下根据不同的条件可以进入另一个状态。也就是action。
有了状态机,就可以实现任意的流程图。这是规则引擎的重要作用。实际上,我们写的很多代码,本质上只是在写流程,例如流量进来,进行规则判定,根据判定结果,进行不同的处理。看起来是代码逻辑,但是抽象一下,这就是流程。看起来是流程,但是再抽象一下,就是状态机。因此有了状态机,就可以任意实现流程变更,而不需要发布了。因此,能大大节约时间,提升灵活性,降低出错概率。
状态机可能在服务端执行也可能在BFF执行这取决于公司的架构。当然要尽量适应公司架构而不是去改变架构因为反爬并非一个高ROI项目不具备这样的实力。如果公司没有BFF那就老老实实在服务端做就可以了。