<>一、用户行为日志概述

1)用户行为日志
用户每次访问网站时所有的行为数据:访问、浏览、搜索、点击… 用户行为轨迹、流量

2)为什么要记录用户访问行为日志

* 进行网站页面的访问量的统计
* 分析网站的黏性
* 推荐
3)用户行为日志生成渠道

* Nginx:web服务器记录的web访问日志
* Ajax:记录的访问日志以及其他相关的日志
4)用户行为日志大致内容

* 访问时间
* 访问者所使用的客户端(UserAgent)
* 访问者的IP地址
* 访问者账号某个页面的停留时间
* 访问的时间与地点跳转的链接地址(referer)
* 访问信息,例如:session_id模块AppID
5)日志数据内容

* 访问的系统属性:操作系统、浏览器等
* 访问特征:点击的url、从哪个url跳转过来的(referer)、页面上的停留时间等
* 访问信息:session_id、访问ip(访问城市)等
6) 用户行为日志分析的意义

* 网站的眼睛
* eg.能够看到用户的主要来源、喜好网站上的哪些内容,以及用户的忠诚度等
* 网站的神经
* eg.通过分析用户行为日志,我们能对网站的布局、功能进一步的优化,以提高用户的体验等
* 网站的大脑
* eg.通过分析结果,进行推广预算的划分,以及重点优化用户群体的倾向点
<>二、离线处理架构##### 数据处理流程

1)数据采集:Flume:Web日志写入到HDFS

当访问某个网站时,每一个访问请求都会发送到后台的服务器上,面对高并发的情况下,大多使用的是Njexl来接受请求,然后再进行高并发的访问均衡,即使用N已经可以输出数据了,再通过Flume采集,它是将数据从一个地方搬运到另一个地方的框架
2)数据清洗
脏数据 eg.不符合日志规范的数据,要先清除技术:Hive Spark
MapReduce或其他一些分布式计算框架清洗完的数据可以存放在HDFS(Hive/Spark SQL)
3)数据处理
按照我们的需要进行相应业务的统计和分析Hive Spark MapReduce或其他一些分布式计算框架
4)处理结果入库
可以存放到RDBMS(关系型数据库)、NoSQL(非关系型数据库)
5)数据的可视化
通过图形化的方式展现出来:饼图、柱状图、地图、折线图等ECharts、HUE、Zeppelin


<>三、项目需求统计imooc主站访问日志的浏览器访问次数

* 根据日志信息抽取出浏览器信息
* 针对不同的浏览器进行统计操作
1)日志片段如下:
183.162.52.7 - - [10/Nov/2016:00:01:02 +0800] "POST /api3/getadv HTTP/1.1" 200
813 "www.xxx.com" "-"
cid=0×tamp=1478707261865&uid=2871142&marking=androidbanner&secrect=a6e8e14701ffe9f6063934780d9e2e6d&token=f51e97d1cb1a9caac669ea8acc162b96
"mukewang/5.0.0 (Android 5.1.1; Xiaomi Redmi 3 Build/LMY47V),Network 2G/3G" "-"
10.100.134.244:80 200 0.027 0.027 10.100.0.1 - - [10/Nov/2016:00:01:02 +0800]
"HEAD / HTTP/1.1" 301 0 "117.121.101.40" "-" - "curl/7.19.7
(x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.16.2.3 Basic ECC zlib/1.2.3
libidn/1.18 libssh2/1.4.2" "-" - - - 0.000
2)实现UserAgent解析类测试
工具类下载githu地址:https://github.com/LeeKemp/UserAgentParser
<https://github.com/LeeKemp/UserAgentParser>

