1. 项目背景与核心价值
最近在牛客网刷题时发现一个痛点:虽然平台提供了丰富的题库资源,但缺乏系统性的进度追踪和每日规划功能。作为程序员,我们都知道持续刷题对保持编码手感、备战技术面试有多重要。这个项目就是为了解决这个问题而生——通过自动化工具实现刷题进度可视化+每日一题智能推荐。
这个工具的核心价值在于:
- 自动同步牛客网账号的刷题记录
- 生成多维度的刷题数据看板(题型分布/难度曲线/时间热力图)
- 基于个人薄弱环节智能推荐每日一题
- 支持自定义刷题计划与成就系统
2. 技术架构解析
2.1 数据采集层
采用Python + Requests模拟登录牛客网,通过分析页面DOM结构发现:
- 用户刷题记录存储在
/profile/record接口 - 题目元数据通过
/question/fetch获取 - 需要处理Cloudflare反爬机制(添加随机延迟+UserAgent轮询)
python复制def fetch_solved_problems(user_id):
session = requests.Session()
# 模拟登录流程
login_payload = {
'username': os.getenv('NIUKE_USER'),
'password': os.getenv('NIUKE_PWD')
}
session.post('https://www.nowcoder.com/login', data=login_payload)
# 获取刷题记录
record_url = f'https://www.nowcoder.com/profile/{user_id}/record'
resp = session.get(record_url)
soup = BeautifulSoup(resp.text, 'html.parser')
# 解析DOM获取已做题目标签...
2.2 数据处理层
使用Pandas进行数据清洗:
- 题型分类(算法/数据库/系统设计)
- 难度标准化(牛客的"中等"≈LeetCode Medium)
- 时间序列分析(刷题频率/时间段偏好)
python复制def analyze_problems(df):
# 难度映射表
difficulty_map = {'简单':1, '中等':2, '较难':3, '困难':4}
df['difficulty'] = df['difficulty'].map(difficulty_map)
# 按周分组统计
weekly_stats = df.resample('W', on='solve_time').agg({
'problem_id':'count',
'difficulty':'mean'
})
return weekly_stats
2.3 推荐算法
基于协同过滤+内容相似度混合模型:
- 找到与用户解题模式相似的其他用户
- 提取题目特征(知识点标签/公司出现频率)
- 生成推荐分数 = 0.6协同过滤 + 0.4内容相似度
注意:牛客网的题目标签体系不如LeetCode完善,需要额外做NLP处理题面提取关键词
3. 核心功能实现
3.1 进度追踪看板
使用Echarts实现动态可视化:
- 环形图展示题型分布
- 折线图显示难度进阶曲线
- 日历热力图记录每日刷题量
javascript复制// 示例:日历热力图配置
option = {
tooltip: {
formatter: function (params) {
return `${params.value[0]}<br/>刷题量: ${params.value[1]}`
}
},
visualMap: {
min: 0,
max: 10,
calculable: true,
inRange: {
color: ['#ebedf0', '#c6e48b', '#7bc96f', '#239a3b']
}
}
}
3.2 每日一题推荐
推荐逻辑优先级:
- 近期高频考察题型(通过牛客讨论区爬取)
- 用户最近错题相似题型
- 知识图谱中的相邻节点(如做完二叉树就该做DFS)
python复制def recommend_daily_problem(user_id):
# 获取用户薄弱知识点
weak_tags = get_weak_tags(user_id)
# 获取热门题目
hot_problems = scrape_hot_problems()
# 计算推荐分数
candidates = []
for pid in hot_problems:
score = 0
if match_tags(pid, weak_tags):
score += 0.7
if is_high_frequency(pid):
score += 0.3
candidates.append((pid, score))
return max(candidates, key=lambda x:x[1])[0]
4. 部署与使用指南
4.1 本地运行方案
- 安装依赖:
bash复制pip install requests beautifulsoup4 pandas numpy scikit-learn
- 配置环境变量:
bash复制export NIUKE_USER="your_account"
export NIUKE_PWD="your_password"
- 启动Flask服务:
python复制from flask import Flask
app = Flask(__name__)
@app.route('/daily-problem')
def get_daily_problem():
user_id = request.args.get('uid')
return jsonify(recommend_daily_problem(user_id))
if __name__ == '__main__':
app.run(port=5000)
4.2 数据更新策略
建议设置定时任务(Crontab):
- 每天7:00同步前一天的刷题记录
- 每周日23:00生成周度报告
- 每月最后一天生成月度分析
bash复制# 每日同步
0 7 * * * /usr/bin/python3 /path/to/sync.py >> /var/log/niuke_tracker.log
5. 踩坑实录与优化建议
5.1 反爬对抗经验
牛客网对频繁请求有严格限制,实测有效的方法:
- 请求间隔随机化(2-5秒)
- 使用住宅代理IP轮询
- 模拟鼠标移动事件(通过Selenium)
重要:不要设置低于1秒的请求间隔,否则可能触发账号封禁
5.2 性能优化点
- 使用SQLite缓存题目元数据
- 增量更新刷题记录(记录最后同步时间戳)
- 预计算推荐结果(每日凌晨批量处理)
python复制# 增量更新示例
last_sync = get_last_sync_time()
new_records = []
for record in fetch_new_records():
if record['time'] > last_sync:
new_records.append(record)
update_database(new_records)
set_last_sync_time(datetime.now())
5.3 推荐算法调参
经过AB测试得出的最佳参数组合:
- 协同过滤权重:0.6(高于0.7会导致推荐过于保守)
- 题目新鲜度衰减系数:每周降低15%
- 难度阶梯系数:建议每次提升不超过0.5(如上次做中等难度,下次推荐中等或中等偏难)
这个项目最让我惊喜的是,通过分析自己的刷题数据,发现周三晚上8-10点是解题效率最高的时段。现在我会特意把难题目留到这个时间段处理,正确率提升了20%左右。