资讯动态

豆瓣电影数据分析系统:Flask+pandas+ECharts全栈毕设项目

发布时间:2026/10/29 11:37:21 来源:尧图企业网站定制
简介本资源是一套面向本科毕业设计与Python数据分析初学者的完整实战项目聚焦豆瓣电影数据采集、清洗、分析与可视化全流程解决学生在课程设计中缺乏端到端工程实践参考的痛点。压缩包共1054个文件含688个核心Python源码覆盖Flask后端、爬虫模块、pandas数据处理及ECharts前端集成、36张JPG图表素材、24个说明类TXT文档、15个HTML可视化页面及1个可执行SQL建表脚本整体30.07MB结构清晰便于按模块学习调试。已有256人下载学习适合需快速搭建毕业设计原型、理解Web爬虫数据库可视化技术栈协同逻辑的学习者。资源提供开箱即用的MySQL数据库方案、PyCharm环境配置指引、完整论文框架及可直接运行的前后端代码包含activate等虚拟环境脚本与datas.csv原始数据样例显著降低部署门槛与调试成本。1. 这不是又一个“爬豆瓣练手项目”它是一套能直接答辩、可部署、带完整数据闭环的毕业设计系统你肯定见过那种“用 Python 爬豆瓣 Top250画个柱状图就叫数据分析”的毕设 demo——跑得通但一问细节就卡壳数据怎么存并发怎么控页面刷新后图表消失论文里写的“实时更新”根本没实现这个项目不是。它把「爬虫→清洗→存储→API→Web 展示→交互图表→导出报告」全链路压进一个可运行、可调试、可改写、可答辩的 Flask 工程里。核心不是“爬到数据”而是“让数据活起来”比如点击某部电影自动加载该导演所有作品的评分趋势筛选“2010 年后上映豆瓣评分 ≥8.5”的影片一键生成含词云热力图TOP10 表格的 PDF 报告后台提供/api/movie?year2022genre剧情这类真可用的 REST 接口。适合正在赶毕设 deadline 的本科生也适合想快速搭建数据展示原型的初级开发——它不炫技但每一步都经得起导师点开 Chrome DevTools 查网络请求、翻数据库看表结构、进终端看日志报错。2. 项目结构与技术栈Flask 是骨架pandas 是血液ECharts 是皮肤这个项目不是“Flask ECharts”两个库拼凑出来的玩具而是一个有明确分层、职责清晰、能支撑中等规模数据展示的 Web 应用。我拆包后第一件事就是看requirements.txt和目录结构确认它没在关键路径上埋坑——比如用urllib写爬虫却没处理反爬或用sqlite存万级电影数据却没加索引。结果很稳它用requestsfake_useragent模拟真实浏览器行为pandas做全量数据清洗非简单pd.read_csvMySQL作为主数据库附带建表 SQL 脚本Flask-SQLAlchemy管理 ORM前端完全基于ECharts 5.x的原生 JS API非封装库所有图表配置项都暴露在 Python 后端方便动态生成。2.1 目录结构5 个核心文件夹撑起整个数据流项目解压后是标准的 Flask 结构但比教学 Demo 多了两层现实约束douban-movie-analyzer/ ├── app/ # 主应用包 │ ├── __init__.py # Flask 实例创建、蓝本注册、数据库初始化 │ ├── models.py # Movie、Director、Genre 等 6 张表的 SQLAlchemy 模型定义含外键、索引 │ ├── crawler/ # 独立爬虫模块非脚本是可 import 的包 │ │ ├── __init__.py │ │ ├── douban_spider.py # 核心爬虫支持断点续爬、自动识别验证码调用本地 OCR、限速控制 │ │ └── utils.py # 公共工具URL 构造器、HTML 解析器lxml cssselect、异常重试装饰器 │ ├── services/ # 业务逻辑层关键避免把计算逻辑塞进视图函数 │ │ ├── data_processor.py # pandas 清洗主入口去重、空值填充用均值/众数、类型转换、特征工程如“上映年份”转“年代区间” │ │ └── chart_generator.py # 图表数据组装器接收参数 → 查询 DB → pandas 聚合 → 返回 ECharts 所需 JSON 格式 │ ├── routes/ # 路由层轻量只做参数校验和调用 service │ │ ├── __init__.py │ │ ├── main.py # 首页、搜索页、详情页路由 │ │ └── api.py # /api/movie, /api/genre, /api/trend 等 8 个 REST 接口 │ └── static/ # 前端资源 │ ├── css/ │ ├── js/ # 所有 ECharts 初始化代码每个页面一个 JS 文件如 dashboard.js │ └── uploads/ # 用户上传的 CSV用于扩展分析——这个设计很务实 ├── migrations/ # Flask-Migrate 生成的数据库迁移脚本支持从空库一键建表初始数据 ├── scripts/ # 实用脚本非必须但极大提升效率 │ ├── init_db.py # 执行 SQL 脚本初始化数据库含 1000 条模拟数据防首次启动白屏 │ └── export_report.py # 命令行导出 PDF 报告调用 weasyprint ├── config.py # 配置中心DEBUG/PRODUCTION 模式切换、数据库 URL、爬虫并发数、超时时间 ├── run.py # 启动入口flask run -h 0.0.0.0 -p 5000 └── requirements.txt # 明确版本pandas1.5.3, flask2.2.5, pymysql1.1.0, echarts-py0.1.9注意这是 ECharts 的 Python 封装仅用于服务端生成配置前端仍用原生 JS提示app/crawler/是独立模块意味着你可以把它抽出来单独跑python -m app.crawler.douban_spider --start 1 --end 500不影响 Web 服务。这种解耦对毕设答辩特别友好——导师问“爬虫怎么写的”你直接切到爬虫目录演示而不是在routes/main.py里翻几百行混在一起的代码。2.2 技术选型为什么是这组组合不是 FastAPI不是 Streamlit有人会问现在都用 FastAPI 写 API为啥还用 Flask答案很实在毕业设计评审标准里“可维护性”和“教学规范性”权重远高于“性能”。Flask 的显式路由、清晰的分层models/services/routes、成熟的 SQLAlchemy ORM 文档让导师能一眼看懂数据流向而 FastAPI 的依赖注入、异步模型在毕设场景下反而增加理解成本。至于不用 Streamlit因为 Streamlit 本质是“Python 脚本转 Web”它无法满足毕设要求的“前后端分离”哪怕只是逻辑分离和“可部署性”——Streamlit App 部署需要额外进程管理而这个项目gunicorn -w 4 -b 0.0.0.0:5000 run:app一行命令就能上线。pandas 的选择更是血泪经验早期我见过学生用纯 Python 字典处理 2000 电影数据排序、分组、统计全靠 for 循环页面加载要 8 秒。而本项目services/data_processor.py里一个df.groupby(year)[rating].mean().round(2)就搞定十年平均分趋势执行时间 200ms。这不是炫技是让“数据分析”真正发生——否则所谓“分析”不过是把原始数据换个格式打印出来。ECharts 没用 Vue/React 封装库如vue-echarts是因为毕设答辩时导师大概率不会装 Node.js 环境。原生 JS 方式echarts.init(dom).setOption(option)保证你拷贝static/js/dashboard.js到任意 HTML 页面都能跑零依赖。2.3 数据库设计6 张表如何支撑复杂查询models.py定义了 6 张表不是为了炫技而是解决真实分析需求表名字段关键设计意图索引movieid, title, rating, year, duration, intro, poster_url电影主表rating为 DECIMAL(3,1) 类型非字符串PRIMARY KEY, INDEX(year), INDEX(rating)directorid, name导演信息PRIMARY KEY, UNIQUE(name)movie_directormovie_id, director_id多对多关联表一部电影可有多个导演PRIMARY KEY(movie_id, director_id), INDEX(director_id)genreid, name类型字典表剧情、喜剧、动作...PRIMARY KEY, UNIQUE(name)movie_genremovie_id, genre_id多对多关联表PRIMARY KEY(movie_id, genre_id), INDEX(genre_id)crawl_logid, start_page, end_page, status, created_at爬虫任务日志支持断点续爬INDEX(status), INDEX(created_at)注意movie_director和movie_genre是典型的关联表避免在movie表里用逗号分隔的director字段如张艺谋,陈凯歌。这样设计后SELECT d.name, COUNT(*) FROM movie m JOIN movie_director md ON m.idmd.movie_id JOIN director d ON md.director_idd.id WHERE m.year 2010 GROUP BY d.name ORDER BY COUNT(*) DESC LIMIT 10才能高效执行。我在本地 MySQL 8.0 上测试过10 万条记录下该查询耗时 0.3s。3. 核心模块拆解一个请求从进入到返回的完整链路我们以最典型的场景切入用户在首页点击“近五年高分电影 TOP10”卡片页面加载出排行榜表格和评分分布直方图。这个看似简单的操作背后是 5 层模块协同工作。下面我带你逐层拆解代码全部来自源码包无任何删减。3.1 路由层routes/api.py中的/api/top_movies接口# app/routes/api.py from flask import Blueprint, jsonify, request from app.services.chart_generator import get_top_movies_by_year_range api_bp Blueprint(api, __name__) api_bp.route(/api/top_movies, methods[GET]) def top_movies_api(): # 1. 参数校验强制 year_start/year_end且为整数 try: year_start int(request.args.get(year_start, 2019)) year_end int(request.args.get(year_end, 2023)) limit int(request.args.get(limit, 10)) except ValueError: return jsonify({error: year_start/year_end must be integers}), 400 # 2. 范围校验防止传入 1900 或 3000 if not (2000 year_start 2030 and 2000 year_end 2030): return jsonify({error: year out of valid range [2000, 2030]}), 400 # 3. 调用业务层传入参数 result get_top_movies_by_year_range(year_start, year_end, limit) # 4. 统一返回格式data 字段包裹结果status 字段标识成功 return jsonify({ status: success, data: result, meta: {count: len(result)} })这段代码的价值在于防御性编程它没把参数校验丢给前端也没用request.args.get(year_start, 2019)就直接传给数据库——而是先int()强转并捕获ValueError再做业务范围检查。这是很多毕设项目翻车的第一步前端传个abc后端int(abc)直接 500 错误页面白屏。而这里返回 400 友好提示前端可直接展示错误。3.2 业务层services/chart_generator.py的数据聚合逻辑# app/services/chart_generator.py from app.models import Movie, db import pandas as pd def get_top_movies_by_year_range(year_start: int, year_end: int, limit: int 10) - list: 获取指定年份范围内评分最高的电影列表 返回格式[{id: 1, title: XXX, rating: 9.2, year: 2022, genres: [剧情, 爱情]}, ...] # 1. 构建 SQLAlchemy 查询非原始 SQL利用 ORM 关系 query db.session.query( Movie.id, Movie.title, Movie.rating, Movie.year, Movie.duration ).filter( Movie.year.between(year_start, year_end), Movie.rating.isnot(None) # 过滤掉评分为空的脏数据 ).order_by(Movie.rating.desc()).limit(limit) # 2. 执行查询转为 Pandas DataFrame为后续可能的复杂计算留接口 df pd.read_sql(query.statement, db.engine) # 3. 关联查询类型通过 movie_genre 和 genre 表 # 这里用 raw SQL 因为 SQLAlchemy 关联多对多太冗长且此场景性能敏感 sql SELECT m.id, GROUP_CONCAT(g.name SEPARATOR , ) as genres FROM movie m LEFT JOIN movie_genre mg ON m.id mg.movie_id LEFT JOIN genre g ON mg.genre_id g.id WHERE m.id IN :movie_ids GROUP BY m.id genre_df pd.read_sql(sql, db.engine, params{movie_ids: tuple(df[id].tolist())}) # 4. 合并数据按 id join result_df df.merge(genre_df, onid, howleft) result_df[genres] result_df[genres].fillna(未知) # 填充空类型 # 5. 转为字典列表符合 ECharts 前端消费习惯 return result_df.to_dict(records)关键点解析第 1 步用Movie.year.between()替代Movie.year year_start and Movie.year year_endSQLAlchemy 会生成更高效的BETWEEN语句第 2 步pd.read_sql()是点睛之笔。它把 ORM 查询结果转成 DataFrame意味着后续可以无缝接入pandas的rolling()滑动窗口、qcut()分位数分箱等高级分析函数——而不仅是查完就返回。比如你想加个“近五年评分波动率”一行df[rating].std()就搞定第 3 步对多对多关系硬写 SQLAlchemy 关联太啰嗦需定义secondary表、backref此处用原生 SQL GROUP_CONCAT是务实选择MySQL 8.0 下性能极佳第 5 步to_dict(records)输出[{}, {}]格式前端 ECharts 的dataset.source可直接使用无需二次转换。3.3 前端渲染static/js/dashboard.js如何消费 API// static/js/dashboard.js function loadTopMovies() { const url /api/top_movies?year_start${$(#year-start).val()}year_end${$(#year-end).val()}; $.get(url) .done(function(res) { if (res.status ! success) { alert(数据加载失败 res.error); return; } // 1. 渲染表格用原生 DOM 操作不依赖 jQuery DataTables const tbody $(#top-movies-table tbody); tbody.empty(); res.data.forEach(item { const row $( tr td${item.id}/td tda href/movie/${item.id}${item.title}/a/td td${item.rating}/td td${item.year}/td td${item.genres}/td /tr ); tbody.append(row); }); // 2. 渲染直方图ECharts const chartDom document.getElementById(rating-hist); const myChart echarts.init(chartDom); // 动态生成 X 轴评分区间和 Y 轴频次 const ratings res.data.map(d d.rating); const bins [0, 6, 7, 8, 9, 10]; // 分 5 个区间 const histData new Array(bins.length - 1).fill(0); ratings.forEach(r { for (let i 0; i bins.length - 1; i) { if (r bins[i] r bins[i 1]) { histData[i]; break; } } }); const option { tooltip: { trigger: axis }, xAxis: { type: category, data: [6, 6-7, 7-8, 8-9, 9-10] }, yAxis: { type: value }, series: [{ data: histData, type: bar }] }; myChart.setOption(option); }) .fail(function(xhr) { console.error(API 请求失败, xhr); alert(网络错误请检查服务器是否运行); }); }这段 JS 的价值在于零框架依赖没有用 Vue/React甚至没用 jQuery 的$.ajax封装而是用原生$.getjQuery 已引入DOM 操作也极简。这意味着你答辩时即使导师电脑没装 Node.js只要打开index.htmlF12 控制台就能看到完整请求过程。echarts.init()后的setOption()是标准写法所有 ECharts 官方案例都这么写不存在兼容性玄学。4. 爬虫模块详解如何稳定抓取豆瓣电影数据含反爬绕过爬虫是这个项目的地基。如果爬不到数据后面所有分析都是空中楼阁。本项目app/crawler/douban_spider.py不是简单requests.get()而是一套有心跳、有重试、有状态管理的生产级爬虫。4.1 反爬策略应对User-Agent、Referer、Cookies、频率控制豆瓣对未登录用户的请求有严格限制同一 IP 每分钟最多 20 次请求且会校验User-Agent和Referer。本爬虫的应对方案是组合拳# app/crawler/douban_spider.py import time import random from fake_useragent import UserAgent from requests.adapters import HTTPAdapter from urllib3.util.retry import Retry class DoubanSpider: def __init__(self): self.ua UserAgent() # 动态生成 UA避免固定 UA 被封 self.session requests.Session() # 1. 设置重试策略网络抖动时自动重试 retry_strategy Retry( total3, backoff_factor1, status_forcelist[429, 500, 502, 503, 504], ) adapter HTTPAdapter(max_retriesretry_strategy) self.session.mount(http://, adapter) self.session.mount(https://, adapter) # 2. 随机延迟0.5~2.0 秒模拟真人操作 self.delay_range (0.5, 2.0) def _get_headers(self, referer: str None) - dict: 生成合法请求头 headers { User-Agent: self.ua.random, # 每次请求随机 UA Accept: text/html,application/xhtmlxml,application/xml;q0.9,*/*;q0.8, Accept-Language: zh-CN,zh;q0.9,en;q0.8, Accept-Encoding: gzip, deflate, Connection: keep-alive, } if referer: headers[Referer] referer # 必须设置 Referer否则豆瓣返回 403 return headers def fetch_page(self, url: str, referer: str None) - str: 获取页面 HTML time.sleep(random.uniform(*self.delay_range)) # 随机延迟 try: response self.session.get( url, headersself._get_headers(referer), timeout(10, 30) # 连接 10s读取 30s ) response.raise_for_status() return response.text except requests.exceptions.RequestException as e: logger.error(f请求失败 {url}: {e}) raise关键参数说明fake_useragent.UserAgent()从 1000 真实浏览器 UA 池中随机取避免被识别为爬虫Referer豆瓣会校验来源页比如从搜索页跳转到详情页Referer必须是搜索页 URL否则 403time.sleep(random.uniform(0.5, 2.0))不是固定 1 秒而是 0.5~2.0 秒随机更像真人浏览节奏timeout(10, 30)连接超时 10 秒DNS 解析TCP 握手读取超时 30 秒等待响应体避免卡死。4.2 验证码处理本地 OCR 替代打码平台免付费、免网络豆瓣在检测到异常请求时会返回验证码图片。本项目不调用第三方打码 API需付费、有网络依赖而是用pytesseractPIL本地识别# app/crawler/utils.py from PIL import Image import pytesseract import re def solve_captcha(img_bytes: bytes) - str: 本地识别豆瓣验证码 img_bytes: 验证码图片的二进制内容 返回: 4 位字母数字字符串如 A2b9 try: # 1. 加载图片并预处理转灰度、二值化、降噪 img Image.open(io.BytesIO(img_bytes)).convert(L) # 二值化像素 128 设为 255白否则 0黑 img img.point(lambda x: 255 if x 128 else 0, mode1) # 2. OCR 识别tessdata_dir 指向本地训练数据 text pytesseract.image_to_string( img, config--psm 8 -c tessedit_char_whitelist0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ, langeng ) # 3. 清洗只保留 4 位字母数字 cleaned re.sub(r[^a-zA-Z0-9], , text.strip()) return cleaned[:4] if len(cleaned) 4 else None except Exception as e: logger.warning(fOCR 识别失败: {e}) return None注意你需要提前安装tesseract-ocr系统级和pytesseractPython 包并下载eng.traineddata放到tessdata目录。项目scripts/install_tesseract.sh提供了一键安装脚本Linux/macOSWindows 用户可参考注释手动安装。这是本项目能离线运行的关键——不依赖任何外部服务。4.3 断点续爬爬虫崩溃后从上次位置继续爬取 1000 部电影可能耗时 2 小时中途断电或 CtrlC 会导致前功尽弃。本项目用crawl_log表记录任务状态# app/crawler/douban_spider.py def crawl_movies(self, start_page: int 1, end_page: int 100): 断点续爬主函数 # 1. 查询上次中断的任务 last_log CrawlLog.query.filter_by( statusrunning ).order_by(CrawlLog.created_at.desc()).first() if last_log: # 从上次中断页继续避免重复爬 start_page max(start_page, last_log.end_page 1) logger.info(f检测到中断任务从第 {start_page} 页继续) # 2. 记录新任务开始 log CrawlLog(start_pagestart_page, end_pageend_page, statusrunning) db.session.add(log) db.session.commit() try: for page in range(start_page, end_page 1): url fhttps://movie.douban.com/top250?start{(page-1)*25}filter html self.fetch_page(url, refererhttps://movie.douban.com/top250) movies self.parse_movie_list(html) self.save_movies_to_db(movies) # 3. 任务成功更新日志状态 log.status success db.session.commit() logger.info(f爬取完成第 {start_page} 至 {end_page} 页) except Exception as e: # 4. 任务失败记录错误并标记为 failed log.status failed log.error_msg str(e)[:500] db.session.commit() raise这个设计让爬虫具备了“生产环境”属性你随时CtrlC下次运行python -m app.crawler.douban_spider --start 1 --end 100它会自动跳过已成功爬取的页码从第一个失败页开始。5. 避坑指南那些让我凌晨三点还在改的 4 个致命问题这个项目源码质量很高但部署和二次开发时仍有几个经典坑踩过才知道有多痛。以下是我用三台不同配置的机器Mac M1、Ubuntu 22.04、Windows 11实测总结的避坑清单每一条都对应真实报错和解决方案。5.1 现象启动flask run后报错ModuleNotFoundError: No module named app原因Python 的模块导入路径问题。项目根目录下执行flask run时Python 默认把当前目录即douban-movie-analyzer/加入sys.path但run.py中from app import create_app要求app是顶层包。如果当前目录是douban-movie-analyzer/app/就会找不到app。解决确保在项目根目录即包含run.py和app/文件夹的目录下启动cd /path/to/douban-movie-analyzer flask run或者用-m方式启动推荐更明确python -m flask --app run:app run如果用 IDE如 PyCharm在运行配置中将 “Working directory” 设为项目根目录并勾选 “Add content roots to PYTHONPATH”。5.2 现象访问首页显示空白浏览器控制台报错echarts is not defined原因ECharts 的 JS 文件未正确加载。源码中base.html通过script src{{ url_for(static, filenamejs/echarts.min.js) }}/script引入但echarts.min.js文件实际在static/lib/echarts/目录下项目打包时漏放。解决方法一推荐下载官方 ECharts 5.4.3 的echarts.min.js放入static/js/目录方法二修改base.html的 script 标签指向正确路径script src{{ url_for(static, filenamelib/echarts/echarts.min.js) }}/script验证在浏览器打开http://127.0.0.1:5000/static/js/echarts.min.js应能直接下载 JS 文件。5.3 现象爬虫运行时报错OSError: [Errno 24] Too many open files原因requests.Session()在高并发下默认max_workers10会打开大量 TCP 连接超出系统文件描述符限制Linux 默认 1024。解决降低并发数在config.py中修改CRAWLER_CONCURRENCY 3从 10 降到 3或者提高系统限制Linux/macOS# 临时提高当前会话有效 ulimit -n 4096 # 永久提高在 ~/.bashrc 或 /etc/security/limits.conf 中添加 * soft nofile 4096 * hard nofile 4096Windows 用户无需调整其文件句柄限制更高。5.4 现象MySQL 连接报错pymysql.err.OperationalError: (1045, Access denied for user...)原因config.py中的数据库配置未修改。默认配置是SQLALCHEMY_DATABASE_URI mysqlpymysql://root:123456127.0.0.1:3306/douban_movie但你的 MySQL root 密码不是123456或数据库douban_movie不存在。解决步骤 1登录 MySQL 创建数据库CREATE DATABASE douban_movie CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;步骤 2创建专用用户比 root 更安全CREATE USER doubanlocalhost IDENTIFIED BY your_secure_password; GRANT ALL PRIVILEGES ON douban_movie.* TO doubanlocalhost; FLUSH PRIVILEGES;步骤 3修改config.pySQLALCHEMY_DATABASE_URI mysqlpymysql://douban:your_secure_password127.0.0.1:3306/douban_movie步骤 4执行初始化脚本python scripts/init_db.py提示init_db.py会自动执行douban_movie.sql脚本建表并插入 1000 条模拟数据。如果只想建表不插数据注释掉init_db.py中的insert_sample_data()调用。6. 二次开发实战如何快速接入自己的数据源并替换豆瓣 API这才是毕业设计的核心竞争力——不能只跑通别人的数据要能换成你关心的领域。我以“接入 Bilibili 热门视频数据”为例演示从零改造的全流程。整个过程不超过 30 分钟且不破坏原有豆瓣功能。6.1 新增数据源Bilibili 视频爬虫复用现有架构目标把app/crawler/下新增bilibili_spider.py复用DoubanSpider的 Session、重试、延迟等能力只重写解析逻辑。# app/crawler/bilibili_spider.py from app.crawler.douban_spider import DoubanSpider # 复用基础能力 from app.models import BilibiliVideo # 新建模型 import json class BilibiliSpider(DoubanSpider): def __init__(self): super().__init__() self.base_url https://api.bilibili.com/x/web-interface/ranking/v2 def crawl_ranking(self, rid: int 3, day: int 7) - list: 爬取 B 站分区热门榜rid3 是动画区day7 是周榜 返回[{aid: 123, title: xxx, play: 100000, author: UP主}, ...] url f{self.base_url}?rid{rid}day{day} html self.fetch_page(url, refererhttps://www.bilibili.com/) # B 站 API 返回 JSON直接解析 data json.loads(html) videos [] for item in data[data][list]: videos.append({ aid: item[aid], title: item[title], play: item[stat][view], author: item[owner][name], duration: item[duration], pubdate: item[pubdate] # 时间戳 }) return videos def save_videos_to_db(self, videos: list): 保存到数据库 for v in videos: video BilibiliVideo( aidv[aid], titlev[title], playv[play], authorv[author], durationv[duration], pubdatev[pubdate] ) db.session.add(video) db.session.commit()关键点BilibiliSpider继承DoubanSpider直接获得fetch_page()、_get_headers()、重试、延迟等能力只需专注业务逻辑。这比从零写一个爬虫快 5 倍。6.2 新增模型与数据库迁移# app/models.py class BilibiliVideo(db.Model): __tablename__ bilibili_video id db.Column(db.Integer, primary_keyTrue) aid db.Column(db.Integer, uniqueTrue, nullableFalse) # B 站视频 ID title db.Column(db.String(200), nullableFalse) play db.Column(db.Integer, default0) # 播放量 author db.Column(db.String( p a hrefhttps://download.csdn.net/download/caofeng891102/91297907 stylecolor:#ec7500;font-size:14px; 本文还有配套的精品资源点击获取 /a img altmenu-r.4af5f7ec.gif srchttps://csdnimg.cn/release/wenkucmsfe/public/img/menu-r.4af5f7ec.gif stylewidth:16px;margin-left:4px;vertical-align:text-bottom;cursor:text; /p

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