通过git clone或者浏览器下载到本地后,使用命令行进入到其主目录下,然后通过maven命令对其进行打包并安装到本地仓库里:
mvn clean package -DskipTest mvn clean install -DskipTest
安装完成后,在工程中添加依赖:
<!-- 添加UserAgent解析的依赖 --> <dependency> <groupId>com.kumkee</groupId>
<artifactId>UserAgentParser</artifactId> <version>0.0.1</version> </dependency>
编写一个测试用例来测试一下这个解析类
** * UserAgentTest测试类 */ public class UserAgentTest { /** *
单元测试:UserAgent工具类的使用 */ @Test public void testUserAgentParser(){ //信息 String
source="183.162.52.7 - - [10/Nov/2016:00:01:02 +0800] \"POST /api3/getadv
HTTP/1.1\" 200 813 \"www.xxx.com\" \"-\"
cid=0×tamp=1478707261865&uid=2871142&marking=androidbanner&secrect=a6e8e14701ffe9f6063934780d9e2e6d&token=f51e97d1cb1a9caac669ea8acc162b96
\"mukewang/5.0.0 (Android 5.1.1; Xiaomi Redmi 3 Build/LMY47V),Network 2G/3G\"
\"-\" 10.100.134.244:80 200 0.027 0.027\n" + "10.100.0.1 - -
[10/Nov/2016:00:01:02 +0800] \"HEAD / HTTP/1.1\" 301 0 \"117.121.101.40\" \"-\"
- \"curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.16.2.3 Basic ECC
zlib/1.2.3 libidn/1.18 libssh2/1.4.2\" \"-\" - - - 0.000"; //解析日志头部的工具类
UserAgentParser userAgentParser = new UserAgentParser(); UserAgent agent =
userAgentParser.parse(source); //功能 String browser=agent.getBrowser(); String
engine=agent.getEngine(); String engineVersion=agent.getEngineVersion(); String
os=agent.getOs(); String platform=agent.getPlatform(); boolean
isMobile=agent.isMobile(); //输出结果 System.out.println(browser+", "+engine+",
"+engineVersion+", "+os+", "+platform+", "+isMobile); }
结果:Unknown, Unknown, null, Linux, Android, true

<>四、基于Hash的本地浏览器数量代码
package com.immoc.hadoop.project; import com.kumkee.userAgent.UserAgent;
import com.kumkee.userAgent.UserAgentParser; import
org.apache.commons.lang.StringUtils; import org.junit.Test; import java.io.*;
import java.util.HashMap; import java.util.Map; import java.util.regex.Matcher;
import java.util.regex.Pattern; /** * UserAgentTest测试类 */ public class
UserAgentTest { /** * 单元测试:UserAgent工具类的使用 */ @Test public void
testUserAgentParser(){ //信息 String source="183.162.52.7 - -
[10/Nov/2016:00:01:02 +0800] \"POST /api3/getadv HTTP/1.1\" 200 813
\"www.xxx.com\" \"-\"
cid=0×tamp=1478707261865&uid=2871142&marking=androidbanner&secrect=a6e8e14701ffe9f6063934780d9e2e6d&token=f51e97d1cb1a9caac669ea8acc162b96
\"mukewang/5.0.0 (Android 5.1.1; Xiaomi Redmi 3 Build/LMY47V),Network 2G/3G\"
\"-\" 10.100.134.244:80 200 0.027 0.027\n" + "10.100.0.1 - -
[10/Nov/2016:00:01:02 +0800] \"HEAD / HTTP/1.1\" 301 0 \"117.121.101.40\" \"-\"
- \"curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.16.2.3 Basic ECC
zlib/1.2.3 libidn/1.18 libssh2/1.4.2\" \"-\" - - - 0.000"; //解析日志头部的工具类
UserAgentParser userAgentParser = new UserAgentParser(); UserAgent agent =
userAgentParser.parse(source); //功能 String browser=agent.getBrowser(); String
engine=agent.getEngine(); String engineVersion=agent.getEngineVersion(); String
os=agent.getOs(); String platform=agent.getPlatform(); boolean
isMobile=agent.isMobile(); //输出结果 System.out.println(browser+", "+engine+",
"+engineVersion+", "+os+", "+platform+", "+isMobile); } /** * 自定义方法 *
获取指定字符串中指定标识符的字符串出现的索引位置 * @param value 字符串值 * @param operator 指定标识符 * @param
index 索引位置 * @return */ private int getCharacterPosition(String value,String
operator,int index){ //对子字符串进行匹配 Matcher slashMatcher=
Pattern.compile(operator).matcher(value); int mInx=0;//计数
//matcher.find();尝试查找与该模式匹配的输入序列的下一个子序列 while (slashMatcher.find()){ mInx++; if
(mInx==index){ break; } } //slashMatcher.start()返回上一个匹配的起始索引 return
slashMatcher.start(); } /** * 测试自定义方法 */ @Test public void
testGtCharacterPosition(){ String value="183.162.52.7 - - [10/Nov/2016:00:01:02
+0800] \"POST /api3/getadv HTTP/1.1\" 200 813 \"www.xxx.com\" \"-\"
cid=0×tamp=1478707261865&uid=2871142&marking=androidbanner&secrect=a6e8e14701ffe9f6063934780d9e2e6d&token=f51e97d1cb1a9caac669ea8acc162b96
\"mukewang/5.0.0 (Android 5.1.1; Xiaomi Redmi 3 Build/LMY47V),Network 2G/3G\"
\"-\" 10.100.134.244:80 200 0.027 0.027\n" + "10.100.0.1 - -
[10/Nov/2016:00:01:02 +0800] \"HEAD / HTTP/1.1\" 301 0 \"117.121.101.40\" \"-\"
- \"curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.16.2.3 Basic ECC
zlib/1.2.3 libidn/1.18 libssh2/1.4.2\" \"-\" - - - 0.000"; int
index=getCharacterPosition(value,"\"",7); System.out.println(index); } /** *
测试读取文件 */ @Test public void testReadFile() throws Exception{ String path="";
//读取path路径下的文件内容 BufferedReader reader=new BufferedReader (new
InputStreamReader(new FileInputStream(new File(path)))); String line=""; //计数
int count=0; //解析日志头部的工具类 UserAgentParser userAgentParser=new
UserAgentParser(); //String 浏览器类型 Integer 浏览次数 Map<String,Integer>
browserMap=new HashMap<String,Integer>(); while(line!=null){
line=reader.readLine();//一次读取一行数据 count++;//记录数据量 if
(StringUtils.isNotBlank(line)){ //得到第7个"后的字符串 String
source=line.substring(getCharacterPosition(line,"\"",7)+1); UserAgent agent =
userAgentParser.parse(source); String browser=agent.getBrowser(); String
engine=agent.getEngine(); String engineVersion=agent.getEngineVersion(); String
os=agent.getOs(); String platform=agent.getPlatform(); boolean
isMobile=agent.isMobile(); Integer broswerValue=browserMap.get(browser);
if(broswerValue!=null){ //put(K key,V value)
browserMap.put(browser,broswerValue+1); }else{ browserMap.put(browser,1); }
//输出结果 System.out.println(browser+", "+engine+", "+engineVersion+", "+os+",
"+platform+", "+isMobile); } } System.out.println("records count:"+count);
System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~");
//entrySet将map里的键值对取出来封装成一个Entry对象再存到一个Set中 for(Map.Entry<String,Integer> entry
: browserMap.entrySet()){ System.out.println(entry.getKey()+":
"+entry.getValue()); } } public static void main(String []args){ } }

友情链接
ioDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:ixiaoyang8@qq.com
QQ群:637538335
关注微信