Python爬虫+Flask+Echarts:豆瓣图书数据分析可视化系统实战
发布时间:2026/9/25 21:22:02来源:尧图网络
每年到了毕业设计集中开工的阶段后台问得最多的就是这一类题目Python 爬虫 Echarts Flask。看起来是四块东西拼在一起实际做起来却是一条完整的数据分析链路——数据从哪来、怎么洗干净、怎么存、怎么通过后端接口交给前端最后再用图表把结论讲明白。这个“机器学习Python豆瓣图书数据分析可视化系统”的题目名字里有机器学习但核心并不是调参炼丹而是把整个项目串成一个能演示、能讲清楚、能应对答辩追问的完整作品。这个项目的目标很直接抓取豆瓣图书信息比如书名、作者、出版社、出版年份、评分和评论人数清洗后入库再用 Flask 写接口把数据以 JSON 格式返回给页面由 Echarts 渲染成折线图、饼图、柱状图和词云等可视化结果最后再塞一个轻量级的机器学习模块用来做评分预测或图书聚类。整套东西麻雀虽小五脏俱全特别适合计算机方向的学生拿来作为毕业设计也适合刚入门的同学跟着做一遍把爬虫、Web 开发、可视化和机器学习这些零散知识点串成完整的项目经验。这篇博客我按照实际动手的顺序来写从环境准备、爬虫采集、Flask 接口到 Echarts 可视化、机器学习接入最后把我在实操中踩过的坑和排查思路一并整理出来。文章里给的代码都是可以直接跑的最小实现你可以在此基础上换成其他数据源或者扩展成更完整的功能系统。1. 项目整体设计与技术选型1.1 系统模块与数据流转动手写代码之前先把整个系统拆成模块理清数据是怎么流动的这样后面写代码才不会乱。这个项目的模块可以拆成五块爬虫模块负责从豆瓣图书页面采集数据数据存储模块负责把清洗后的数据写入数据库后端接口模块用 Flask 提供 JSON 数据前端展示模块用 Echarts 渲染图表机器学习模块做基于已有数据的预测或分类。数据流非常清晰爬虫抓下来的原始数据先做去重和格式清洗然后写入 SQLite。Flask 启动后前端页面通过 Ajax 请求后端的/api/xxx接口Flask 从数据库查出对应维度的数据用jsonify返回 JSON前端拿到 JSON 后调用 Echarts 的setOption渲染图表。机器学习模块则是离线训练好模型保存成文件Flask 启动时加载模型通过一个单独的表单页面接收用户输入并返回预测结果。这个流程可以概括成一句话爬取、清洗、存库、接口、图表。这也是答辩时最容易被问到的主线建议先把这条链路背熟不管老师问哪个环节你都能说出数据从哪来、经过哪些处理、最后展示成什么。1.2 为什么是 Flask Echarts 这套组合技术选型是答辩时候的高频问题最好提前想清楚不要只会说“大家都用这个”。后端框架上Flask 和 Django 我都用过。Django 功能齐全自带 Admin 后台、ORM、认证系统适合大型项目但结构比较重学起来成本高而且它默认的模板和 ORM 方式对新手不友好。Flask 是微框架路由写法直观没有太多强制约束一个app.py就能把接口跑起来。这个项目本质上是一个以接口和页面展示为主的分析系统Flask 的轻量特性正好合适。如果你想把项目往工程化方向包装还能再加蓝图 Blueprint 和工厂模式这些都是加分项。数据可视化上Echarts 比 D3 和 Plotly 更适合这类毕业设计。原因很现实Echarts 中文文档全示例代码丰富社区里各种配置项一搜就有API 设计对新手友好初始化一个图表只要echarts.init加setOption两步图表默认样式也比较精致能做出好看的答辩截图。D3 灵活但学习曲线太陡Plotly 更偏向科研绘图交互上不如 Echarts 灵活。数据库方面SQLite 是这类项目的最佳起点。它是单文件数据库不需要安装服务端代码里用 Python 自带的sqlite3模块就能操作。答辩演示时不用像 MySQL 那样起服务、配账号。如果你的项目要求必须用 MySQL可以在代码里改成pymysqlSQL 基本不用换只是连接方式不同。选型这种事没有绝对标准关键是你得能解释出为什么选它。哪怕你说“选用 SQLite 是为了简化部署”也比一句“大家都用”诚恳得多。2. 环境准备与项目初始化2.1 Python 环境与依赖安装先说环境。Python 建议使用 3.9 到 3.11 之间的版本太老的版本对 sklearn 和 Flask 的新特性支持不好太新的版本偶尔会遇到依赖包还没适配的情况。如果你电脑上已经装好了 Python直接打开终端确认版本python --version接下来创建虚拟环境。这一步很多人偷懒跳过直接用全局环境装依赖结果后面装包时把系统环境搞得一团糟。我这里强烈建议建一个 venv隔离项目依赖python -m venv venvWindows 下激活方式venv\Scripts\activatemacOS / Linux 下激活方式source venv/bin/activate激活成功后命令行前面会出现(venv)标记这时候再用 pip 安装依赖所有包都会装进这个虚拟环境不会影响全局。本项目需要安装的依赖如下pip install flask requests beautifulsoup4 lxml pandas scikit-learn joblib逐个说明一下用途flask提供 Web 服务requests发 HTTP 请求采集页面beautifulsoup4和lxml负责解析 HTMLpandas做数据处理scikit-learn跑机器学习模型joblib用来保存和加载模型文件。如果你用的是 VSCode装完后记得按CtrlShiftP打开命令面板输入 “Python: Select Interpreter”选择刚才创建的 venv 环境。不然你终端里已经激活了 venvVSCode 却还用的全局解释器运行代码时会报找不到模块的错误这类问题我见过太多次了。2.2 Flask 项目目录结构一个清晰的项目结构不仅能让你自己写代码时少迷路导师看目录也会觉得你工程素养不错。我常用的目录结构是这样的douban_analysis/ ├── app.py # Flask 主入口 ├── requirements.txt # 依赖清单 ├── spider/ │ ├── __init__.py │ └── douban_spider.py # 爬虫模块 ├── models/ │ ├── __init__.py │ ├── database.py # 数据库操作 │ └── ml_models.py # 机器学习训练与预测 ├── static/ │ ├── js/ │ │ └── echarts.min.js # 本地 Echarts 文件 │ ├── css/ │ │ └── style.css │ └── data/ │ └── china.json # 中国地图 GeoJSON ├── templates/ │ ├── index.html # 可视化大屏页面 │ └── predict.html # 机器学习预测页面 └── data/ └── books.db # SQLite 数据库文件templates和static这两个目录是 Flask 默认约定的模板文件必须放进templates静态资源必须放进static。如果你把 HTML 文件放错位置运行时会直接报TemplateNotFound这不是代码逻辑问题而是目录问题。这条规则记住能省很多排查时间。2.3 初始化数据库表数据库设计不复杂但字段类型要提前想清楚。一张表存图书信息就够了CREATE TABLE IF NOT EXISTS books ( id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT NOT NULL, author TEXT, publisher TEXT, pub_date TEXT, rating REAL, rating_count INTEGER, price REAL, category TEXT );这里有两个细节。评分用REAL而不是INTEGER因为豆瓣评分有小数比如 8.7 分评论人数用INTEGER因为它是整数后面做机器学习特征时也会更干净。pub_date用字符串存因为豆瓣上有的日期精确到年有的精确到月日直接用字符串可以避免解析异常。创建表的代码可以放在独立的models/database.py里每次启动 Flask 时自动执行import sqlite3 DB_PATH data/books.db def get_db(): conn sqlite3.connect(DB_PATH) return conn def init_db(): conn get_db() cur conn.cursor() cur.execute( CREATE TABLE IF NOT EXISTS books ( id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT NOT NULL, author TEXT, publisher TEXT, pub_date TEXT, rating REAL, rating_count INTEGER, price REAL, category TEXT ) ) conn.commit() cur.close() conn.close()3. 豆瓣图书爬虫模块的实现3.1 分析页面结构先手动看再写代码爬虫项目最容易犯的错误是拿到网址就写代码跑完发现解析不到数据。正确做法是先打开页面按下 F12 查看元素结构搞明白数据放在哪个标签里再动手写解析逻辑。豆瓣图书 Top 250 的页面结构整体比较规整每本书都放在一个tr标签里书的具体信息则分布在td下面的多个标签内。书名在a标签的title属性里作者和出版社信息集中在p标签中评分在span.rating_nums里评论人数在span.pl里。用requests请求页面时大部分网站会检查请求头里的User-Agent。如果你用的是默认的 Python 请求头很容易被服务端识别为爬虫。建议在请求头中设置一个常见的浏览器标识import requests from bs4 import BeautifulSoup headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 } def fetch_page(start): url fhttps://book.douban.com/top250?start{start} resp requests.get(url, headersheaders, timeout10) resp.encoding utf-8 return BeautifulSoup(resp.text, lxml)这里设置了超时时间为 10 秒避免某个请求卡住导致整个爬虫停在那里不动。resp.encoding需要显式指定为utf-8不然中文容易出现乱码。3.2 解析单页数据并入库解析的核心逻辑是遍历页面中的所有tr.item节点从每个节点中提取字段def parse_page(soup): items [] for item in soup.select(tr.item): title_tag item.select_one(a[title]) title title_tag[title] if title_tag else None p_tag item.select_one(p) p_text p_tag.text.strip().split( / ) if p_tag else [] rating_tag item.select_one(span.rating_nums) rating float(rating_tag.text) if rating_tag else None count_tag item.select_one(span.pl) count_text count_tag.text if count_tag else rating_count int(.join(ch for ch in count_text if ch.isdigit())) if count_text else 0 items.append({ title: title, author: p_text[0] if len(p_text) 0 else None, publisher: p_text[-2] if len(p_text) 1 else None, pub_date: p_text[-1] if len(p_text) 1 else None, rating: rating, rating_count: rating_count }) return items这段代码里有一个比较重要的细节rating_nums是评分而span.pl里包含的是“(12345人评价)”这种文本必须先过滤掉非数字字符再转成整数。Top 250 一共有 10 页每页 25 本。爬取时要注意控制频率我一般每请求一页后time.sleep(1)这样既不会给目标网站造成压力也避免请求过快被封。完整爬取逻辑只需要加一个循环import time for start in range(0, 250, 25): soup fetch_page(start) items parse_page(soup) save_to_db(items) time.sleep(1)3.3 去重与数据清洗爬下来的数据不一定干净最常见的三个问题是重复数据、空值和格式不统一。重复问题可以用(title, author)作为唯一判断条件在插入前先查一遍存在就跳过。更稳妥的方式是在建表时直接加唯一索引CREATE UNIQUE INDEX IF NOT EXISTS idx_unique_book ON books(title, author);这样即使爬虫重复采集数据库层也帮你挡住了重复记录。空值处理要看字段。书名是最核心的字段为None的数据直接丢弃评分缺失的书可以保留但在后续可视化时要做好空值过滤出版社缺失则不影响主体分析。作者和出版信息在豆瓣上是以作者 / 译者 / 出版社 / 出版年的格式拼在一起的。这种格式解析起来需要踩几个坑因为有的书有多个作者有的书没有译者如果你固定取值的位置很容易取错。我更推荐用“从后往前取”的方式最后一个元素通常是出版年份倒数第二个通常是出版社作者则取第一个元素。如果中间多了译者作者字段仍然正确。3.4 爬虫合规与实操心态我们做一个毕业设计项目重点是掌握数据分析链路。爬取数据时要注意控制请求频率遵守网站的 robots 协议数据只用于学习演示不在公开场合大规模传播。这些要求我在代码里已经帮你做了希望你在扩展功能时也保持同样的习惯。另外有些同学喜欢把反爬策略研究得很深比如搭建代理池、自动切换 IP这些技能确实存在但毕业设计阶段真不需要。你要做的是一套能解释、能演示的系统而不是一个对抗系统。遇到请求被拦截优先检查请求头和频率这两个因素解决掉之后绝大多数问题都能解决。4. Flask 接口与 Echarts 页面搭建4.1 Flask 路由的设计与 JSON 接口Flask 的代码不需要写得复杂但路由要清晰。我的建议是每个图表对应一个接口比如评分分布一个接口、出版年份趋势一个接口、图书分类占比一个接口这样前后端联调时对得上号写起来也不用在一个接口里塞一堆分支判断。主入口文件app.py的基本写法from flask import Flask, render_template, jsonify from models.database import get_db app Flask(__name__) app.route(/) def index(): return render_template(index.html) app.route(/api/rating_distribution) def rating_distribution(): conn get_db() cur conn.cursor() cur.execute( SELECT CAST(rating AS INT) AS score, COUNT(*) AS cnt FROM books WHERE rating IS NOT NULL GROUP BY score ORDER BY score ) rows cur.fetchall() cur.close() conn.close() return jsonify({x: [r[0] for r in rows], y: [r[1] for r in rows]})注意这里我把字段名直接设计成前端需要的x和y省去前端二次加工的过程。JSON 接口的核心思路是数据库查出结果转成前端最方便消费的格式然后返回。格式越简单前端代码越不容易出 bug。本地开发时app.run(debugTrue)很方便改代码自动重启。如果要让同局域网手机访问需要改成app.run(host0.0.0.0, port5000, debugTrue)答辩时如果老师想看系统演示用手机直接访问你电脑的 IP 加端口就行不用拷贝工程到另一台机器上。4.2 前端页面引入 Echarts前端页面最好用一个单页面承载多个图表。由于系统需要从后端接口取数据推荐在页面加载后通过fetch请求数据再初始化图表。模板文件templates/index.html的核心结构如下!DOCTYPE html html langzh-CN head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 title豆瓣图书数据分析系统/title script src{{ url_for(static, filenamejs/echarts.min.js) }}/script style .chart-box { width: 100%; height: 400px; margin-bottom: 20px; } /style /head body div idchart1 classchart-box/div div idchart2 classchart-box/div script function renderChart(containerId, option) { const chart echarts.init(document.getElementById(containerId)); chart.setOption(option); } fetch(/api/rating_distribution) .then(res res.json()) .then(data { renderChart(chart1, { title: { text: 豆瓣图书评分分布 }, tooltip: {}, xAxis: { type: category, data: data.x }, yAxis: { type: value }, series: [{ name: 书籍数量, type: bar, data: data.y }] }); }); /script /body /html这里有一个看起来很基础但特别容易踩的坑图表的容器必须有明确的高度。如果容器的高度是 0 或者autoEcharts 初始化后渲染会一片空白。最保险的做法是给每个.chart-box设置height: 400px或者通过window.onresize调整时重新调用chart.resize()。4.3 各类图表的落地思路与配置要点Echarts 能做很多图表类型但在毕业设计里不需要贪多选四类最合适的就够了。饼图适合展示图书分类占比比如小说、历史、科技、艺术各占多少比例。数据来自category字段按类别分组计数。为了让图更直观可以在option里设置legend和tooltip这样鼠标悬停时能显示具体的数量和占比。折线图和柱状图适合展示年份与出版数量的关系。比如统计每年出版的图书数量或者逐年平均评分变化。这种图最能显示出“数据分析”的价值建议重点制作。词云图适合展示书名中的热门关键词。标准版 Echarts 不包含词云组件需要额外加载echarts-wordcloud插件。实现时先用 jieba 对书名做分词统计词频再把数据传给词云组件。中国地图适合展示作者或出版社的地域分布。这个做起来稍微特殊一点Echarts 5 默认没有内置中国地图数据你需要准备一份中国地图的 GeoJSON 文件然后通过echarts.registerMap注册后才能使用。数据部分把出版社或作者所在省份统计出来用visualMap控制颜色深浅做成“色斑图”效果非常漂亮。柱状图渐变色也是加分项。Echarts 柱状图支持颜色渐变只需要给柱子的itemStyle.color设置一个线性渐变color: { type: linear, x: 0, y: 0, x2: 0, y2: 1, colorStops: [ { offset: 0, color: #83bff6 }, { offset: 1, color: #2f7fd0 } ] }这个渐变效果做出来的柱状图在答辩大屏上会显得很有质感代码也不复杂建议用上。5. 机器学习模块与轻量模型接入5.1 机器学习的定位与选题逻辑很多同学一看到题目里有“机器学习”就紧张觉得要搞深度学习、要训练大模型。实际上这个项目里的机器学习模块定位是“锦上添花”不是“力挽狂澜”。你要做的是在已有数据的基础上完成一个可解释、可演示的小模型让老师觉得你对机器学习不是只会调包。比较好的切入点是两个模型一进一出一个用线性回归预测图书评分一个用 KMeans 对图书聚类打标签。线性回归负责回答“什么样的书评分可能更高”KMeans 负责回答“这些书能分成哪几类”。两个模型原理都很直观解释起来也轻松还能体现出你对特征工程的理解。5.2 用线性回归预测图书评分预测图书评分的思路是把图书的一些属性作为特征比如评论数量、出版年份、页数、所属类别的编码值把评分作为目标值训练一个线性回归模型。实际出来的效果往往不那么理想因为图书评分真的很难用几个数值特征预测准评分受内容质量影响很大这是客观存在的。但故意的“效果不佳”恰好可以作为答辩里的一个真实话题你可以解释为什么模型误差高哪些特征贡献最大后续怎么优化。这种真实感远比你硬编数据强。下面是一段可以在 Jupyter Notebook 或单独脚本里先跑通的最小实现import pandas as pd from sklearn.model_selection import train_test_split from sklearn.linear_model import LinearRegression from sklearn.metrics import mean_absolute_error import joblib df pd.read_sql(SELECT rating, rating_count, CAST(substr(pub_date,1,4) AS INT) AS year FROM books, sqlite:///data/books.db) df df.dropna() X df[[rating_count, year]].values y df[rating].values X_train, X_test, y_train, y_test train_test_split(X, y, test_size0.2, random_state42) model LinearRegression() model.fit(X_train, y_train) y_pred model.predict(X_test) print(MAE:, mean_absolute_error(y_test, y_pred)) joblib.dump(model, models/rating_model.pkl)这里打印的MAE是平均绝对误差。如果值在 0.5 左右说明模型预测的评分平均偏差半颗星这个结果认真讲出来其实不算差。5.3 KMeans 聚类给图书打标签聚类这个点很讨巧因为不需要真实标签单纯靠特征把书分成几堆然后人工给每一堆起个名字比如“高分冷门”“低分热门”“大众经典”等。KMeans 的代码更简单from sklearn.cluster import KMeans from sklearn.preprocessing import StandardScaler X df[[rating, rating_count, year]].values X_scaled StandardScaler().fit_transform(X) km KMeans(n_clusters3, random_state42, n_init10) df[cluster] km.fit_predict(X_scaled)聚类前做标准化非常重要。rating的取值范围是 0 到 10rating_count可能上万year是一千九到两千年之前的年份。如果直接用原始数值评论数量这个特征会主导聚类结果评分的贡献被冲掉。用StandardScaler把每个特征压到同一尺度聚类结果才有意义。n_init10这个参数在 sklearn 新版本里默认值改了建议显式写上避免以后版本升级时出现参数变动问题。聚类完成后你可以统计每个簇的中心点特征给簇起名字然后作为标签存回数据库。前端在展示图书详情时可以标注这本书属于哪类这个功能在实际产品里非常常见。5.4 在 Flask 中加载与使用模型模型训练好之后不要在每次请求时重新训练那是灾难。正确做法是在 Flask 启动时加载一次放在全局变量里请求进来时直接调用。from flask import Flask, request, jsonify import joblib app Flask(__name__) model joblib.load(models/rating_model.pkl) app.route(/predict) def predict(): count int(request.args.get(count, 0)) year int(request.args.get(year, 2000)) pred model.predict([[count, year]])[0] return jsonify({predicted_rating: round(float(pred), 2)})前端可以做一个简单的输入页面让用户手动输入评论数和出版年份点击按钮后拿到预测评分。这个交互功能虽然简单但在演示时效果很好因为它是实时计算的结果不是静态图表。这里还要提醒一个问题joblib.load加载的模型必须和训练时用的特征顺序完全一致。你训练时用的特征是[rating_count, year]预测时输入也必须是这个顺序换一下结果就完全错误。6. 常见问题与排查技巧实录6.1 问题排查速查表实操中会遇到不少问题我把最典型的情况列成了一张速查表症状可能原因处理办法requests 请求返回 418 或 403缺少 User-Agent或请求太频繁设置浏览器 User-Agent拉长请求间隔爬虫解析出来的字段全部为 None页面结构变化或选器拼写错误打开浏览器检查真实 HTML 结构数据库插入时中文乱码写入前编码不对请求时设置resp.encoding utf-8写 CSV 时用utf-8-sigFlask 页面显示 TemplateNotFoundHTML 没有放进 templates 目录把文件放入正确目录检查目录名拼写Echarts 图表空白容器没有高度或未正确初始化给容器设置固定高度确认echarts.init在 DOM 加载后执行fetch 拿不到数据接口报 500 或路由写错先直接访问接口地址检查浏览器控制台网络请求模型加载报错文件不存在模型训练后没有保存到目标路径训练完成后检查 models 目录下是否有.pkl文件6.2 请求被拦截的排查思路爬虫最常遇到的反馈就是请求被拦截。如果你看到返回内容不是图书页面而是验证页优先检查两点请求头是否完整、请求频率是否合理。设置User-Agent后仍然被拒可以考虑在请求头中补上Accept、Accept-Language等常见字段让请求看起来更像浏览器行为。但这些最终要有限度。数据量差不多够分析就够了真的不用把全站图书都抓下来。6.3 Echarts 图表显示异常的定位顺序图表不显示时不要直接怀疑 Echarts 配置写错了按照这个顺序排查先在浏览器按 F12 打开开发者工具看 Network 面板里接口请求是否返回了正常数据再看 Console 面板有没有 JavaScript 报错最后看容器元素是否在不在页面上、有没有显式高度。绝大多数 Echarts 空白问题都是后面两个原因。接口数据没拿到前端代码再正确也没用容器高度为 0 时setOption执行了但画布撑不起来视觉上就是空白。6.4 机器学习部分的几个深坑机器学习模块最大的坑不在算法而在数据准备。特征里有缺失值的时候dropna()会直接删掉部分数据如果缺失比例过高剩下的数据可能不足以训练模型。处理前先看一眼缺失比例数据量够就直接删不够就要考虑填充。第二个坑是特征范围差异过大前面说过的标准化问题。第三个坑是类别特征没有编码如果你直接在 DataFrame 里塞一列字符串分类sklearn 会报错。处理方式要么用pd.get_dummies做独热编码要么用LabelEncoder做整数映射。想做出好看的聚类可视化可以取聚类后的数据做 PCA 降维把多维特征压缩成两个主成分再画散点图。这样你能直观看到书的类别分布答辩时可以放这张图。7. 答辩演示与项目扩展建议7.1 如何把项目“讲”出来项目做完最怕答辩时只能干巴巴地说“我用了爬虫、Flask、Echarts”。我的建议是准备一条演示主线按顺序把图讲成一个故事。比如“首先我们爬取了豆瓣 250 本热门图书的基本数据清洗后入库然后从多个维度进行分析可以看到评分分布集中在 8 分以上说明榜单整体质量较高接下来看出版年份分布发现近年出版的书占比在上升出版社地域分布显示大部分集中在东部地区最后我们用机器学习方法预测图书评分并尝试对图书聚类分类。”这个演示脚本不需要背理解每个图表背后的分析逻辑就行了。老师追问任何一个环节你都能从数据流的角度回应。7.2 前端大屏的细节优化同一个系统视觉效果差别很大。想让页面更有“大屏感”可以用深色背景搭配不同配色把多个图表放进栅格布局。Echarts 图表本身支持深色模式通过设置backgroundColor和文字颜色即可实现。另外可以加一个简单的筛选交互比如用下拉框选择图书分类图表数据随之变化。这样页面就不再是一组静态图片而是一个真正的数据分析系统展示效果提升明显。7.3 后续还能扩展什么这套系统扩展性其实很好。如果你想把项目做成更完整的数据分析平台可以增加图书详情页展示单本书的评分走势可以接入自动更新任务每天定时抓取新数据也可以加上用户登录功能做成支持多用户使用的在线分析工具。如果你对推荐系统感兴趣还能在现有数据上做一个简单的基于相似度的图书推荐计算图书间的相似度推荐“和你喜欢的书风格最接近的其他书”。这些扩展方向都能成为答辩亮点而且都建立在你已经跑通的基础框架上。7.4 写在最后的经验之谈我做这类项目最大的体会是毕业设计不需要追求“大而全”更重要的是把一条主线做完整。爬虫能用、数据是真实跑出来的、接口能通、图表能展示、模型能跑出结果哪怕模型效果一般整个项目在演示和答辩时都站得住脚。建议你先按这篇博客把最小版本完整跑通再逐步加功能。你会发现后面每个深化的点都有清晰的方向而不会陷入“不知道从哪里下手”的状态。如果你在实践过程中遇到其他问题欢迎在评论里把现象和代码片段贴出来我看到后会根据实际经验给你排查建议。
网站建设高端定制企业官网