尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

微博恶意用户识别全流程解析:爬虫、特征工程与逻辑回归建模

发布时间:2026/9/26 18:38:59

资讯中心
01
ARTICLE

微博恶意用户识别全流程解析:爬虫、特征工程与逻辑回归建模

微博恶意用户识别全流程解析:爬虫、特征工程与逻辑回归建模
简介这是一份基于机器学习的微博恶意用户识别系统完整项目资料面向人工智能、计算机及相关专业的学生和开发者尤其适合作为毕业设计、课程设计或初期项目演示。资源涵盖数据采集、特征处理、模型训练与Web展示等环节能够帮助读者快速搭建并理解一套完整的恶意用户识别方案。包内共56个文件主要包括Python脚本模型训练与爬虫采集、npy/dat数据文件、SQL数据库脚本、YAML配置、HTML/CSS前端页面、Markdown说明文档及Shell脚本等各类文件按功能组织便于按需查阅与二次开发压缩包整体仅8.8MB。项目文档还标注了环境配置与运行要点配合测试通过的代码可快速复现并继续改进已有65人学习适合不同基础的学习者在此基础上修改扩展也可直接用于相关课程作业或项目答辩。1. 微博恶意用户识别一套能跑通全流程的95分毕设接手“微博恶意用户识别”这套资料时我最关心的是两件事数据从哪来模型有没有真跑通。拆解之后两个答案都很明确——它不是一个只给训练脚本的单项作业而是把爬虫采集、MySQL存储、特征工程、逻辑回归训练、Flask 展示串成一条完整链路。从微博抓用户关系数据清洗落库再交给机器学习模型做二分类最终在 Web 页面完成单用户识别。技术栈覆盖标准数据链路完整这正是答辩时最容易被追问的“全流程”能力也是 95 分的来源。机器学习和 Python 的热门词背后其实都是这张表里实实在在的字段计算。适合做毕设、课设或者想完整走一遍“数据采集—特征—模型—服务”这条路的同学。下面按数据层、算法层、工程层逐层拆解把最容易翻车的地方单独拎出来讲。2. 数据层拆解爬虫采集、SQL 落库与训练集构造2.1 微博爬虫模块关注关系采集与 Cookie 维护项目里爬虫文件分得很清楚weiboCrawler.py负责基础抓取concern.py和fans.py分别抓用户关注列表和粉丝列表cookies.txt存放登录态。恶意用户识别最常用的行为特征就是关注数、粉丝数比例所以这两个文件是整个特征体系的源头。爬虫的核心逻辑通常是这个风格# concern.py 核心逻辑示意 import requests import time import json def fetch_following(uid, cookie): url fhttps://weibo.com/ajax/friendships/friends?uid{uid}page1 headers { cookie: cookie, user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) } resp requests.get(url, headersheaders, timeout10) data resp.json() return [item[id] for item in data.get(data, {}).get(list, [])] if __name__ __main__: uid sys.argv[1] cookie open(cookies.txt).read().strip() following_list fetch_following(uid, cookie) print(json.dumps(following_list, ensure_asciiFalse))逻辑说明这里抓的是用户关注的账号 ID 列表后续可以计算“互粉率”“关注列表里有多少疑似营销号”等特征。参数说明timeout10表示单次请求 10 秒超时避免某个用户数据异常时把爬虫卡死cookie 从cookies.txt统一读取保证登录态集中维护。真实运行时还需要加请求延时我一般会在循环里time.sleep(0.5)到time.sleep(1)微博的反爬策略对高频请求很敏感赶时间可以压到 0.3 秒但不要取消。fans.py的逻辑与concern.py几乎对称只是把 url 换成粉丝列表接口返回的字段里多了一个followed_by布尔值用来判断对方是否关注了当前用户。这个字段能直接算出“互粉数”也是恶意用户识别里区分真人和机器号的重要信号——机器号的互粉率通常极低。2.2 数据表设计从 SQL 文件看存储结构项目里的xinan.sql和xinan_with_data.sql两个文件分工很明确前者是空表结构适合先看字段后者是带数据的完整库导入后可以直接复现训练。数据表核心是一张用户主表加一张恶意样本标签表用户的画像信息都在这两个文件里。导入数据库时有个字符集坑先给命令# 创建数据库时必须指定 utf8mb4否则中文昵称直接变乱码 mysql -u root -p -e CREATE DATABASE IF NOT EXISTS weibo DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_bin; mysql -u root -p weibo xinan_with_data.sql注意那条COLLATE utf8mb4_bin微博昵称包含大量 emoji 和特殊符号用默认的utf8mb4_general_ci在某些 MySQL 版本下会报排序规则错误。bin排序规则按字节比较能完整保留原始数据。用户主表最关键字段如下字段类型说明uidbigint微博用户 ID主键screen_namevarchar(64)昵称followers_countint粉丝数follow_countint关注数statuses_countint微博总数created_atdatetime注册时间is_malicioustinyint标签1 为恶意用户latest_texttext最近微博文本is_malicious的来源通常是人工标注加上evil1.txt这类黑名单账号匹配的结果。evil1.txt里存放的是已经确认的恶意用户 ID 清单清洗时拿用户表和这份清单做 JOIN能自动生成一部分标签。2.3 数据处理与训练集构造从数据库到训练集核心是把原始字段转成模型能吃的数值矩阵。insertUser.py负责把爬虫抓到的数据写进用户表newUser.py做增量更新两者都只解决“数据进库”的问题真正构造训练集还需要一个查询清洗脚本。# 构造训练集从 MySQL 读取并做最基础的清洗 import pymysql import pandas as pd conn pymysql.connect( hostlocalhost, userroot, password123456, databaseweibo, charsetutf8mb4 ) df pd.read_sql( SELECT followers_count, follow_count, statuses_count, is_malicious FROM user_profile WHERE followers_count IS NOT NULL, conn ) # 基础清洗排除负数和明显异常数据 df df[df[followers_count] 0] df df.drop_duplicates(subset[uid]) # 实际场景要保留 uid 列 X df[[followers_count, follow_count, statuses_count]].values y df[is_malicious].values逻辑说明取出三列数值特征和标签列drop_duplicates按 uid 去重避免同一用户被抓多次造成数据泄漏。参数说明charsetutf8mb4必须和建库时一致否则读中文会报UnicodeDecodeErrorWHERE followers_count IS NOT NULL是为了过滤脏数据爬虫抓取失败时最容易产生 NULL。这里要特别提醒训练集里不要直接放 uid。uid 是类别型标识放进逻辑回归会被当成数值导致模型学到“某个特定 ID 是恶意用户”这种完全不可泛化的规律。uid 只能用于去重和回查不能作为特征。3. 算法层拆解特征工程与逻辑回归识别模型3.1 特征工程恶意用户长什么样恶意用户和正常用户的行为差异最直观的几条关注数极高但粉丝数极低典型的“广撒网”式关注微博内容多为转发或刷屏原创率低注册时间短但发博频率异常昵称带有一串随机数字或营销关键词。这些领域知识直接决定了特征怎么构造。基于这些先验把原始字段转成真正有区分度的特征特征名计算公式含义follow_fan_ratio关注数 / (粉丝数 1)恶意用户通常大于 5status_freq微博数 / (注册天数 1)检测刷屏行为original_rate原创微博数 / 总微博数营销号普遍偏低has_mobile是否绑定手机批量注册号常缺失nickname_entropy昵称字符熵随机生成昵称的特征特征构造代码# 特征构造ratio 和 freq 必须在训练前算好 df[follow_fan_ratio] df[follow_count] / (df[followers_count] 1) df[register_days] (pd.Timestamp(now) - pd.to_datetime(df[created_at])).dt.days df[status_freq] df[statuses_count] / (df[register_days] 1) df[original_rate] df[original_count] / (df[statuses_count] 1) # 构造最终特征矩阵 feature_cols [follow_fan_ratio, status_freq, original_rate, has_mobile, nickname_entropy] X df[feature_cols].fillna(0).values逻辑说明分母加 1 是同时解决除零和避免 NaN 的一种常见做法register_days为 0 的新账号在分母加 1 后不会被计算成无穷大。参数说明fillna(0)用 0 填充缺失值但这只在缺失比例低于 5% 时合理如果某列缺失超过 30%我一般会直接丢弃这一列而不是硬填。从实际训练结果看follow_fan_ratio通常是逻辑回归系数最大的特征说明它对恶意用户判别贡献最高。如果你拿不到文本特征优先保证这个特征质量最可靠。3.2 模型选择与训练逻辑回归是这类任务的默认答案恶意用户识别本质是二分类。learner目录下训练代码实现了逻辑回归加交叉验证的经典组合。逻辑回归相比树模型的最大优点是特征系数完全可解释答辩时可以直接展示每个特征对恶意判别的权重比神经网络更适合教学场景。# 训练逻辑回归模型含交叉验证和特征标准化 from sklearn.linear_model import LogisticRegression from sklearn.model_selection import cross_val_score, train_test_split from sklearn.preprocessing import StandardScaler from sklearn.pipeline import make_pipeline X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.3, random_state42, stratifyy ) model make_pipeline( StandardScaler(), LogisticRegression(C1.0, class_weightbalanced, max_iter1000) ) scores cross_val_score(model, X_train, y_train, cv5, scoringf1) print(5-Fold F1: %.3f - %.3f % (scores.mean(), scores.std()))逻辑说明StandardScaler会把关注数、粉丝数这类量纲差异巨大的特征压缩到同一尺度逻辑回归的梯度下降才能正常收敛class_weightbalanced用于缓解恶意用户样本少导致的“全部预测为正常用户”问题交叉验证选 F1 而不是 accuracy是因为该类别的正样本比例通常很低。参数说明C1.0是正则化强度的默认值数据量在几千到几万时不需要刻意改max_iter1000必须设大默认 100 在标准化后也容易警告不收敛我一般直接给 1000。3.3 模型评估别只看准确率恶意用户识别里最容易栽的坑是准确率虚高。如果恶意用户只占 5%把所有用户判为正常准确率也有 95%。所以要重点看混淆矩阵、召回率、F1。from sklearn.metrics import classification_report, confusion_matrix # 用概率输出而不是直接 predict方便后面调阈值 proba model.predict_proba(X_test)[:, 1] y_pred (proba 0.5).astype(int) print(classification_report(y_test, y_pred, target_names[normal, malicious])) print(confusion_matrix(y_test, y_pred))逻辑说明proba是恶意类概率threshold0.5是默认阈值如果业务目标是“宁可误伤也要多抓”可以把阈值降到 0.3。参数说明classification_report里malicious行的 recall 表示恶意用户被识别出来的比例precision 表示被抓出来的里面有多少是真恶意用户。答辩时常被追问“为什么不用准确率”回答“准确率受样本不平衡影响F1 和召回率更贴合业务目标”就能直接命中采分点。4. 工程层拆解从训练脚本到 Flask 接口4.1 Flask Demo加载模型对外提供预测flask_demo目录的作用是把训练好的模型包装成简单 Web 服务配合content.html页面做交互。核心逻辑是接收用户特征返回恶意概率。# app.py 核心代码加载模型并接收特征返回预测结果 import joblib from flask import Flask, request, jsonify app Flask(__name__) model joblib.load(model.pkl) # 训练完成后保存的模型文件 app.route(/predict, methods[POST]) def predict(): data request.get_json() # 前端已经算好了特征值后端不承担特征计算 feats [data[follow_fan_ratio], data[status_freq], data[original_rate]] proba model.predict_proba([feats])[0][1] return jsonify({ proba: proba, malicious: int(proba 0.5) }) if __name__ __main__: app.run(host0.0.0.0, port5000, debugFalse)逻辑说明host0.0.0.0让服务可被局域网其他机器访问方便答辩时从自己的笔记本演示predict_proba返回恶意类的概率比例子直接返回类别更灵活方便随时调阈值。参数说明debugFalse必须保持否则生产环境暴露调试器有安全风险端口 5000 是 Flask 默认端口被占用时可以换 5001。一个容易被忽略的细节joblib.load在启动时加载模型但 sklearn 的LogisticRegression第一次predict_proba才初始化底层 liblinear 库所以第一次请求会卡顿。解决方法是启动后先调一次缓存接口# 启动时预热模型避免第一个请求慢 5-10 秒 model.predict_proba([[0, 0, 0]])4.2 全流程串联从采集到预测的管道顺着项目的文件结构走一遍完整数据流能帮你快速定位每一个文件该在哪个环节运行weiboCrawler.py加concern.py、fans.py抓取原始用户关系数据结果写入文本文件或直接落 MySQLinsertUser.py把新抓到的用户数据插入user_profile表newUser.py做增量更新避免每天全量重爬从 MySQL 导出特征训练集learner目录完成模型训练与评估flask_demo加载模型content.html提供录入界面浏览器调用/predict接口mysqldump.sh是数据库备份脚本nohup.out是后台运行日志。从工程角度看爬虫和 Flask 服务都应该用nohup或systemd守护避免 SSH 断开后进程被杀# 后台启动 Flask 服务日志写入 nohup.out nohup python app.py nohup.out 21 4.3 关键文件与配置清单拿到资源后按这张表对号入座能快速知道该先看哪个文件文件/目录作用使用建议weiboCrawler.py微博基础爬虫先验证 cookies.txt 是否有效concern.py / fans.py抓关注、粉丝列表请求频率控制在每秒一次以内cookies.txt登录 Cookie失效后爬虫返回登录页 HTMLxinan.sql空表结构用于理解字段含义xinan_with_data.sql带数据完整库导入后可直接复现训练evil1.txt恶意用户 ID 黑名单用于生成标注learner训练和评估代码模型保存为 model.pklflask_demoWeb 服务先本地跑通再部署insertUser.py / newUser.py入库与增量更新注意唯一索引冲突处理mysqldump.sh数据库备份建议 crontab 每天执行注意cookies.txt是爬虫的生命线。Cookie 过期后爬虫不会立刻报错而是返回登录页的 HTML解析结果为空很多人会误以为是目标用户没有数据。我一般会写个脚本每隔一段时间请求一次用户接口返回内容里如果检测不到 “screen_name” 字段就说明 Cookie 已失效需要手动更新。5. 避坑指南微博恶意用户识别的五个典型翻车现场5.1 SQL 导入失败数据全部丢失现象导入xinan_with_data.sql时提示Unknown collation或导入成功后中文昵称全是乱码。原因SQL 文件里表结构用的是utf8mb4_bin字符集而 MySQL 客户端连接时用了系统默认的latin1或utf8两边排序规则对不上。解决导入前在 mysql 客户端先执行SET NAMES utf8mb4;再指定字符集重新导入。mysql -u root -p --default-character-setutf8mb4 weibo xinan_with_data.sql从那以后我每次导入 MySQL 都会先看一眼 init_connect 字符集宁可多写一句也不赌默认配置。5.2 模型在验证集上分数很高新用户预测全是正常用户现象交叉验证 F1 有 0.85接进 Flask 后连续预测 10 个用户全部返回malicious: 0。原因训练集里恶意用户样本占比太低模型决策面偏向多数类或者新用户数据分布变了比如注册时间、昵称风格都和训练集不一致。解决class_weightbalanced已加的情况下尝试对正常用户做人工下采样同时把阈值从 0.5 降到 0.3用最近一周新增的标注数据做增量训练。最典型的案例是训练数据里全是 2019 年的恶意脚本特征而 2023 年的恶意脚本早已换了策略所以这个任务里周期性重训不是可选项是必选动作。5.3 爬虫抓到的粉丝数全是 0现象concern.py/fans.py运行正常没有报错但抓回来的数据里followers_count全是 0。原因微博前端改版后旧接口返回字段被移除或者 Cookie 有效但请求 URL 里没带正确的 uid 参数。解决用浏览器开发者工具打开一个真实用户主页重新抓取 Ajax 接口地址确认 Cookie 是否包含SUB字段nohup.out日志中如果返回 200 但 JSON body 为空基本就是接口路径过期。这类问题靠断点调试定位不了直接看响应内容最省时间。5.4 Flask 接口第一次请求要等 10 秒现象本地运行时第一次请求/predict卡很久后面的请求又正常变快。原因joblib.load只负责把磁盘文件反序列化到内存sklearn 底层 liblinear 资源要等第一次预测时才初始化叠加了模型冷启动。解决在 Flask 启动后手动调用一次model.predict_proba([[0, 0, 0]])做预热。如果部署在公网服务器上用 Nginx 反向代理并开启 gzip首屏响应也能明显改善。5.5 MySQL 连接字符集不一致导致训练数据缺失现象用 pymysql 读出的 DataFrame 里statuses_count大量为NaN模型训练直接报 ValueError。原因数据库字段允许 NULL爬虫没抓到某些微博数时会插入 NULLpandas 读入后就是 NaN字段类型定义过窄也会导致导入时被截断为 NULL。解决SQL 查询里用COALESCE(statuses_count, 0)做兜底或者读入后用fillna(0)填充。如果特征缺失超过 30%不要填充直接删除整列。数据质量比算法复杂度更影响这个项目的最终效果。6. 验证与进阶阈值扫描与增量更新策略6.1 阈值扫描把模型调到业务需要的强度训练完模型后最该做的不是看准确率而是跑一遍阈值扫描。默认 0.5 是数学上的分界线不是业务上的最优解。恶意用户识别这种场景漏放一个恶意账号的成本远高于误伤一个正常账号所以要主动降阈值去换召回率。import numpy as np from sklearn.metrics import precision_recall_curve proba model.predict_proba(X_test)[:, 1] precision, recall, thresholds precision_recall_curve(y_test, proba) # 在召回率不低于 0.8 的前提下选 precision 最高的阈值 valid np.where(recall 0.8)[0] best_idx valid[np.argmax(precision[valid])] best_thr thresholds[best_idx] print(suggest threshold: %.3f - recall%.3f precision%.3f % ( best_thr, recall[best_idx], precision[best_idx]))逻辑说明precision_recall_curve返回每个阈值下的精确率和召回率np.where(recall 0.8)把小于业务底线的阈值全部排除再从剩下候选里选精确率最高的那个。参数说明0.8 这个底线不是固定值如果业务上可以接受 70% 召回就改成 0.7这是个业务参数不是算法参数。6.2 增量更新避免模型上线即衰减微博这类数据变化很快每个月都会出现新的恶意用户模式。我的更新策略是每天把新增的已标注样本写入new_user_label表每周把新数据和原训练集合并重跑一次逻辑回归用warm_startTrue保留旧权重作为初始值训练速度能快 20% 左右每次更新前先跑交叉验证对比 F1如果下降超过 0.05 就回滚到上一版模型一个迭代里最容易被忽略的是特征对齐。新增样本的字段如果和旧模型不一致predict_proba会直接报维度错误。每次训练前我会打印一次model.n_features_in_和训练集列名确保线上线下特征完全一致。这组方法就是从这套微博恶意用户识别项目里反复验证出来的。最开始我拿到模型只跑了一下准确率就交付结果真实环境里误报率极高。现在已经形成习惯任何二分类模型交付前强制走一遍阈值扫描再把召回率、精确率曲线和特征系数表一起提交。答辩时评委看到的不只是一个模型文件而是你清楚知道业务上线后会怎么衰减、阈值该怎么调这才是高分项目最值钱的部分。希望帮到你。本文还有配套的精品资源点击获取
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。