当前位置: 首页 > news >正文

浏览器市场与用户画像分析-数据加工

浏览器市场与用户画像分析-数据加工

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 数据文件结构

所有数据分为两部分:

  1. 数据目录/

  2. ├── behavior/ # 按日期归档,存放数万条TXT行为日志

  3. └── 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 日志文件内部格式

每个日志文件固定分为三部分:

行为记录格式示例

  1. 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:

  1. CREATE TABLE behavior_events (

  2. id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '自增主键',

  3. session_id VARCHAR(255) COMMENT '会话唯一ID',

  4. user_id VARCHAR(100) COMMENT '用户ID',

  5. session_start_time VARCHAR(50) COMMENT '会话开始时间',

  6. event_seconds INT COMMENT '事件发生秒数',

  7. process_name VARCHAR(255) COMMENT '进程名称',

  8. process_id VARCHAR(100) COMMENT '进程ID',

  9. url TEXT COMMENT '访问网址',

  10. addr_handle VARCHAR(255) COMMENT '地址栏句柄',

  11. tab_handle VARCHAR(255) COMMENT '标签页句柄',

  12. browser_version VARCHAR(100) COMMENT '浏览器版本',

  13. window_handle VARCHAR(255) COMMENT '窗口句柄',

  14. app_name VARCHAR(255) COMMENT '程序名称',

  15. company_name VARCHAR(255) COMMENT '开发公司',

  16. source_file VARCHAR(255) COMMENT '原始日志文件名',

  17. create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '入库时间',

  18. INDEX idx_session_id (session_id),

  19. INDEX idx_user_id (user_id)

  20. ) COMMENT '用户行为事件明细表';

执行转换流。

4.2.4 获取文件名:日志文件批量采集

设计思路:由于原始数据是半结构化数据,无法直接通过文件输入组件获取数据,因此采用以下方案:

通过“获取文件名”组件批量读取并定位日志文件

交由“Java代码”组件完成半结构化日志解析

通过“字段选择”组件筛选并规整有效字段

最终输出为标准结构化数据表

新建转换流“行为日志数据转为结构化数据”,拖拽“获取文件名”组件。

双击配置,点击【浏览文件】,选择“互联网用户行为日志数据集”目录,点击【增加】后确认。

4.2.5 Java代码:日志解析与结构化转换

拖拽“Java代码”组件到画布,创建从“获取文件名”到“Java代码”的连线。

双击“Java代码”组件,输入以下代码:

  1. // 全局变量定义

  2. String pathField;

  3. String shortFilenameField;

  4. public boolean processRow() throws HopException {

  5. if (first) {

  6. pathField = "filename";

  7. shortFilenameField = "short_filename";

  8. first = false;

  9. }

  10. Object[] r = getRow();

  11. if (r == null) {

  12. setOutputDone();

  13. return false;

  14. }

  15. String path = get(Fields.In, pathField).getString(r);

  16. String short_filename = get(Fields.In, shortFilenameField).getString(r);

  17. String user_id = "";

  18. String l_start = "";

  19. if (short_filename != null) {

  20. String name = short_filename.replace(".txt", "");

  21. String[] parts = name.split("_");

  22. if (parts.length >= 3) {

  23. user_id = parts[0];

  24. l_start = parts[1] + " " + parts[2].replace("-", ":");

  25. }

  26. }

  27. String session_id = user_id + "_" + l_start;

  28. java.io.BufferedReader br = null;

  29. try {

  30. br = new java.io.BufferedReader(new java.io.FileReader(path));

  31. String line = "";

  32. // 跳过前两行(Last和L_Start)

  33. br.readLine();

  34. br.readLine();

  35. while ((line = br.readLine()) != null) {

  36. if (line.trim().isEmpty()) {

  37. continue;

  38. }

  39. // 解析键值对

  40. String[] kvPairs = line.split("\\[=\\]");

  41. String t = "", p = "", i = "", u = "", a = "", b = "", v = "", w = "", n = "", c = "";

  42. for (String kv : kvPairs) {

  43. int sepIdx = kv.indexOf("<=>");

  44. if (sepIdx == -1) continue;

  45. String key = kv.substring(0, sepIdx).trim();

  46. String val = kv.substring(sepIdx + 3);

  47. if ("T".equals(key)) t = val;

  48. else if ("P".equals(key)) p = val;

  49. else if ("I".equals(key)) i = val;

  50. else if ("U".equals(key)) u = val;

  51. else if ("A".equals(key)) a = val;

  52. else if ("B".equals(key)) b = val;

  53. else if ("V".equals(key)) v = val;

  54. else if ("W".equals(key)) w = val;

  55. else if ("N".equals(key)) n = val;

  56. else if ("C".equals(key)) c = val;

  57. }

  58. // 创建输出行

  59. Object[] outRow = createOutputRow(r, data.outputRowMeta.size());

  60. get(Fields.Out, "session_id").setValue(outRow, session_id);

  61. get(Fields.Out, "user_id").setValue(outRow, user_id);

  62. get(Fields.Out, "l_start").setValue(outRow, l_start);

  63. get(Fields.Out, "t").setValue(outRow, t);

  64. get(Fields.Out, "p").setValue(outRow, p);

  65. get(Fields.Out, "i").setValue(outRow, i);

  66. get(Fields.Out, "u").setValue(outRow, u);

  67. get(Fields.Out, "a").setValue(outRow, a);

  68. get(Fields.Out, "b").setValue(outRow, b);

  69. get(Fields.Out, "v").setValue(outRow, v);

  70. get(Fields.Out, "w").setValue(outRow, w);

  71. get(Fields.Out, "n").setValue(outRow, n);

  72. get(Fields.Out, "c").setValue(outRow, c);

  73. get(Fields.Out, "source_file").setValue(outRow, short_filename);

  74. putRow(data.outputRowMeta, outRow);

  75. }

  76. } catch (Exception e) {

  77. logError(e.getMessage(), e);

  78. } finally {

  79. try { if (br != null) br.close(); } catch (Exception e) {}

  80. }

  81. return true;

  82. }

