网站点击流数据分析


网站点击流数据分析项目业务背景

什么是点击流数据

WEB访问日志

即指用户访问网站时的所有访问、浏览、点击行为数据

日志的生成渠道:

  • 是网站的web服务器所记录的web访问日志;

  • 是通过在页面嵌入自定义的js代码来获取用户的所有访问行为(比如鼠标悬停的位置,点击的页面组件等),然后通过ajax请求到后台记录日志;这种方式所能采集的信息最全面;

  • 通过在页面上埋点1像素的图片,将相关页面访问信息请求到后台记录日志;

日志数据内容详述

在实际操作中,有以下几个方面的数据可以被采集:

  • 访客的系统属性特征。比如所采用的操作系统、浏览器、域名和访问速度等。

  • 访问特征。包括停留时间、点击的URL等。

  • 来源特征。包括网络内容信息类型、内容分类和来访URL等。

  • 产品特征。包括所访问的产品编号、产品类别、产品颜色、产品价格、产品利润、产品数量和特价等级等

点击流数据模型

点击流这个概念更注重用户浏览网站的整个流程,网站日志中记录的用户点击就像是图上的“点”,而点击流更像是将这些“点”串起来形成的“线”

点击流数据是由网站日志中整理得到的

点击流模型生成

点击流数据在具体操作上是由散点状的点击日志数据梳理所得,从而,点击数据在数据建模时应该存在两张模型表(Pageviews和visits)

JaZcUU.png

这就是点击流模型。当WEB日志转化成点击流数据的时候,很多网站分析度量的计算变得简单了,这就是点击流的“魔力”所在。基于点击流数据我们可以统计出许多常见的网站分析度量

网站流量数据分析的意义

网站流量统计分析,可以帮助网站管理员、运营人员、推广人员等实时获取网站流量信息,并从流量来源、网站内容、网站访客特性等多方面提供网站分析的数据依据。从而帮助提高网站流量,提升网站用户体验,让访客更多的沉淀下来变成会员或客户,通过更少的投入获取最大化的收入.

终极目标是:改善网站(电商、社交、电影、小说)的运营,获取更高投资回报率(ROI)

技术上

  • 辅助改进网络的拓扑设计,提高性能

  • 在有高度相关性的节点之间安排快速有效的访问路径

  • 帮助企业更好地设计网站主页和安排网页内容

业务上

  • 帮助企业改善市场营销决策,如把广告放在适当的Web页面上。

  • 优化页面及业务流程设计,提高流量转化率。

  • 帮助企业更好地根据客户的兴趣来安排内容。

  • 帮助企业对客户群进行细分,针对不同客户制定个性化的促销策略等

如何进行网站流量分析

流量分析整体来说是一个内涵非常丰富的体系,其整体过程是一个金字塔结构

流量分析模型举例

网站流量质量分析

流量并不是越多越好,应该更加看重流量的质量,换句话来说就是流量可以为我们带来多少收入

JauesA.png

网站流量多维度细分

细分是指通过不同维度对指标进行分割,查看同一个指标在不同维度下的表现,进而找出有问题的那部分指标,对这部分指标进行优化

JauuZt.png

网站内容及导航分析

对于所有网站来说,页面都可以被划分为三个类别: 导航页,功能页, 内容页

比如从内容导航分析中,以下两类行为就是网站运营者不希望看到的行为:

Jauli8.png

网站转化及漏斗分析

所谓转化,即网站业务流程中的一个封闭渠道,引导用户按照流程最终实现业务目标(比如商品成交);而漏斗模型则是指进入渠道的用户在各环节递进过程中逐渐流失的形象描述;

JaMg56.png
JaMcUx.png

流量分析常见指标

基础分析(PV,IP,UV)

page view: 同一个人一天浏览一个网站的多少网页,重复的只算一条

unique visitor: 同一天,只记录第一次进入网站的具有独立IP的访问者,重复访问不计

PR:pageRank,网页的级别技术。用于标识一个网站的流行程度。来源google

Ø \趋势分析**:根据选定的时段,提供网站流量数据,通过流量趋势变化形态,为您分析网站访客的访问规律、网站发展状况提供参考。

Ø \对比分析**:根据选定的两个对比时段,提供网站流量在时间上的纵向对比报表,帮您发现网站发展状况、发展规律、流量变化率等。

Ø \当前在线**:提供当前时刻站点上的访客量,以及最近15分钟流量、来源、受访、访客变化情况等,方便用户及时了解当前网站流量状况。

Ø \访问明细**:提供最近7日的访客访问记录,可按每个PV或每次访问行为(访客的每次会话)显示,并可按照来源、搜索词等条件进行筛选。 通过访问明细,用户可以详细了解网站流量的累计过程,从而为用户快速找出流量变动原因提供最原始、最准确的依据

来源分析

\来源分类**

\搜索引擎**

\搜索词**

\最近7日的访客搜索记录**

\来路域名**

\来路页面**

\来源升降榜**

受访分析

