欢迎光临
我们一直在努力

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

平台全称:助睿数智(Uniplore)一站式数据科学实验平台

平台定位:覆盖数据接入、ETL处理、机器学习建模到可视化分析的全链路Agentic零代码数据智能

产品官网:https://www.uniplore.com/

实验平台地址:https://lab.guilian.cn/

1. 实验目的

  • 数据加工能力培养:掌握半结构化日志数据的解析、字段拆分与规整方法,将原始文本日志转化为标准结构化数据表。
  • 指标体系搭建:通过多维度数据聚合、字段衍生与跨表关联,构建适配浏览器市场与用户行为分析场景的指标体系。
  • 业务分析实战:基于真实用户行为数据,完成浏览器市场格局、用户使用习惯等核心业务问题的初步探查。

2. 实验环境

  • 实验平台:助睿在线实验平台(https://lab.guilian.cn/)
  • 数据科学平台:助睿数智(Uniplore)一站式数据科学平台,覆盖数据接入、ETL处理、机器学习建模到可视化展示的全链路零代码功能
  • 数据处理工具:助睿 ETL 数据集成平台
  • 数据规模:1000名用户,800万+条行为记录,原始数据约825MB

3. 实验数据与建模思路

3.1 数据构成

本实验基于首届中国互联网数据挖掘竞赛公开数据集,是典型的计算机用户行为半结构化日志数据。数据集包含三大核心部分:

  • 用户基本信息表 (demographic.csv):存储用户ID、性别、年龄、职业、教育程度、收入等人口属性信息
  • 浏览器上网记录:包含URL、域名、访问时间等
  • 软件使用记录:包含进程名、程序名、使用时长、窗口切换等
  • 数据覆盖1000名用户连续4周的电脑使用行为,每周抽取一周数据,时间跨度为4个月。

    3.2 核心数据模型与加工思路

    • 原始数据特点:数据以TXT文本文件形式存在,文件名包含用户ID、日期和开机时间,文件内部结构为“键值对”形式的半结构化日志
    • 加工思路:通过“获取文件名”组件批量定位日志文件,使用自定义“Java代码”组件解析文件名与文件内容,将半结构化数据拆解为行列清晰的结构化表(behavior_events),并通过ETL流程进行清洗、聚合与衍生
    • 分析思路:对行为数据按进程名统计用户覆盖度,发现浏览器类应用具有最高覆盖率,且包含url字段,具备深度分析价值。因此,后续分析将锁定浏览器,分析市场格局、用户使用时段等

    4. 实验步骤

    本实验主要分为三大阶段:

  • 数据准备与结构化转换:将原始TXT日志解析并装载至关系型数据库
  • 数据分析方向确定:探查数据,锁定浏览器为分析对象
  • 数据清洗、聚合与关联加工:构建浏览器市场格局与用户使用时段统计表
  • 4.1 数据准备与结构化转换

    创建项目,命名为互联网用户行为日志数据加工

    4.1.1 数据资源获取与建表

    进入项目,在文件库的根目录下右键新建文件夹,命名为互联网用户行为日志数据集

    点击公共空间,找到数据资源标签,点击更多,选择导入,将其中标签为“互联网用户行为日志数据集“的20个样例csv日志文件(实际只有12个,其他的是重复的)导入到已创建的“互联网用户行为日志数据集”目录下

    连接数据库,(就是前几次实验连接的团队私有数据库此处不做演示)

    为确保数据结构化后有处存放,首先在资源库标签根目录右键创建转换流命名为“创建原始行为日志数据表”,拖入执行一个SQL脚本组件来创建明细表 behavior_events

    具体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.1.2 日志文件批量采集与解析

    新建转换流“行为日志数据转为结构化数据”,拖拽“获取文件名”组件,双击进入配置,点击浏览文件,选择文件库创建的“互联网用户行为日志数据集”文件夹后点击确认,然后再点击增加,再点击确认

    4.1.3 Java代码实现半结构化解析

    拖拽“Java代码”组件,并将其与“获取文件名”组件相连,选择主输出步骤;在组件中编写Java逻辑,实现以下核心功能:

  • 解析文件名:从文件名中提取user_id、l_start(会话开始时间),并拼接生成session_id
  • 读取文件内容:跳过文件头部的两行元数据(Last和L_Start)
  • 解析行为记录:按[=]分隔符拆分每条记录,再按<=>分隔符提取字段名(T、P、I、U、A、B、V、W、N、C)与对应的值
  • 输出结构化行:将解析出的所有字段(会话ID、用户ID、开始时间、事件秒数、进程名、URL等)作为结构化数据行输出
  • 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 = "";

                String p = "";

                String i = "";

                String u = "";

                String a = "";

                String b = "";

                String v = "";

                String w = "";

                String n = "";

                String 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) {

                // ignore

            }

        }

        return true;

    }

    在下方字段空白处右键插入

    插入字段参考如下

    字段名

    类型

    session_id

    String

    user_id

    String

    l_start

    String

    t

    String

    p

    String

    i

    String

    u

    String

    a

    String

    b

    String

    v

    String

    w

    String

    n

    String

    c

    String

    source_file

    String

    点击确认后右键选择显示输出字段,查看输出是否符合预期

    4.1.4 字段筛选与表输出
  • 字段选择:拖拽“字段选择”组件,在移除标签下右键获取字段,因为只需要保留上一步Java代码输出的字段,所以要在要移除的字段中将这些字段全部删除
  • 表输出:拖拽“表输出”组件,配置目标数据库连接为“团队私有数据库”,目标表为behavior_events
  • 在数据库字段处右键获取字段,表字段从session_id开始,按顺序向下填入

  • 执行:运行转换流,完成从半结构化日志到结构化数据表的转换
  • 在元数据右键团队私有数据库加载元数据,选择behavior_event可以看到输出结果
  • 4.2 数据分析方向确定

    新建转换流,命名为“创建进程统计表”

    拖入执行一个sql脚本组件

    具体sql脚本如下:

    — 创建程序/软件统计表

    CREATE TABLE program_stats (

        program_name VARCHAR(255) NOT NULL,        — 程序/软件名称

        user_count INT NOT NULL              — 使用用户数

    );

    由于数据量较大,为了顺利运行转换流,运行转换流前,先右键团队私有数据库,勾选使用结果流

    为确定最具分析潜力的对象,新建转换流“统计进程用户规模”:

  • 表输入:数据库连接选择团队私有数据库,点击获取sql查询语句,选择behavior_event
  • 字段选择:统计每个进程得用户数量只需用到 user_id、process_name 两个字段,所以需要移除其他字段(即在移除标签中删除这两个字段)
  • 空值处理:
  • 双击“替换NULL值”组件,勾选“选择字段”,在下方字段表格中插入一行,并输入:

    字段:process_name

    值替换为:未知

    是否为空:否

  • 排序与分组:按process_name排序后,使用“分组”组件按process_name分组,并聚合计算使用该进程的独立用户数(user_count)。
  • 表输出:将统计结果输出到program_stats表。
  • 进入助睿BI,点击数据集,选择新建数据集

    将刚刚创建的program_stats拖入画布

    字段配置如下

    保存并发布

    点击工作表,新建工作表

    选择水平条图,配置如下

    User_count选择降序

    4.3 数据清洗、聚合与关联加工

    根据分析目标,预先设计了browser_coverage(市场格局表)和browser_hourly(时段统计表)的结构,并创建了相应的数据库表。

    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='浏览器按小时活跃用户数';

    随后,新建转换流“互联网用户行为日志数据清洗抽取”,核心步骤如下:

  • 读取数据:通过“表输入”组件读取线上公共数据库中的全量behavior_events表
  • 字段选择:删除冗余字段,选中 session_id, user_id, session_start_time, process_name, url, event_seconds 后删除选中的行,保留下来的字段就是要移除的字段,点击“确认”
  • 筛选浏览器记录:使用“过滤记录”组件,筛选process_name属于目标浏览器列表(iexplore.exe;360chrome.exe;360se.exe;chrome.exe;sogouexplorer.exe;QQBrowser.exe)的数据
  • 计算停留时长:
    • 排序:按session_id和event_seconds升序排序
      • 分析查询:获取同一会话内下一条记录的event_seconds值,存入新字段next_event_seconds

      • 计算器:通过公式 next_event_seconds – event_seconds 计算得出用户在每个窗口的停留时长 duration_sec,并过滤掉时长无效(≤0)的记录

  • 字段选择:保留必要字段
  • 使用“字段选择”,只保留 user_id, process_name, session_start_time, url, duration_sec

  • 过滤记录:筛选停留时长>0的数据
  • 使用“过滤记录”组件,过滤掉 duration_sec <= 0 的记录(最后一条记录没有下一条,时长无效,忽略)

  • 剪切字符串:提取日期
  • 后续很多分析需要按天、按时段聚合(比如每日使用时长、时段热力图)。提前提取好日期和小时,后续分组时直接使用,避免重复解析。

    session_start_time 的格式为:yyyy-MM-dd HH:mm:ss,通过剪切字符串组件可以直接获取yyyy-MM-dd

  • 字段选择:设置日期格式
  • 目前获取的数据中,session_start_time 的类型为String,为方便提前提取好小时,需要将session_start_time 的类型设置为Date,格式为yyyy-MM-dd HH:mm:ss

  • 生成行为明细:提取日期和小时信息,并通过“分组”组件按user_id、process_name、日期、小时进行聚合,计算每个用户在每个小时内的总停留时长(total_duration_sec)和活跃次数(active_count),生成粒度合适的用户-日-浏览器-小时明细数据
  • 到这一步,大体组件连线如下:

  • 分支A:生成市场格局表:基于上一步明细,再次使用“分组”组件,仅按process_name分组,聚合计算独立用户数(user_count)和总使用时长(total_duration),最终通过“表输出”写入browser_coverage表
  • 分支B:生成时段统计表:基于明细数据,按process_name和hour分组,聚合计算每小时活跃用户数(active_user_count),最终通过“表输出”写入browser_hourly表
  • 拖入排序记录组件,将分组组件与其连接,选择复制发送

    分支B:

    总体连线如下:

    运行转换流完毕后,右键团队私有数据库选择加载元数据,在数据探查中可以看到输出结果

    5. 实验总结

    本次实验基于海量真实的用户行为日志,成功完成了一次完整的数据加工与分析流程,实现了以下目标:

  • 攻克半结构化数据解析难题:通过“Java代码”组件和自定义解析逻辑,将复杂的文本日志成功转化为可用于分析的结构化数据表,掌握了处理此类数据的通用方法
  • 构建浏览器分析指标体系:以“浏览器”为核心主题,通过多步数据清洗、字段衍生(停留时长)和多维度聚合,构建了从用户明细到市场格局、使用习惯的层次化指标体系
  • 为深度洞察奠定数据基础:产出的browser_coverage和browser_hourly两张统计表,能够直接回答“哪些浏览器用户最多、使用最久?”以及“用户集中在什么时段使用浏览器?”等关键业务问题。实验后续章节设计的留存分析、流失预测、个性化推荐等高阶分析均能基于本次实验加工的标准化数据进行
  • 赞(0)
    未经允许不得转载:171主机测评 » 浏览器市场与用户画像分析-数据加工(1)
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址