浏览器市场与用户画像分析-数据加工
浏览器市场与用户画像分析-数据加工
1 实验目的
熟悉数据集构成与半结构化日志数据特点,掌握文本日志解析、字段拆分的实操方法;
完成数据规整,将零散原始日志转化为标准结构化数据表;
实现多维度数据聚合、字段衍生与跨表关联,搭建适配分析场景的指标体系。
2 实验环境
实验平台:助睿在线实验平台 https://lab.guilian.cn/
平台说明:本次实验使用助睿数智(Uniplore)一站式数据科学平台,覆盖数据接入、ETL处理、机器学习建模到可视化展示的全链路零代码功能。官网:https://www.uniplore.com/
数据处理:助睿ETL数据集成平台
数据规模:1000用户,800万+条行为记录,约825MB
3 实验数据
本实验基于首届中国互联网数据挖掘竞赛公开数据集开展,是非常典型的计算机用户行为半结构化日志数据,专门用于用户行为分析、习惯挖掘、活跃度预测与用户画像研究。
3.1 数据集整体构成
数据集包含三大核心部分:
数据规模:
数据总大小(解压后):约825MB
原始行为记录:800多万条
覆盖用户:1000名
时间跨度:连续4周的电脑使用行为(横跨4个月,每月抽取1周数据)
3.2 数据文件结构
所有数据分为两部分:
数据目录/
├── behavior/ # 按日期归档,存放数万条TXT行为日志
└── demographic.csv # 用户属性表
两个数据通过 user_id(用户ID)唯一关联。
3.3 日志文件命名规则
每个TXT文件 = 一个用户一次开机产生的行为日志
文件名格式:用户ID_日期_开机时间.txt
示例:0AB6BBBEDFF24EC8BAAC905F45AE314C_2012-05-07_21-22-38.txt
从文件名可直接解析出:
user_id:用户唯一标识
file_date:日志日期
file_start_time:开机时间
3.4 日志文件内部格式
每个日志文件固定分为三部分:
行为记录格式示例:
T<=>177[=]P<=>360se.exe[=]I<=>5572[=]W<=>30378[=]V<=>4,1,6,6[=]N<=>360安全浏览器[=]C<=>360.cn
固定分隔符说明:
<=>:字段名与值分隔符
[=]:字段与字段之间分隔符
3.5 字段含义
3.6 数据特点
半结构化:无固定行列,不能直接分析
数据量大:800万+条记录
文件分散:按日期和用户分散存储
格式统一:解析规则明确,适合批量处理
4 实验步骤
4.1 创建实验项目
点击“新建项目”,输入项目名称“互联网用户行为日志数据加工”,点击“确定”。
4.2 日志数据结构化转换
4.2.1 数据资源获取
注意:由于本次实验数据量过大,仅使用其中20个文件来学习半结构化数据转换方法。
步骤1:打开项目
点击项目卡片右上角的【…】→【打开项目】。
步骤2:创建目录
点击【文件库】,右键根目录 →【新建目录】,命名为“互联网用户行为日志数据集”。
步骤3:导入公共空间数据
点击【公共空间】→【数据资源】,找到属于“互联网用户行为日志数据集”的数据文件。
依次点击每个文件卡片右上角的【更多】→【导出】,选择目标目录为“互联网用户行为日志数据集”。
4.2.2 建立数据源连接
在之前的实验中已创建团队私有数据库连接,可直接使用。如未创建,请参考《学生用户画像-考勤主题标签构建》实验的4.2.2节。
4.2.3 创建原始用户行为日志表
新建转换流“创建原始行为日志数据表”,拖拽“执行一个SQL脚本”组件,配置如下SQL:
CREATE TABLE behavior_events (
id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '自增主键',
session_id VARCHAR(255) COMMENT '会话唯一ID',
user_id VARCHAR(100) COMMENT '用户ID',
session_start_time VARCHAR(50) COMMENT '会话开始时间',
event_seconds INT COMMENT '事件发生秒数',
process_name VARCHAR(255) COMMENT '进程名称',
process_id VARCHAR(100) COMMENT '进程ID',
url TEXT COMMENT '访问网址',
addr_handle VARCHAR(255) COMMENT '地址栏句柄',
tab_handle VARCHAR(255) COMMENT '标签页句柄',
browser_version VARCHAR(100) COMMENT '浏览器版本',
window_handle VARCHAR(255) COMMENT '窗口句柄',
app_name VARCHAR(255) COMMENT '程序名称',
company_name VARCHAR(255) COMMENT '开发公司',
source_file VARCHAR(255) COMMENT '原始日志文件名',
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '入库时间',
INDEX idx_session_id (session_id),
INDEX idx_user_id (user_id)
) COMMENT '用户行为事件明细表';
执行转换流。
4.2.4 获取文件名:日志文件批量采集
设计思路:由于原始数据是半结构化数据,无法直接通过文件输入组件获取数据,因此采用以下方案:
通过“获取文件名”组件批量读取并定位日志文件
交由“Java代码”组件完成半结构化日志解析
通过“字段选择”组件筛选并规整有效字段
最终输出为标准结构化数据表
新建转换流“行为日志数据转为结构化数据”,拖拽“获取文件名”组件。
双击配置,点击【浏览文件】,选择“互联网用户行为日志数据集”目录,点击【增加】后确认。
4.2.5 Java代码:日志解析与结构化转换
拖拽“Java代码”组件到画布,创建从“获取文件名”到“Java代码”的连线。
双击“Java代码”组件,输入以下代码:
// 全局变量定义
String pathField;
String shortFilenameField;
public boolean processRow() throws HopException {
if (first) {
pathField = "filename";
shortFilenameField = "short_filename";
first = false;
}
Object[] r = getRow();
if (r == null) {
setOutputDone();
return false;
}
String path = get(Fields.In, pathField).getString(r);
String short_filename = get(Fields.In, shortFilenameField).getString(r);
String user_id = "";
String l_start = "";
if (short_filename != null) {
String name = short_filename.replace(".txt", "");
String[] parts = name.split("_");
if (parts.length >= 3) {
user_id = parts[0];
l_start = parts[1] + " " + parts[2].replace("-", ":");
}
}
String session_id = user_id + "_" + l_start;
java.io.BufferedReader br = null;
try {
br = new java.io.BufferedReader(new java.io.FileReader(path));
String line = "";
// 跳过前两行(Last和L_Start)
br.readLine();
br.readLine();
while ((line = br.readLine()) != null) {
if (line.trim().isEmpty()) {
continue;
}
// 解析键值对
String[] kvPairs = line.split("\\[=\\]");
String t = "", p = "", i = "", u = "", a = "", b = "", v = "", w = "", n = "", c = "";
for (String kv : kvPairs) {
int sepIdx = kv.indexOf("<=>");
if (sepIdx == -1) continue;
String key = kv.substring(0, sepIdx).trim();
String val = kv.substring(sepIdx + 3);
if ("T".equals(key)) t = val;
else if ("P".equals(key)) p = val;
else if ("I".equals(key)) i = val;
else if ("U".equals(key)) u = val;
else if ("A".equals(key)) a = val;
else if ("B".equals(key)) b = val;
else if ("V".equals(key)) v = val;
else if ("W".equals(key)) w = val;
else if ("N".equals(key)) n = val;
else if ("C".equals(key)) c = val;
}
// 创建输出行
Object[] outRow = createOutputRow(r, data.outputRowMeta.size());
get(Fields.Out, "session_id").setValue(outRow, session_id);
get(Fields.Out, "user_id").setValue(outRow, user_id);
get(Fields.Out, "l_start").setValue(outRow, l_start);
get(Fields.Out, "t").setValue(outRow, t);
get(Fields.Out, "p").setValue(outRow, p);
get(Fields.Out, "i").setValue(outRow, i);
get(Fields.Out, "u").setValue(outRow, u);
get(Fields.Out, "a").setValue(outRow, a);
get(Fields.Out, "b").setValue(outRow, b);
get(Fields.Out, "v").setValue(outRow, v);
get(Fields.Out, "w").setValue(outRow, w);
get(Fields.Out, "n").setValue(outRow, n);
get(Fields.Out, "c").setValue(outRow, c);
get(Fields.Out, "source_file").setValue(outRow, short_filename);
putRow(data.outputRowMeta, outRow);
}
} catch (Exception e) {
logError(e.getMessage(), e);
} finally {
try { if (br != null) br.close(); } catch (Exception e) {}
}
return true;
}
配置输出字段:
在字段表格中右键点击“插入”,依次添加以下字段:
注意:部分额外操作可能导致已配置的字段类型变为0,此时转换流程虽可正常运行,但数据表不会生成数据。请重新配置正确字段类型后再次执行。
4.2.6 字段选择:有效字段筛选与规整
右键“Java代码”组件点击“预览输出字段”,可以看到很多字段不属于原始数据字段,需要移除。
拖拽“字段选择”组件到画布,创建从“Java代码”到“字段选择”的连线。
双击配置,点击【移除】tab,右键【获取字段】,选中多余字段后删除。
4.2.7 表输出:结构化数据表落地
拖拽“表输出”组件到画布,创建从“字段选择”到“表输出”的连线。
双击配置:
数据库连接:选择“团队私有数据库”
勾选“裁剪表”(插入前清空,避免重复)
勾选“指定数据库字段”
在【数据库字段】tab页,右键【获取字段】,双击表字段下拉框选择正确的字段映射。
4.2.8 执行转换流
点击工具栏【执行】按钮,选择默认配置后点击【启动】。
4.2.9 查看数据库结果
进入【元数据】tab页,右键“团队私有数据库”→【加载元数据】→【数据探查】。
双击 behavior_events 表,选择【查询】tab页查看数据。
4.3 数据分析方向确定
得到 behavior_events 后,按进程名 process_name 统计使用人数,快速锁定最值得分析的候选对象。
4.3.1 创建进程统计表
新建转换流“创建进程统计表”,拖拽“执行一个SQL脚本”组件:
CREATE TABLE program_stats (
program_name VARCHAR(255) NOT NULL,
user_count INT NOT NULL
);
注意:由于数据量较大,在【元数据】中双击“团队私有数据库”,勾选“使用结果流”。
4.3.2 统计进程用户规模
新建转换流“统计进程用户规模”,拖拽“表输入”组件,获取 behavior_events 的所有数据。
步骤流程:
字段选择:只保留 user_id、process_name
替换NULL值:将 process_name 空值替换为“未知”
排序记录:按 process_name 升序排序
分组:按 process_name 分组,聚合 user_count = COUNT(user_id)
表输出:写入 program_stats 表
4.3.3 观察数据确定分析方向
使用助睿BI观察覆盖用户最广的进程/软件。
进入助睿BI → 新建数据集“进程用户数据统计” → 选择 program_stats 表 → 保存并发布。
新建工作表,图表类型选择“水平条图”:
Y轴:program_name
X轴:user_count
排序:按 user_count 降序
分析结论:浏览器类进程(chrome.exe、360chrome.exe、sogouexplorer.exe、QQBrowser.exe)的用户数明显高于其他软件(如QQ.exe、EXCEL.EXE、WINWORD.EXE)。这表明浏览器是覆盖面最广的应用,样本充足,且浏览器记录包含URL字段,可进一步分析网站偏好。因此,确定浏览器为分析对象。
4.4 分析方案设计与数据确定
根据上述统计结果,将分析对象锁定为浏览器,围绕以下业务问题展开:
本次实验先完成前2个数据表的加工。
4.4.1 创建目标数据表
创建转换流“创建浏览器的用户数总使用时长统计表”,执行SQL:
CREATE TABLE `browser_coverage` (
`browser_name` VARCHAR(50) NOT NULL COMMENT '浏览器进程名',
`user_count` INT NOT NULL COMMENT '使用用户数(去重)',
`total_duration_sec` BIGINT NOT NULL COMMENT '总使用时长(秒)'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='浏览器用户覆盖率与总时长';
创建转换流“创建每个浏览器按小时统计活跃用户数统计表”,执行SQL:
CREATE TABLE `browser_hourly` (
`browser_name` VARCHAR(50) NOT NULL COMMENT '浏览器进程名',
`hour` TINYINT NOT NULL COMMENT '小时(0-23)',
`active_user_count` INT NOT NULL COMMENT '活跃用户数',
PRIMARY KEY (`browser_name`, `hour`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='浏览器按小时活跃用户数';
4.5 数据清洗、聚合与关联加工
说明:解析完成的 behavior_events 行为明细表已存放在线上公共数据库中,可直接使用。同时引入 demographic.csv 用户人口属性数据表,通过 user_id 完成数据联动。
新建转换流“互联网用户行为日志数据清洗抽取”。
4.5.1 表输入:读取行为日志数据
拖拽“表输入”组件,连接线上公共数据源(团队私有数据库只有20条教学数据),获取 behavior_events 的所有数据。
4.5.2 字段选择:删除冗余字段
拖拽“字段选择”组件,保留以下字段,其余移除:
session_id
user_id
session_start_time
process_name
url
event_seconds
4.5.3 过滤记录:筛选浏览器进程
拖拽“过滤记录”组件,配置条件:process_name IN LIST
主要浏览器进程名:
iexplore.exe;360chrome.exe;360se.exe;chrome.exe;sogouexplorer.exe;QQBrowser.exe
4.5.4 计算停留时长
设计思路:原始日志只记录了焦点切换时刻,没有直接给出停留时长。通过前后两条记录的 event_seconds 相减,即可得到停留时长。
步骤:
排序记录:按 session_id、event_seconds 升序
分析查询:获取同一会话内下一行的 event_seconds,存入 next_event_seconds
计算器:duration_sec = next_event_seconds - event_seconds
4.5.5 字段选择:保留必要字段
只保留:
user_id
process_name
session_start_time
url
duration_sec
4.5.6 过滤记录:筛选有效时长
过滤掉 duration_sec <= 0 的记录(最后一条记录没有下一条,时长无效)。
4.5.7 剪切字符串:提取日期
从 session_start_time(格式:yyyy-MM-dd HH:mm:ss)中提取日期部分 yyyy-MM-dd。
4.5.8 字段选择:设置日期格式
将 session_start_time 类型从String改为Date。
4.5.9 计算器:提取小时
提取 session_start_time 中的小时部分(HH)。
4.5.10 生成用户-日-浏览器-小时明细
排序:按 user_id、session_start_time、process_name 排序
分组聚合:按以下字段分组:
user_id
session_start_time(日期部分)
process_name
hour
聚合字段:
total_duration_sec = SUM(duration_sec)
launch_count = COUNT(*)(启动次数)
此明细表作为后续所有统计表的基础数据。
4.5.11 分支A:生成市场格局表(browser_coverage)
目标:统计每个浏览器的总用户数和总使用时长
分组配置:
分组字段:process_name
聚合字段:
user_count = COUNT(user_id)(去重计数)
total_duration_sec = SUM(total_duration_sec)
表输出:写入 browser_coverage 表
4.5.12 分支B:生成时段统计表(browser_hourly)
目标:统计每个浏览器在每个小时的使用情况
排序:按 process_name、hour 升序
分组配置:
分组字段:process_name、hour
聚合字段:active_user_count = COUNT(user_id)
表输出:写入 browser_hourly 表
4.5.13 执行转换流
点击运行按钮,等待执行完成。
4.5.14 查看结果
进入【元数据】→ 右键“团队私有数据库”→【加载元数据】→【数据探查】。
查看 browser_coverage 和 browser_hourly 两张表的数据。
5 核心组件说明
6 常见问题与解决
问题1:Java代码组件字段类型丢失
现象:配置好输出字段后,部分字段类型变为0,导致数据无法写入。
原因:额外操作(如切换tab页、关闭再打开)可能导致字段类型重置。
解决方法:重新配置正确字段类型后再次执行任务。
问题2:数据量过大导致执行缓慢
现象:全量800万+数据执行时间较长。
解决方法:本实验先使用20个TXT文件学习解析方法,后续分析使用线上公共数据源中的全量数据。
问题3:分组前未排序导致结果错误
现象:分组聚合结果异常。
原因:分组组件要求输入数据按分组字段有序。
解决方法:在每个分组组件前添加“排序记录”组件,按分组字段升序排序。
7 实验总结
本次实验完成了以下工作:
7.1 技术能力提升
半结构化数据解析能力:掌握了通过Java代码组件实现文本日志解析、字段拆分的完整方法;
ETL全流程操作能力:实现了从“获取文件名”到“表输出”的完整转换流配置;
数据加工设计能力:完成了停留时长计算、多级分组聚合、分支处理等复杂ETL设计。
7.2 业务价值实现
原始数据结构化:将零散的半结构化的TXT日志转化为标准结构化数据表 behavior_events;
分析方向确定:通过进程用户规模统计,锁定浏览器为核心分析对象;
分析数据准备:完成了 browser_coverage(市场格局表)和 browser_hourly(时段统计表)两张分析基础表的加工。
7.3 关键数据产出
7.4 平台优势总结
相比传统编写Python/Shell脚本处理日志的方式,助睿ETL平台提供了以下优势:
本实验为后续更深入的互联网用户行为分析(如浏览器市场竞争分析、用户留存与流失预测、个性化推荐等)奠定了坚实的数据基础。
附录:
Java代码解析逻辑详见4.2.5节
停留时长计算逻辑详见4.5.4节
完整转换流配置详见4.5节各子章节