\受访域名**

\受访页面**

\受访升降榜**

\热点图**

\用户视点**

\访问轨迹**

访客分析

\地区运营商**

\终端详情**

\新老访客**

\忠诚度**

\活跃度**

转化路径分析

转化定义

访客在您的网站完成了某项您期望的活动,记为一次转化,如注册或下载

路径分析

根据设置的特定路线,监测某一流程的完成转化情况,算出每步的转换率和流失率数据,如注册流程,购买流程等

整体技术流程及架构

数据处理流程

数据采集

将各服务器上生成的点击流日志通过实时或批量的方式汇聚到HDFS文件系统中

当然,一个综合分析系统,数据源可能不仅包含***点击流数据*,还有数据库中的*业务数据*(如用户信息、商品信息、订单信息等)及对分析有益的*外部数据****

数据预处理

通过mapreduce程序对采集到的点击流数据进行预处理,比如清洗,格式整理,滤除脏数据等

数据入库

将预处理之后的数据导入到HIVE仓库中相应的库和表中

数据分析

项目的核心内容,即根据需求开发ETL分析语句,得出各种统计结果

数据展现

将分析所得数据进行可视化

项目结构

模块开发

生成log表

生成pageview表

WeblogPreProcess类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
package cn.itcast.bigdata.hive.mr.pre;

import java.io.IOException;
import java.util.HashSet;
import java.util.Set;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

import cn.itcast.bigdata.hive.mrbean.WebLogBean;
import cn.itcast.bigdata.hive.mrbean.WebLogParser;


/**
* 处理原始日志,过滤出真实pv请求
* 转换时间格式
* 对缺失字段填充默认值
* 对记录标记valid和invalid
*
* @author
*
*/

public class WeblogPreProcess {

static class WeblogPreProcessMapper extends Mapper<LongWritable, Text, Text, NullWritable> {
//用来存储网站url分类数据
Set<String> pages = new HashSet<String>();
Text k = new Text();
NullWritable v = NullWritable.get();

/**
* 从外部加载网站url分类数据
*/
@Override
protected void setup(Context context) throws IOException, InterruptedException {
pages.add("/about");
pages.add("/black-ip-list/");
pages.add("/cassandra-clustor/");
pages.add("/finance-rhive-repurchase/");
pages.add("/hadoop-family-roadmap/");
pages.add("/hadoop-hive-intro/");
pages.add("/hadoop-zookeeper-intro/");
pages.add("/hadoop-mahout-roadmap/");

}

@Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {

String line = value.toString();
WebLogBean webLogBean = WebLogParser.parser(line);
// 过滤js/图片/css等静态资源
WebLogParser.filtStaticResource(webLogBean, pages);
/* if (!webLogBean.isValid()) return; */
k.set(webLogBean.toString());
context.write(k, v);
}

}

public static void main(String[] args) throws Exception {

Configuration conf = new Configuration();
Job job = Job.getInstance(conf);

job.setJarByClass(WeblogPreProcess.class);

job.setMapperClass(WeblogPreProcessMapper.class);

job.setOutputKeyClass(Text.class);
job.setOutputValueClass(NullWritable.class);

// FileInputFormat.setInputPaths(job, new Path(args[0]));
// FileOutputFormat.setOutputPath(job, new Path(args[1]));
FileInputFormat.setInputPaths(job, new Path("c:/weblog/input"));
FileOutputFormat.setOutputPath(job, new Path("c:/weblog/output"));

job.setNumReduceTasks(0);

job.waitForCompletion(true);

}

}

WebLogParser类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
package cn.itcast.bigdata.hive.mrbean;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Locale;
import java.util.Set;


public class WebLogParser {

public static SimpleDateFormat df1 = new SimpleDateFormat("dd/MMM/yyyy:HH:mm:ss", Locale.US);
public static SimpleDateFormat df2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US);

public static WebLogBean parser(String line) {
WebLogBean webLogBean = new WebLogBean();
String[] arr = line.split(" ");
if (arr.length > 11) {
webLogBean.setRemote_addr(arr[0]);
webLogBean.setRemote_user(arr[1]);
String time_local = formatDate(arr[3].substring(1));
if(null==time_local) time_local="-invalid_time-";
webLogBean.setTime_local(time_local);
webLogBean.setRequest(arr[6]);
webLogBean.setStatus(arr[8]);
webLogBean.setBody_bytes_sent(arr[9]);
webLogBean.setHttp_referer(arr[10]);

//如果useragent元素较多,拼接useragent
if (arr.length > 12) {
StringBuilder sb = new StringBuilder();
for(int i=11;i<arr.length;i++){
sb.append(arr[i]);
}
webLogBean.setHttp_user_agent(sb.toString());
} else {
webLogBean.setHttp_user_agent(arr[11]);
}

if (Integer.parseInt(webLogBean.getStatus()) >= 400) {// 大于400,HTTP错误
webLogBean.setValid(false);
}

if("-invalid_time-".equals(webLogBean.getTime_local())){
webLogBean.setValid(false);
}
} else {
webLogBean.setValid(false);
}

return webLogBean;
}

