“知物由学”是网易易盾打造的一个品牌栏目,词语出自汉·王充《论衡·实知》。人,能力有高下之分,学习才知道事物的道理,而后才有智慧,不去求问就不会知道。“知物由学”希望通过一篇篇技术干货、趋势解读、人物思考和沉淀给你带来收获的同时,也希望打开你的眼界,成就不一样的你。当然,如果你有不错的认知或分享,也欢迎在“网易易盾”公众号后台投稿。
随着互联网开放式、爆发式地增长,数据的价值变得越来越重要,尤其是电商、传媒、社交等等业务,将数据比作黄金也不为过。因而随之诞生了网络爬虫技术,黑客通过调用网站开放的免费接口来批量获取有价值的数据,用以数据挖掘和分析行业状况等。然而大量的非法爬虫会造成网站服务器压力巨大,甚至影响正常用户的访问;而且有价值的数据被窃取,也会对网站的商业利益造成负面影响。
因此反爬虫技术应运而生。反爬虫技术大体包含“爬虫识别”和“爬虫反制”两个步骤,后者主要是用于对前者识别出的爬虫出的爬虫进行惩罚和反制,主要包括限制访问、验证码校验、数据投毒等等,本文不做深究。而前者目前常用的方式是基于规则判断。比如以某个用户或者IP为单位,统计其在一定时间内的访问记录,然后用人为设定的一些阈值,这种可以称为专家规则方法。其优点是规则明确、可靠,可以实时针对发现的爬虫特征来设定规则,从而实现与爬虫对抗。
但是它也有明显的缺点:
- 强依赖运营的经验,规则和阈值难以凭空设定;
- 与爬虫对抗依赖人为观察爬虫的特征;
- 当规则越来越复杂且数量庞大时,规则引擎的效率会越来越低,成本会比较大。
由于上述原因,我们结合了两项热门的技术:大数据和机器学习,来探究其在爬虫识别中的应用。
一、基于Flink的大数据统计
首先我们需要通过一些大数据技术来获取统计数据。Flink是一个新兴的分布式大数据流处理引擎,本文不做详细介绍,只是利用了其基于事件时间窗口统计数据的功能。
流处理过程主要包含以下步骤:
Flink流处理过程
- 数据源:我们的数据源是业务网站吐出的Nginx访问日志,保存在kafka队列中。
- 预处理:按照数据源中的数据格式,将访问日志中有用的字段解析出来,主要是Timestamp、IP、URI、Htpp_User_Agent等。
- 维度聚合:利用Flink的keyby功能,将同一IP的数据汇总起来。
- 时间窗口:利用Flink的Window功能,把Timestamp处于某一时间窗口内的数据汇总到一起。我们采用的是滑动窗口的方式,统计15分钟之内的数据,每1分钟滑动一次。
- 统计:通过以上两步,我们每1分钟结束,都能获得每个IP在前15分钟内的所有访问记录。我们对这些数据进行进一步统计,得到的数据以Json形式写入到Kafka,格式如下图
Flink输出数据
字段含义:
- Timestamp:窗口结束时间的时间戳;
- IP:该数据所属的IP;
- Sum:该IP在时间区间内的总访问次数
- URI:该IP在时间区间内访问的URI的具体统计
a)counts: 是一个map,key是所访问的URI,value是访问计数
b)count: counts中不同key的数量
c)sum: counts中所有value的和
d)min: counts中所有value的最小值
e)max: counts中所有value的最大值
- Http_User_Agent:该IP在时间区间内访问记录所使用的User Agent的具体统计。内部的counts、count、sum、min、max与URI中的类似
- 其他还有一些字段如http_referer、status、params、http_version等也类似,不再一一列出。
二、数据的特征提取
要利用机器学习的算法来实现爬虫的判断,首先要将原始数据转化为向量,向量中的维度数据要尽量包含数据的特征,这样才能尽可能地区分爬虫和正常记录的差异。
通过观察发现,爬虫记录与正常记录相比,主要有以下特征:
- 访问总计数sum偏高;
- 每个URI的访问计数较高;
- 访问的URI比较集中,通常只访问特定的几个URI,而且可能呈现一定的比例;
- 访问所用的User Agent比较单一;
- 每个User Agent的计数都很接近;
针对以上特征,我们用以下维度来组成数据的特征向量:
- 普通维度:这些维度是直接采用原始数据中的统计量,比如sum、URI.count、URI.max、URI.min、http_user_agent.count、http_user_agent.max、http_user_agent.min等等
- 方差维度:考虑到URI、http_user_agent等字段的不同取值的分布情况也是重要的特征,把counts中value的方差也作为特征维度
- 订制维度:业务方对其URI分布有一定的了解,可以对URI.counts中的数据做一个二次统计,产生一些订制维度。比如把key匹配正则表达式“^/api/v\\d+/products/.*”的记录的value相加,来作为一个新的特征维度。同样的也可用http_user_agent.counts中的数据产生订制维度
三、线下分析
我们采用神经网络算法,该算法的优点是: 技术成熟、适应性强、工程化容易、可移植性强等等。但是它是一种有监督学习,需要有一批训练数据才能工作。
3.1 训练数据获取阶段:
获取训练数据的思路有两种:
- 3.1.1 借助规则引擎法:我们已经拥有一个规则引擎,可以用它配置一些简单的规则,然后把规则引擎判断出的结果作为标记,和原始数据一起作为训练集数据。这种方法的优点是简单、直观;且规则越复杂,则相应训练出来的模型也越优秀,区分爬虫的能力越强。但是缺点也是很明显的,因为依赖了规则引擎,所以也继承了规则引擎的弊端,要创建合适的规则比较困难,而且学习后的模型也只是能起到和规则引擎一样的效果,无法识别更多特殊的异常。所以该方法必须要搭配数据反馈和模型进化,才能使模型更加智能。
- 3.1.2 人工标记法:这也是一种常见的获取训练集的方式,训练集越完备,数据代表性越好则训练出来的模型越优秀。但是该种方法最大的缺点是工作量巨大,面对海量的大数据,我们不可能做到一一标记,因此这种方法的难点就在于如何高效地获取有效数据。
我们采用的方法是基于PCA+Kmeans的无监督学习算法,大概步骤如下:
- 先采样一批提取完特征的数据作为输入
- 对原始的特征数据做PCA主成分分析,通过线性变换获得方差最大的几个主成分维度,作为新的、降维后的特征向量,这一步是为了提取特征向量中的有效成分,去除无用信息
- 对降维后的数据采用Kmeans算法进行聚类,得到若干个类别,并且对每条数据标记类别号
- 对于每类数据,抽取最有代表性的若干条数据,人为分析对应的原始数据,判断是否为爬虫,然后计算抽取数据中爬虫的比例。如果比例超过一定阈值,则将该类标记为爬虫;如果比例小于一定阈值,则将该类标记为正常;比例在上下阈值之间的做对类内数据做进一步聚类,再做类似的判断
- 用类别的标记来标记类内的每条数据,得到了带标记的训练数据集
- 这种方式需要在效果和工作量之间做取舍。当然也可以搭配数据反馈和模型进化,使模型表现更好。
3.2 模型构建和训练阶段
使用Pytorch搭建神经网络模型。可以分批、多组地用同一批数据反复训练模型。 当达到一定的迭代次数,或者损失函数小于一定阈值,则表示模型训练完毕。可以将模型参数文件导出,供线上部署。
一个简单的单层神经网络例子
训练过程
在测试集上的测试结果
四、线上部署
模型引擎的线上部署如下图所示。Training模块负责数据的线下处理和训练,训练完的模型文件上传至Nos,然后将模型的配置信息以及模型文件的地址写入Etcd。Model Engine模块是线上的模型引擎,实时监听Etcd中额配置,当配置更新时,会立即拉取模型文件,并加载。
Model Engine会消费Flink统计完写入Kafka的数据,并用模型做爬虫判别,并将判别的结果写入数据库,供其他系统查询使用。
线上部署架构
五、模型进化
到此我们已经搭建了包含数据采集、线下训练、线上部署的模型引擎架构,但是正如前面所说,目前的模型只能达到与规则引擎相近的效果,要想让模型进化得更为智能,必须加入反馈机制,使得模型能够进化。
反馈的思路是从模型引擎的输出数据入手。神经网络分类算法的输出数据,除了包含记录是否属于爬虫的判断,还包含是否属于爬虫的概率。可以根据概率分为三段:非爬虫:0~33%、疑似爬虫:33%~66%,爬虫:66%~100%。
对三段抽样进行人工分析:
- 非爬虫、爬虫段:抽取少量数据,检查是否有误杀和漏杀;
- 嫌疑段:抽取大量数据来重点分析,判断是否为爬虫;
将分析完的数据作为新的训练集,对原来训练好的模型进行增量训练,使模型在保留部分历史经验的情况下获取新的特性。这一步当然也可以结合一些别的增量学习、迁移学习以及强化学习的算法来实现。
相关阅读:
来源:oschina
链接:https://my.oschina.net/u/4223303/blog/3159002