配置输出字段

在字段表格中右键点击“插入”,依次添加以下字段:

注意:部分额外操作可能导致已配置的字段类型变为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脚本”组件:

  1. CREATE TABLE program_stats (

  2. program_name VARCHAR(255) NOT NULL,

  3. user_count INT NOT NULL

  4. );

注意:由于数据量较大,在【元数据】中双击“团队私有数据库”,勾选“使用结果流”。

4.3.2 统计进程用户规模

新建转换流“统计进程用户规模”,拖拽“表输入”组件,获取 behavior_events 的所有数据。

步骤流程

  1. 字段选择:只保留 user_id、process_name

  2. 替换NULL值:将 process_name 空值替换为“未知”

  3. 排序记录:按 process_name 升序排序

  4. 分组:按 process_name 分组,聚合 user_count = COUNT(user_id)

  5. 表输出:写入 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:

  1. CREATE TABLE `browser_coverage` (

  2. `browser_name` VARCHAR(50) NOT NULL COMMENT '浏览器进程名',

  3. `user_count` INT NOT NULL COMMENT '使用用户数(去重)',

  4. `total_duration_sec` BIGINT NOT NULL COMMENT '总使用时长(秒)'

  5. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='浏览器用户覆盖率与总时长';

创建转换流“创建每个浏览器按小时统计活跃用户数统计表”,执行SQL:

  1. CREATE TABLE `browser_hourly` (

  2. `browser_name` VARCHAR(50) NOT NULL COMMENT '浏览器进程名',

  3. `hour` TINYINT NOT NULL COMMENT '小时(0-23)',

  4. `active_user_count` INT NOT NULL COMMENT '活跃用户数',

  5. PRIMARY KEY (`browser_name`, `hour`)

  6. ) 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

主要浏览器进程名:

  1. iexplore.exe;360chrome.exe;360se.exe;chrome.exe;sogouexplorer.exe;QQBrowser.exe

4.5.4 计算停留时长

设计思路:原始日志只记录了焦点切换时刻,没有直接给出停留时长。通过前后两条记录的 event_seconds 相减,即可得到停留时长。

步骤

  1. 排序记录:按 session_id、event_seconds 升序

  2. 分析查询:获取同一会话内下一行的 event_seconds,存入 next_event_seconds

  3. 计算器: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节各子章节

http://www.zskr.cn/news/1439634.html

相关文章:

  • 跨学科共情AI:多模态感知与情感推理的架构设计与工程实践
  • Gemini 英文论文(SCI/EI)写作:从“中式英语”到顶刊表达的实战重构
  • # 2026年国内莱赛尔牛仔布公司排行榜:广东佛山等地,五大推荐榜单 - 十大品牌榜
  • 如何高效使用RePKG:Wallpaper Engine资源提取与TEX转换完整指南
  • 基于分数阶傅里叶变换与LSTM的AI音乐生成系统:原理、实现与调优
  • 怎么寄快递更划算?普通人的经验与注意事项
  • 2026年5月荆州黄金回收哪家靠谱?余生黄金回收领衔六大正规门店星级排行,沙市荆州纪南全域实测干货 - 余生黄金回收
  • Hermes Agent Docker 离线部署完整指南
  • 从数据洞察短视频创作者的秘密
  • htc 国家超算中心 高性能计算 环境配置 , 计算节点 不能访问外网的,环境配置要在登录节点
  • 从陀螺仪噪声到Kalman滤波:Allan方差参数的实际工程应用指南
  • 【C++】vector的模拟实现
  • 2026 山东大学软件学院项目实训博客 (六):历史人物轨迹系统 DeepSeek 智能查询与坐标校对全流程实现
  • 无感通关 智守国门 黎阳之光赋能海关口岸监管升级
  • 怎么选择一款合适的电磁冷热量表?哪些厂家值得信赖? - 仪表人小余
  • 2026年最新三明市金银首饰回收+金条金币+铂金K金 高价回收;实体老店回收黄金 多年口碑 交易放心;TOP5实力权威排行榜推荐+联系方式 - 亦辰小黄鸭
  • 群面系统中五维能力评估的实现
  • 鸿蒙原生开发生态全景:从 ArkTS 到纯血鸿蒙
  • 跨国链路的物理限制:马蒂斯公式(Mathis‘s Formula)
  • 人形检测数据集, 目标检测/行人检测/安防AI模型训练 密集场景人形检测数据集 / 行人检测数据集训练及应用
  • 开发日志六
  • 从一次线上GC故障排查说起:我为什么最终把生产环境从OracleJDK 11换成了Amazon Corretto 11
  • 聊天机器人的搭建(一)
  • Web应用技术第一次和第二次作业
  • 微服务架构(MSA)是如何诞生的?
  • AI销售助理:1700万美元融资背后的技术架构与落地实践
  • 单向循环链表超详细精讲 | 带头节点带头指针 + 完整可运行c语言代码
  • 保姆级教程:在Ubuntu 20.04上从源码编译运行ORB-SLAM3(含ROS1/ROS2配置)
  • 设计模式深度解析:从六大原则到Spring源码,面试通关全攻略
  • 基于YOLOv8的美国手语手势检测系统 美国手语手势检测数据集训练及应用