public static void filtStaticResource(WebLogBean bean, Set<String> pages) {
if (!pages.contains(bean.getRequest())) {
bean.setValid(false);
}
}

public static String formatDate(String time_local) {
try {
return df2.format(df1.parse(time_local));
} catch (ParseException e) {
return null;
}

}

}

WebLogBean类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
package cn.itcast.bigdata.hive.mrbean;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

import org.apache.hadoop.io.Writable;
import org.apache.hadoop.io.WritableComparable;

/**
* 对接外部数据的层,表结构定义最好跟外部数据源保持一致
* 术语: 贴源表
* @author
*
*/
public class WebLogBean implements Writable {

private boolean valid = true;// 判断数据是否合法
private String remote_addr;// 记录客户端的ip地址
private String remote_user;// 记录客户端用户名称,忽略属性"-"
private String time_local;// 记录访问时间与时区
private String request;// 记录请求的url与http协议
private String status;// 记录请求状态;成功是200
private String body_bytes_sent;// 记录发送给客户端文件主体内容大小
private String http_referer;// 用来记录从那个页面链接访问过来的
private String http_user_agent;// 记录客户浏览器的相关信息


public void set(boolean valid,String remote_addr, String remote_user, String time_local, String request, String status, String body_bytes_sent, String http_referer, String http_user_agent) {
this.valid = valid;
this.remote_addr = remote_addr;
this.remote_user = remote_user;
this.time_local = time_local;
this.request = request;
this.status = status;
this.body_bytes_sent = body_bytes_sent;
this.http_referer = http_referer;
this.http_user_agent = http_user_agent;
}

public String getRemote_addr() {
return remote_addr;
}

public void setRemote_addr(String remote_addr) {
this.remote_addr = remote_addr;
}

public String getRemote_user() {
return remote_user;
}

public void setRemote_user(String remote_user) {
this.remote_user = remote_user;
}

public String getTime_local() {
return this.time_local;
}

public void setTime_local(String time_local) {
this.time_local = time_local;
}

public String getRequest() {
return request;
}

public void setRequest(String request) {
this.request = request;
}

public String getStatus() {
return status;
}

public void setStatus(String status) {
this.status = status;
}

public String getBody_bytes_sent() {
return body_bytes_sent;
}

public void setBody_bytes_sent(String body_bytes_sent) {
this.body_bytes_sent = body_bytes_sent;
}

public String getHttp_referer() {
return http_referer;
}

public void setHttp_referer(String http_referer) {
this.http_referer = http_referer;
}

public String getHttp_user_agent() {
return http_user_agent;
}

public void setHttp_user_agent(String http_user_agent) {
this.http_user_agent = http_user_agent;
}

public boolean isValid() {
return valid;
}

public void setValid(boolean valid) {
this.valid = valid;
}

@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(this.valid);
sb.append("\001").append(this.getRemote_addr());
sb.append("\001").append(this.getRemote_user());
sb.append("\001").append(this.getTime_local());
sb.append("\001").append(this.getRequest());
sb.append("\001").append(this.getStatus());
sb.append("\001").append(this.getBody_bytes_sent());
sb.append("\001").append(this.getHttp_referer());
sb.append("\001").append(this.getHttp_user_agent());
return sb.toString();
}

@Override
public void readFields(DataInput in) throws IOException {
this.valid = in.readBoolean();
this.remote_addr = in.readUTF();
this.remote_user = in.readUTF();
this.time_local = in.readUTF();
this.request = in.readUTF();
this.status = in.readUTF();
this.body_bytes_sent = in.readUTF();
this.http_referer = in.readUTF();
this.http_user_agent = in.readUTF();

}

@Override
public void write(DataOutput out) throws IOException {
out.writeBoolean(this.valid);
out.writeUTF(null==remote_addr?"":remote_addr);
out.writeUTF(null==remote_user?"":remote_user);
out.writeUTF(null==time_local?"":time_local);
out.writeUTF(null==request?"":request);
out.writeUTF(null==status?"":status);
out.writeUTF(null==body_bytes_sent?"":body_bytes_sent);
out.writeUTF(null==http_referer?"":http_referer);
out.writeUTF(null==http_user_agent?"":http_user_agent);

}

}

生成visit表


世上所有的惊喜和好运,等于你的人品乘以你的努力。

本文标题:网站点击流数据分析

文章作者:TTYONG

发布时间:2020年04月23日 - 09:04

最后更新:2022年02月20日 - 11:02

原始链接:http://tianyong.fun/%E5%A4%A7%E6%95%B0%E6%8D%AE%E8%A1%8C%E4%B8%9A%E9%83%A8%E7%BD%B2-%E7%BD%91%E7%AB%99%E7%82%B9%E5%87%BB%E6%B5%81%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90.html

许可协议: 转载请保留原文链接及作者。

多少都是爱
0%