开发者学堂课程【大数据实战项目:反爬虫系统(Lua+Spark+Redis+Hadoop 框架搭建)第三阶段):数据预处理-单程往返-代码实现及效果】学习笔记,与课程紧密联系,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/671/detail/11659
数据预处理-单程往返-代码实现及效果
内容介绍:
一、代码编写
二、代码执行
一、代码编写
第一步,将数据用问号进行拆分。现在的代码里面实现的是单程和往返。
package
com.air.antispider.stream.dataprocess.businessprocess
//用于交现返程-往返标签
object TravelTypeclassifier {
//实现打单程往返标签
def classifyByRefererAndRequestBody( httpReferrer:
string : Unit = {
https://b2c.csair.com/B2C40/newTrips/static/main/page/booking
/index.html?
t=R&c1=CAN&c2=PEK&d1=2019-05-16&d2=2019-05-16&at=1
&ct=0&it=0
}}
方法里面的数据也就是 httpReferrer 已经有了。在这里面对它用问号拆分,拆分之前要判断一下有没有问号。上面的数据里是有问号的,但是如果没有问号的话就不进行拆分,所以再这里要做一个判断。代码如下:
if (httpReferrer.contains("?") && httpReferrer.split( regex =
“\\?").length>1){
}
如果我的数据包含问号,并且这个数据用问号切分后它的长度(length)大于一。这样才能得到需要的数据。获得这个数据后依然是去切分,切分完以后下角标为一的就是第二个数据。代码:httpReferrer.split( regex = “\\?")(1)
第二步是在第一步的基础上,对数据用&进行切分,代码:
//2在第一步的基础上,对数据使用”&”进行切割,获取切割后的所有数据val params =httpReferrer.split( regex =
“\\?")(1).split( regex =“&")
上节课中用&切分后的数据:
//t=R&
//c1=CAN&
// c2=PEK&
//d1=2019-05-16&
//d2=2019-05-16&
//at=1&
//ct=0&
/ /it=0
这里面一共有8个参数,所以对于多个参数要进行一个接收,也就是用“&”切分可能会有多个值,现在要拿到这些参数的集合。
第三步,遍历每一个数据。用 for 进行遍历。遍历的时候,前面的 param 用来接收,等遍历了每个数据以后用等号切分,切分完以后做一个接收,
//3遍历每一个数在使用“=”进行切割,获取切割后的第二个数据
for(param<-params){
val param.split(“=")
切分完以后可能会有一个 K 和一个 V 。给它定一个变量名字就叫做
keyAndValue?
val keyAndValue = param.split( regex = “=")
切分完以后再来判断,现在已经拿到了第二个数据,所以再做一个判断,如果这个数据切分完以后它的点大于一,那取下标为一的也就是第二个值,如果第二个值匹配(match)我的正则表达式,下面是判断匹配的代码:
//4用第三步的数据匹配日期的正列
if (keyAndvalue.length>1 && keyAndvalue(1).matches()){
}
第四步,数据数据与正则表达式匹配。
下面是一个日期格式的正则表达式:
valregex = "^(\\d{4})-(0\\d{1}/1[0-2])-(0\\d{1]][12]\\d{1]}[3[01])$"
第五步,用之前数据去匹配这个正则。如果匹配上了那就把定义的计数器进行一个加一的操作。
现在还没有计数器,所以,下面来实例一个计数器:
//实力计数器 实现记录日期格式的数据出现的次数
var dateCounts=0
这里用 var 是因为 var 可变,后面需要它可以变化。数量 Counts 默认等于零,然后如果匹配了一次,就让它来做一个加一的操作。也就是说如果数据的长度大于一并且第一个下角标为一的数据与正则表达式匹配,计数器就加一。这样就完成了计数器的实现。
第六步,根据日期格式出现的次数,返回数据。
根据前面计算出来结果来返回值。如果这个值等于零,就表示一次都没有匹配上。也就是没有日期格式的数据,那么表示为其他。同样然后一个就是单程两个就是往返。
前面提供了一个参数 Traveltype 用来表示单程,往返,其他。
package com.air.antispider.stream.dataprocess.constants
//标记往返类别0-单程,1-往返,-1-其他
object travelTypeEnumextends Enumeration {
type TravelTypeEnum = value
/ /这里仅仅是为了将Enumration.value的类型暴露出来给外界使用而已
val oneway = value(0)
val RoundTrip = vaiue(1)
val unknown= value(-1)
}
实例一个表示最终数据业务类型的变量:它的类型是枚举类型。
//实例表示最终数据业务的类型变量
val travelType:TravelTypeEnum=null
所以这个 traveltype 是枚举类型。默认给他一个null,用来他来进行接收。
代码为:
根据计数器的值返回数据(Oneway ,RoundTrip, Unknown )
if(datecounts==0){//一个日期格式的数据都没有 其他
travelType=TravelTypeEnum. unknown
上面显示红色是什么意思?在这里面将 val 改成 var 即可。这样
就不会报错了。
var travelType : TravelTypeEnum=null
那么如果日期(dateCounts)等于零,也就是没有出现一次的时候,那么就表示其他,同时还有等于一跟等于二的情况。按这个顺序,等于一的时候就表示单程,出现一个日期格式的数据;等于二的时候就表示往返,出现两个日期的格式。那这个就处理好了,处理好以后把这个值返回。
具体代码如下:
//根据计数器的值返回数据(Oneway ,RoundTrip,unknown)
if(datecounts==0){//一个日期格式的数据都没有 其他
travelType=TravelTypeEnum. Unknown
}else if (datecounts==1){//出现1个日期格式的数据 单程
travelType=TravelTypeEnum.Oneway
}else if (datecounts==2){//出现2个日期格式的数据 往返
travelType=TravelTypeEnum. RoundTrip
}
travelType}
}
到这里,这个方法就写完了。
首先,用问号去拆分、问号拆分完以后再用与字符&拆分、与字符&拆分完以后再用等号拆分。拆分完以后用等号的第二个数据去匹配正则表达式。每匹配上一次,就用计数器进行一次加一操作。然后再根据计数器的数量来判断:零次就是其他,一次就是单程,两次就是往返。然后再实例一个枚举,里面是单程、往返还是未知,把它返回就行了。
这个方法写完以后,回到调用程序当中,也就是 Dataprocess 里面,这个是我们单层还是往返的一个实现,然后在这里用一个变量来进行接收。
val
travelType=TravelTypeClassifier.classifyByRefererAndRequestBody(httpReferrer)
看一下数据类型:val travelType:TravelTypeEnum = travelType
发现它是枚举的数据类型。
前面也要添加上这个数据类型。
//实现打单程往返标签
def classifyByRefererAndRequestBody(httpReferrer:
String): TravelTypeEnurl ={
//5-2单程/往返
val
travelType:TravelTypeEnume=TravelTypeClassifier.classify
BynefererAndRequestsody
(httpReferrer) travelType
然后进行返回。
二、代码执行
接下来执行一下这个代码,看看是不是想要的效果。
看一下 referrer 的日期数量,从代码里面能看出日期数量只有一个(getGoTime())
name:"Referer",
value:"http://b2c.csair.com/B2C40/modules/bookingnew/main/flightselectDirect.html?t=S&c1=CANBc2=AUH&d1= +getFoTime()+“&at=1&ct=0&it=0");
在默认情况下,如果只有一个日期,那它就是单程。实际看一下效果,如下图:
输出的是 OneWay 也就是单程,所以得到的结果是正确的。
总结:
1、使用问号“?”对数据进行切割,获取切割后的第二个数据
httpReferrer.contains("?") && httpReferrer.split( regex = "\
\?").length>1
2、在第一步的基础上,对数据使用”&”进行切割,获取切割后的所有数据
val params =httpReferrer.split( regex =
"\\?")(1).split( regex ="&")
3、遍历每一个数在使用“=”进行切割,获取切割后的第二个数据
val keyAndValue = param.split("=")
4、用第三步的数据匹配日期的正则
5、匹配成功计数器加一(计数器用于记录日期格式的数据出现次数)
If(keyAndvalue.length>1 &&
keyAndValue(1).matches(regex)){
//5匹配成功计数器加一(计数器用于记录日期格式的数据出现次数)
dateCounts+=1
}
6、根据计数器的返回数据(OneWay,RoundTrip,Unknown)
if(datecounts==0){//一个日期格式的数据都没有 其他
travelType=TravelTypeEnum. Unknown
}else if (datecounts==1){//出现1个日期格式的数据 单程
travelType=TravelTypeEnum.Oneway
}else if (datecounts==2){//出现2个日期格式的数据 往返
travelType=TravelTypeEnum. RoundTrip
}