简介:本资源是一份面向人工智能初学者与数据科学实践者的CSDN用户画像构建项目源码包,聚焦于利用机器学习与自然语言处理技术完成真实平台用户行为建模。项目覆盖数据采集、文本分词、Word2Vec词向量训练、用户聚类与画像标签生成全流程,适用于推荐系统优化、精准运营及个性化服务等典型AI落地场景。压缩包共17个文件,含9个核心Python脚本(如preprocess.py、train_word2vec.py、seg_data.py等)、3个IDE配置XML文件、2个说明类TXT文档及辅助模块,整体仅17KB,轻量但结构完整,便于快速部署与代码级理解。已有111人学习下载,资源包含清晰的预处理—建模—评估链路设计,提供可运行的分步训练逻辑、中文文本处理适配方案及CSDN场景下的特征工程示例,是掌握用户画像从理论到工程落地的关键实践材料。
从零搭建一套可落地的用户画像系统:以CSDN博客作者画像为例
这两年“用户画像”这个词已经被说烂了,随便一个数据分析岗位的JD里都写着“具备用户画像构建经验”,可真到动手的时候,很多人其实是懵的。找了一圈开源项目,要么是纯PPT级别的demo,要么是耦合了全家桶大数据的重工程,本地根本跑不起来。我这次做的事很简单:用Python从数据采集、标签加工到画像可视化,完整实现了一套面向CSDN博客作者的用户画像系统,代码全部开源,单机可跑,数据量在万级以内完全够用。
这套系统解决的痛点很具体:CSDN上你只能看到作者的粉丝数、文章数、排名这类粗粒度指标,但一个作者的活跃时段、擅长领域、内容质量趋势、粉丝增长模式,这些真正决定“这个人值不值得关注/合作”的信息,全部隐藏在历史文章和互动数据里。人工一篇篇翻,效率太低,而且判断标准不统一。画像系统要做的,就是把“这个人是什么样”这个问题,变成一组可以量化、可以对比、可以随时间更新的标签。
如果你是刚接触人工智能和数据挖掘的学生,想拿一个能写进简历的项目练手;或者你是运营、编辑,想快速筛选优质技术作者;再或者你只是好奇“用户画像到底是怎么做出来的”,这篇文章都适合你。我会把从数据获取到画像输出的完整链路拆开讲,包括我当时踩过的坑和最终采用的方案。
1. 画像系统不等于标签堆砌:先想清楚要回答什么问题
很多初学者做用户画像,上来就抓数据,然后套用TF-IDF跑关键词,最后输出一个词云,觉得这就叫画像。这其实是对画像最大的误解。标签只是画像的载体,画像的核心是“回答业务问题”。
1.1 从业务问题反推画像维度
我拿到CSDN作者这个场景时,第一件事不是写爬虫,而是列问题清单:
- 这个作者主要写什么领域的文章?是Java、Python、前端,还是算法?
- 他写文章的频率怎么样?是日更、周更,还是一个月憋一篇?
- 他的文章质量如何?阅读量和点赞量是真实增长还是数据异常?
- 他的读者喜欢什么?评论多意味着话题争议性强或实用性强,收藏多意味着干货属性高。
- 他最近是在上升期还是沉寂期?粉丝增长趋势能说明问题。
- 他的写作有没有固定习惯?比如周末发文、深夜发文。
这些问题对应到画像上,就是内容偏好、活跃度、内容质量、读者互动、成长趋势、写作习惯六个维度。每个维度再拆成具体的标签,比如内容偏好下可以有“Python”“深度学习”“爬虫”这类主题标签,活跃度下可以有“高频更新”“稳定更新”“低频更新”这类等级标签。
1.2 画像的层级结构:从原始数据到策略标签
我把画像标签分成了三层:
第一层是事实标签,直接从原始数据里统计出来,比如“近30天发文12篇”“平均阅读量3500”。
第二层是规则标签,基于事实标签按照业务规则加工,比如“高频更新”“干货型作者”“深夜写作型”。
第三层是模型标签,需要算法参与,比如“内容主题聚类”“粉丝增长异常检测”。
这个分层最大的好处是:每一层都可以独立验证。事实标签错了,查统计数据;规则标签不合理,调阈值;模型标签不准,换算法。如果一上来就直接给一个“高质量作者”的综合评分,出了问题你都无从排查。
1.3 我给这套系统定义的输出形式
最终输出不是一张孤立的标签表,而是三样东西:
- 用户标签宽表:每个作者一行,包含所有标签字段,方便做筛选和排序。
- 用户画像报告:针对单个作者的图文报告,包含趋势图、词云、标签雷达图。
- 人群对比分析:可以对比多个作者,看他们在同一维度上的差异。
后面所有代码和数据结构的设计,都是围绕这三种输出倒推出来的。这个思路想清楚了,整个项目的地基就稳了。
2. 数据采集层:合法合规地拿到CSDN上公开的博主数据
做画像,数据是源头。CSDN的页面结构不算复杂,但采集过程中有大量细节容易踩坑,我一个个说。
2.1 采集范围与字段设计
我选择采集两类页面:博主主页和文章列表页。博主主页包含昵称、简介、粉丝数、获赞数、评论数、访问量、排名、原创文章数。文章列表页包含标题、发布时间、阅读量、点赞数、评论数、收藏数、文章分类。
字段设计上有个经验:宁可多存,不要少存。因为后期做标签加工时,你会发现当初觉得没用的字段突然派上用场。比如我当初没存“文章摘要”,后来想做内容主题判断时发现摘要其实是很重要的文本信号,幸好列表页有摘要,补采也很方便。
2.2 请求策略:单线程+限速是底线
CSDN的反爬不算严格,但不代表可以肆无忌惮地爬。我最终的策略是:requests会话保持Cookie,随机User-Agent,每次请求间隔2到4秒。单线程,不加并发。虽然慢一点,但一万个作者大约几小时能跑完,对于离线画像完全够用。
注意:如果你是拿别人的公开数据进行学术研究或个人学习,请严格遵守目标网站的robots协议和用户协议,控制请求频率,不要对目标服务器造成压力,也不要把采集到的数据用于商业用途。
2.3 解析策略:BeautifulSoup还是XPath
CSDN的HTML结构比较规范,我直接用BeautifulSoup加CSS选择器解析。核心逻辑就是定位特定的class或id,然后提取文本。有一类典型的坑是:有的字段存在多个页面位置,比如阅读量在列表页显示为“1234阅读”,在详情页显示为“1.2万阅读”,解析时要统一做格式化处理。
我写了一个数据清洗函数,专门处理“万”这个单位,将字符串转成数字。这个看起来很小的函数,在统计计算阶段节省了大量时间。
2.4 数据存储:SQLite足够用
数据量在万级时,SQLite完全能扛住。我建了三张表:authors(作者基础信息)、articles(文章信息)、author_snapshots(作者数据快照)。快照表的作用后面会讲,它让系统具备追踪历史变化的能力。
表的Schema大致如下:
CREATE TABLE authors ( author_id TEXT PRIMARY KEY, nickname TEXT, bio TEXT, followers INT, likes INT, comments INT, views INT, rank INT, original_articles INT, crawled_at TIMESTAMP ); CREATE TABLE articles ( article_id TEXT PRIMARY KEY, author_id TEXT, title TEXT, summary TEXT, category TEXT, publish_time TIMESTAMP, read_count INT, like_count INT, comment_count INT, favorite_count INT );2.5 增量采集设计:画像需要时间维度
一次性的快照数据只能反映“当前状态”,没法回答“趋势类”问题。所以我在设计之初就加入了增量采集:每周跑一次作者信息,把最新的粉丝数、排名存到快照表里。这样积累几周后,就能算出粉丝增长速率、排名变化方向。
这是很多初学者容易忽略的点:画像系统天然需要数据随时间累积,采集绝不只是一次性任务。
3. 标签加工:从原始数据到有业务含义的标签
数据进库之后,重头戏才开始。标签加工是画像系统的核心环节,我按照之前的六维度逐一来实现。
3.1 内容主题识别
给作者打内容标签,本质上是文本分类问题。每个作者的标题和摘要拼起来就是他的“文档”,我需要判断这篇文档的主题分布。
我选的方案是TF-IDF加LDA主题模型,而不是BERT之类的深度模型。原因有三:数据量不够大,深度学习容易过拟合;解释性要求高,运营人员要能看懂为什么打上这个标签;计算资源有限,LDA在单机上跑得飞快。
实际效果来看,LDA能区分得很好的是几个大类:编程语言、算法、前端开发、大数据、人工智能、数据库、运维、职场相关。我设置了topic数为8,超参数alpha和beta使用默认值,经过20轮迭代,效果已经可用。
3.2 活跃度标签
活跃度我用两个指标衡量:近30天发文数和历史平均发文间隔。
规则如下:
- 近30天发文数大于等于8,标为“高频更新”;
- 大于等于3且小于8,标为“稳定更新”;
- 小于3但历史有内容,标为“低频更新”;
- 近90天无新文章,标为“疑似停更”。
这里有个细节值得说:只统计“近30天发文数”是不够的,因为有些作者本来更新频率就低,30天内恰好没发,不代表他弃更了。所以补充了“历史平均发文间隔”这个指标,两者结合判断才合理。
3.3 内容质量标签
质量标签我用的是“平均单篇阅读量”和“平均单篇点赞量”两个值,然后按分位数分层。我取了所有作者这两个指标的25%、50%、75%分位数,分别定义为“低”“中”“高”“优秀”四档。
为什么要用分位数而不是固定值?因为不同领域文章的阅读量天然有差异,Java教程和哲学随笔的受众体量完全不同。分位数天然做了归一化,跨领域比较时才不至于失真。
3.4 读者互动标签
互动标签用来描述“读者怎么看待这个作者的内容”。我构建了三个子指标:
- 评论率:评论数除以阅读量,衡量话题讨论度;
- 收藏率:收藏数除以阅读量,衡量收藏价值;
- 点赞率:点赞数除以阅读量,衡量内容认可度。
这三个比率比绝对数值更能反映内容质量。一个阅读量1万但收藏仅50的文章,和一个阅读量2000但收藏300的文章,后者的“干货浓度”明显更高。
3.5 成长趋势标签
成长趋势主要通过粉丝快照计算。我用线性回归拟合粉丝数随时间的变化,斜率就是增长速度。再结合近30天和近90天的增长率,分为“快速增长”“稳步增长”“增长缓慢”“负增长”几档。
计算粉丝增长速率前有个预处理必须做:清理异常快照。比如某天接口返回了0,或者爬取失败导致的缺失值,这些都要过滤掉,否则线性回归的结果会被单个异常点带偏。
3.6 写作习惯标签
写作习惯是挺有意思的一个维度。我统计了每个作者发文时间的分布:周几发文最多,一天中哪个时段发文最多。
时段划分为:凌晨(0-6点)、上午(6-12点)、下午(12-18点)、晚上(18-24点)。如果某个作者在某个时段发文占比超过60%,就打上对应标签比如“深夜写作型”“上午发文型”。
这个标签看似无用,但在内容运营场景里非常实用——你可以在作者最活跃的时间去联系他,回复率会高很多。
4. 画像生成与可视化:把标签变成能用的东西
标签加工完,数据还是躺在数据库里。画像系统能不能被业务方接受,关键看最后呈现出来的是什么样子。
4.1 标签宽表:核心数据出口
我生成了一张author_profile表,每个作者一行,字段就是前面提到的各类标签。这张表可以直接导出Excel,也可以丢进BI工具做透视分析。
| 作者昵称 | 内容主题 | 活跃度 | 内容质量 | 粉丝趋势 | 写作习惯 |
|---|---|---|---|---|---|
| 张三 | Python,爬虫 | 高频更新 | 优秀 | 快速增长 | 深夜写作型 |
| 李四 | Java,微服务 | 稳定更新 | 高 | 稳步增长 | 晚间发文型 |
| 王五 | 前端,JavaScript | 低频更新 | 中 | 增长缓慢 | 周末发文型 |
4.2 单作者画像报告
我单独写了一个report模块,输入一个作者ID,就输出一份图文报告。报告包括三个部分:基本信息卡片、阅读量趋势折线图、主题词云、标签雷达图以及文本描述。
雷达图展示六个核心维度的得分,这个得分是把各类标签映射成0到100分得到的。映射规则我在代码里写得很清楚:每个规则标签对应一个分数区间,最终取加权平均。
单作者报告的价值在于“一目了然”。运营拿到一份报告就能判断:这个作者是走量的还是走质的,适合约稿还是适合做深度专访。
4.3 对比分析:多作者的横向比较
除了单作者报告,系统还支持多作者对比。比如你手上有一批候选合作作者,可以一次性加载他们的标签宽表,按内容主题筛选,用散点图对比“内容质量分”和“粉丝增速”,快速筛出综合实力强、成长性好的作者。
这部分我用了matplotlib的scatter函数,X轴是质量分,Y轴是粉丝增长速度,点的大小表示粉丝总量。视觉上非常直观。
4.4 可视化代码片段
雷达图的代码核心并不复杂,用的是matplotlib的polar坐标系:
import matplotlib.pyplot as plt import numpy as np def draw_radar(labels, scores, title): angles = np.linspace(0, 2 * np.pi, len(labels), endpoint=False).tolist() scores += scores[:1] angles += angles[:1] fig, ax = plt.subplots(figsize=(6, 6), subplot_kw=dict(polar=True)) ax.fill(angles, scores, color='skyblue', alpha=0.4) ax.plot(angles, scores, color='blue', linewidth=2) ax.set_xticks(angles[:-1]) ax.set_xticklabels(labels, fontsize=12) ax.set_ylim(0, 100) plt.title(title, fontsize=15) plt.show()5. 项目中踩过的坑与排查过程
这个项目看起来流程顺畅,实际上我在开发过程中踩了不少坑,随便挑几个来说说。
5.1 文本特征维度爆炸:TF-IDF向量太大
最初我做内容主题识别时,把每篇标题和摘要直接拼起来做TF-IDF,然后喂给LDA。结果发现特征矩阵特别大,几万篇文档跑一次要十几分钟,内存吃紧。
排查后发现问题出在:我保留了所有词汇,包括大量无意义的通用词。解决方案是做更严格的文本预处理:分词后过滤停用词,过滤掉单字词,过滤出现频率过高或过低的词,然后限定特征维度max_features=5000。处理完之后,训练时间缩短到一分钟以内。
5.2 阅读数里的“万”导致排序错乱
前文提到数据清洗的问题,这里具体展开。CSDN的阅读量显示为“1.2万阅读”时,如果直接按字符串排序,1.2万会被排到8000后面,因为字符串比较时“8”比“1”大。
我的解决方法是写一个统一的转换函数:
def parse_count(text): if '万' in text: return int(float(text.replace('万', '')) * 10000) return int(text.replace('阅读', '').replace(',', ''))这个函数对“1234阅读”“1.2万阅读”“1,234阅读”都能正确解析。看似简单,但如果不处理,后面的所有统计全都会错。
5.3 LDA主题数不收敛导致主题混乱
LDA需要预置主题数,我一开始拍脑袋设了5,结果跑出来的主题特别混乱,有的主题里Python和建筑行业词混在一起。
后来我用了困惑度曲线来确定主题数。在1000篇文档的样本上分别计算6、8、10、12个主题时的困惑度,发现8个主题时困惑度最低且主题间区分度最好。这个调参过程在项目代码里留了可视化脚本,复现时可以直接跑。
5.4 快照数据的缺失值处理
做粉丝增长趋势时,我发现有些作者缺了某几周的快照,导致线性回归的结果不稳定。后来我改成了按作者分组后,在组内对时间列做前向填充,缺失值用最近一次的快照补上,再拟合。误差在可接受范围内。
6. 开源结构与扩展方向
这套系统在GitHub上的目录结构是:
csdn_user_profile/ ├── crawler/ │ ├── spider.py # 博主主页和文章列表采集 │ └── cleaner.py # 数据清洗 ├── analysis/ │ ├── topic_model.py # LDA主题识别 │ ├── tags.py # 六维标签加工 │ └── trend.py # 粉丝趋势 ├── report/ │ ├── profile_report.py # 单作者报告 │ └── compare.py # 多作者对比 ├── data/ │ └── database.db # SQLite数据库 └── README.md如果你不是CSDN场景,想套用到其他内容平台,需要改的基本上只有crawler层和字段映射规则,analysis和report层的逻辑是通用的。
后续如果数据量上来,有几个扩展方向可以考虑:把LDA换成BERTopic这类深度主题模型,在标签加工阶段引入规则引擎,以及用Streamlit把报告模块包装成Web应用,让业务人员直接输入作者ID就能看报告。
用户画像这东西,说难不难,说简单也绝对不简单。难的不是算法,而是对整个数据链路的掌控——从采集到清洗、从建模到解释,每一步都会影响最后画像的可靠性。我这套系统的定位是“轻量、可复现、能跑通全流程”,希望给正在做相似项目的人一个可参考的起点。
本文还有配套的精品资源,点击获取