Python旅游景点大数据采集与可视化系统:从Django到Agent的毕设全解析

发布时间:2026/10/7 11:52:40
Python旅游景点大数据采集与可视化系统:从Django到Agent的毕设全解析
1. 为什么选旅游景点大数据做毕设一个技术亮点够但能落地的方向前阵子有个学弟问我毕设题目到底该怎么选他列了好几个备选方向要么是纯前端页面展示、技术含量太低要么是纯算法模型调参、工作量巨大还容易翻车。我直接跟他说你不如参考我当年做的那套Python旅游景点大数据采集与可视化展示系统用Django做后端框架、selenium做数据采集、再叠加数据分析、机器学习、大模型和agent这几个热门概念一个项目把所有技术栈串成一条完整链路。这个方向看起来技术点密集但每个模块都有成熟方案可以落地不会出现做到一半做不下去的情况。为什么我说旅游景点这个题材特别适合做毕设最核心的原因是数据源公开且丰富。携程、同程、马蜂窝、去哪儿这些平台都有大量景点基础信息、用户评论、评分、门票价格、热度排名数据不需要找什么小众数据源爬虫的合规边界也很清晰——只做公开信息的采集和聚合分析不涉及用户隐私。其次是故事性好旅游本身就是大众话题你做出来的数据大屏、城市热度排行、旅游偏好分析答辩现场任何人都能看懂评审老师不会觉得你做的东西没有实际意义。我当年做完这个项目之后最大的感受是毕设选题的核心不是选一个多难的题目而是选一个能让多个技术点自然串联的题目。旅游景点大数据刚好满足这个条件——从数据采集到数据清洗、从指标分析到可视化展示、再到智能推荐每一步都有明确的技术选型和可展示的产出物。这篇文章我会把整个项目的完整设计思路、核心代码片段、踩过的坑和答辩经验全部拆开讲需要的可以直接照着抄。2. 技术选型与整体架构五个层各司其职别让技术栈变成堆名词2.1 先画清楚项目边界不是所有功能都要做得很深很多同学在做毕设时容易犯一个错误题目里写了大数据就把Hadoop、Spark全堆上写了大模型就一定要本地部署一个什么几十B的模型结果项目搭了个壳子就再也跑不动了。毕设项目的第一原则是在自己的机器上能稳定跑起来技术选型必须匹配单机运行的实际能力。我当时的做法是把这个系统拆成五个层采集层、存储层、分析层、展示层、智能应用层。每个层都有明确的职责层与层之间通过数据库表和JSON接口沟通。整体架构大概是这样采集层selenium requests BeautifulSoup负责从公开旅游平台抓取景点信息、评论、评分等原始数据存储层MySQL存结构化数据、Redis做缓存和消息队列缓冲应对爬虫写入和前端查询之间的性能差分析层pandas做数据处理、jieba做中文分词、sklearn做机器学习模型、PyTorch做简单的深度学习任务展示层Django提供数据接口和Web页面ECharts渲染数据大屏和可视化图表智能应用层大模型API agent工作流提供评论摘要、智能问答、行程推荐三大功能这套架构最妙的地方在于每一层都有独立的技术点可以写进论文但它们之间的依赖关系并不深。就算大模型那部分答辩时没完全演示成功下面的采集和分析部分照样能撑起整个项目的工作量。2.2 核心选型逻辑同一个任务为什么选这个工具而不是另一个技术选型这块我梳理了一张对比表基本覆盖了我做决策时的完整思考过程。技术组件我选择的方案备选方案选择理由数据采集selenium requestsscrapyscrapy性能更好但旅游平台普遍有动态渲染和反爬机制selenium能模拟真实浏览器行为开发成本低单机规模下速度够用Web后端Django 4.xFlask、FastAPIDjango自带ORM、Admin后台和用户认证毕设要同时做数据管理后台和前端页面Django一站式解决少写大量重复代码数据库MySQL 8.0 RedisSQLite、MongoDB结构化查询多MySQL天然适合Redis用于缓存热门接口数据降低数据库压力前端可视化ECharts Django模板Vue 独立后端不强行前后端分离Django模板直出页面配合ECharts的异步请求加载数据开发效率最高机器学习scikit-learnXGBoost、LightGBM数据集规模在万级sklearn的SVM、随机森林、KMeans足够用调参简单、可解释性强深度学习PyTorchTensorFlow做文本情感分析时用微调过的预训练模型PyTorch生态对中文模型更友好大模型与agent大模型API 函数调用本地部署开源模型本地部署对GPU要求高毕设答辩环境不可控调用API更稳妥配合agent设计也能讲清楚大模型这个卖点2.3 为什么坚持用selenium而不全用requests这里单独说一下采集层的选型。旅游平台的反爬手段普遍包括接口签名、字体反爬、动态渲染、请求频率限制。requests直接请求页面源码经常会拿到一堆无关的Script标签真正的景点名称和评分是浏览器执行JavaScript之后才渲染出来的。selenium的优势就是把浏览器自动化当成一个真实用户页面加载之后所有可见内容都会出现在DOM里提取起来干净利落。当然selenium的缺点是慢一个页面从打开到完全渲染可能要两三秒。我的解决方案是第一只对重点页面使用selenium景点详情页、评论列表页对纯静态的列表页用requests批量抓第二开启浏览器的无头模式并且加page_load_strategy eager让网络请求一结束就开始解析不等待所有资源加载完成第三采集线程控制在4到6个实测单机一天能抓几万条景点基础数据对毕设项目来说完全够了。3. 采集层实战selenium爬虫的完整落地过程与常见坑3.1 目标站点分析与景点字段设计开始写爬虫之前我花了两天时间手动浏览目标旅游平台确认了几个关键信息景点列表页的URL规律、详情页的信息结构、评论区的翻页方式是加载更多还是分页。这一步千万不能跳过爬虫代码写得再漂亮页面结构搞错了全是白搭。我当时抓取的主要字段如下表所示这些字段直接决定了后面分析和可视化的维度上限。字段名含义抓取来源示例spot_name景点名称列表页a标签文本故宫博物院city所在城市面包屑导航北京rating_score评分详情页评分模块4.8comment_count评论数详情页统计187234ticket_price门票价格详情页价格模块60元spot_type景点类型标签列表古迹/博物馆latitude / longitude经纬度页面数据属性39.916, 116.397comment_content评论文本评论区内容人少景美出片率高recorded_date采集日期程序自动写入2024-05-20字段设计这块要提前想明白一点分析阶段要用到的每个指标采集阶段必须留出对应字段。比如我后面要做不同城市景点平均评分对比采集时就绝对不能漏掉city字段要做热度预测就必须有comment_count和rating_score。3.2 selenium抓取景点详情页的核心写法下面是我采集景点详情页的核心代码我加了详细注释关键部分直接说清楚为什么这么写。import time import random from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.chrome.options import Options def init_driver(): options Options() # 无头模式不弹出浏览器窗口节省服务器资源 options.add_argument(--headlessnew) # 隐藏selenium标志降低被反爬识别为自动化工具的概率 options.add_argument(--disable-blink-featuresAutomationControlled) options.add_argument(--no-sandbox) # 设置真实的User-Agent这是最基础的伪装 options.add_argument( user-agentMozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 ) options.add_experimental_option(excludeSwitches, [enable-automation]) # 不加载图片大幅提升页面渲染速度 prefs {profile.managed_default_content_settings.images: 2} options.add_experimental_option(prefs, prefs) driver webdriver.Chrome(optionsoptions) return driver def fetch_detail(url, driver): # 访问页面 driver.get(url) # 显式等待最多等8秒直到景点评分元素出现 # 等待逻辑必须用WebDriverWait不要用固定sleep wait WebDriverWait(driver, 8) try: rating_element wait.until( EC.presence_of_element_located((By.CSS_SELECTOR, .scenery-rating)) ) except Exception: return None # 模拟真实用户滚动页面到评论区域触发加载更多逻辑 for i in range(5): driver.execute_script(window.scrollTo(0, document.body.scrollHeight)) time.sleep(random.uniform(0.3, 0.8)) # 提取字段 data {} data[spot_name] driver.find_element(By.CSS_SELECTOR, .scenery-name).text.strip() data[rating_score] rating_element.text.strip() data[comment_count] driver.find_element(By.CSS_SELECTOR, .comment-count).text.strip() # 评论列表处理 comments [] items driver.find_elements(By.CSS_SELECTOR, .comment-item) for item in items[:20]: text item.find_element(By.CSS_SELECTOR, .comment-text).text.strip() comments.append(text) data[comment_content] ||.join(comments) return data3.3 显式等待、滚动加载、异常重试这三个细节决定爬虫能不能跑完写爬虫时最容易翻车的三个点我逐一说明。**第一个是页面等待。**很多教程习惯用time.sleep(random.uniform(1, 3))固定等几秒这样在网速波动时要么白等浪费大量时间要么元素还没渲染出来就报NoSuchElementException。正确做法是WebDriverWait配合expected_conditions等到目标元素出现了才继续往下执行。我上面代码里的wait.until()就是标准写法页面上只要有评分元素就说明核心数据已经渲染完成后续提取基本不会失败。**第二个是滚动加载。**评论列表如果超过10条平台往往采用下拉加载更多而不是分页这意味着你不滚动页面就拿不到完整的评论数据。我的经验是循环滚动到页面底部每滚一次停顿0.5到1秒给浏览器留出渲染时间。滚动结束之后再统一提取元素比滚动过程中边滚边抓效率高得多。**第三个是异常与重试。**爬虫一旦跑起来网络抖动、元素临时改版、验证码弹出都是常态。我写了一个带重试机制的包装函数单次请求失败后休息2秒重试重试3次仍失败就把URL写进错误日志文件最后统一手动补采。这套失败容忍机制比追求单次100%成功率更实际——跑一轮采集能有95%的入库率剩下5%靠日志补齐。3.4 数据入库与去重策略数据抓下来之后不能直接往MySQL灌第一件要做的事情是按业务主键去重。我用的去重策略是以spot_namecity作为唯一键插入之前先查一次数据库如果记录已存在就做更新把评价数、评分这些易变字段刷新不存在才执行插入。import pymysql def upsert_spot_data(data): conn pymysql.connect( host127.0.0.1, userroot, password******, databasetourism_db, charsetutf8mb4 ) cursor conn.cursor() sql INSERT INTO spots (spot_name, city, rating_score, comment_count, ticket_price, spot_type, latitude, longitude, recorded_date) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s) ON DUPLICATE KEY UPDATE rating_score VALUES(rating_score), comment_count VALUES(comment_count), ticket_price VALUES(ticket_price) cursor.execute(sql, ( data[spot_name], data[city], data[rating_score], data[comment_count], data[ticket_price], data[spot_type], data[latitude], data[longitude], data[recorded_date] )) conn.commit() cursor.close() conn.close()注意一个细节charset必须用utf8mb4而不是utf8否则评论里的生僻字和表情符号会直接报Incorrect string value错误。这个坑我当初排查了很久才反应过来现在就当送给你们的见面礼。4. 分析层从脏数据到能写进论文的结论4.1 数据清洗这一步决定机器学习模型的上限数据分析圈有句话叫Garbage in, garbage out放在毕设项目里尤其明显。我采集回来的原始数据存在这么几类问题缺失值部分小众景点没有门票价格字段评论数为空异常值评分出现9.8分这种明显超出平台的评分区间的情况评论数写成8.2万这种带单位的中文文本重复数据同一景点在不同城市下出现两次比如西湖在杭州和惠州都有格式不统一经纬度有的是字符串有的是浮点数门票价格有免费和0元两种表达我处理清洗的步骤是缺失值按业务规则填充——评分缺失用该城市均值填充价格缺失填0代表免费comment_count字段里的中文单位统一换算成数字重复数据保留评分更高、评论数更多的一条经纬度统一转成float类型。所有清洗逻辑我都封装在data_cleaner.py里并在论文中作为一节详细展开这样数据预处理的工作量就完整地落地为代码了。4.2 机器学习与深度学习不止是调包要能讲清楚业务含义为了凑机器学习和深度学习两个关键词而强行建模是没意义的我选了两个场景每个场景都有明确的业务问题在背后。**第一个场景是景点热度预测。**我构造了这样一个问题给定一个景点的历史评分、评论数、门票价格、所在城市维度等特征能否预测它未来的热度等级高/中/低我用sklearn里的RandomForestClassifier和SVC做了对比实验把数据集按7:3划分训练集和测试集用准确率、F1-score评估。最终随机森林的效果稳定在82%左右SVM在75%上下。这个模型的结果在答辩时非常好讲特征重要性排序显示评论数贡献最大这说明景点的曝光度比评分更能带动热度。**第二个场景是评论情感分析。**旅游评论是天然的中文情感分类数据。我做了两个方案对比传统方法是jieba分词 TF-IDF向量化 朴素贝叶斯分类准确率大概在85%深度学习方法用PyTorch加载一个轻量的中文预训练模型比如hfl/rbt3做文本分类微调在3000条人工标注数据上训练了10个epoch准确率能到92%左右。这个对比实验本身就有很好的写作题材——传统方法可解释性强、资源占用低深度学习方法准确率高但对数据量和计算资源要求更高。# 情感分析核心代码简化版 import torch from transformers import AutoTokenizer, AutoModelForSequenceClassification tokenizer AutoTokenizer.from_pretrained(hfl/rbt3) model AutoModelForSequenceClassification.from_pretrained( hfl/rbt3, num_labels2 ) model.load_state_dict(torch.load(checkpoints/comment_sentiment.pt)) def predict_sentiment(text: str) - str: inputs tokenizer(text, return_tensorspt, truncationTrue, max_length128) with torch.no_grad(): logits model(**inputs).logits pred torch.argmax(logits, dim-1).item() return 正面评价 if pred 1 else 负面评价4.3 分析结果如何反过来指导展示很多同学把数据分析和可视化当作两个独立的模块这是不对的。我在做完情感分析和热度预测之后直接在可视化层里增加了两个核心指标情感指数正面评论占比和推荐热度等级。数据大屏上每一张图表都不是平白无故画的背后一定有分析结论支撑。比如我做了城市旅游热门度Top10柱状图这个榜不是简单按评论数排序而是综合了评论数、平均评分、情感指数三个指标加权计算出来的综合得分。再比如我做了一张景点类型偏好分布的饼图聚类算法把游客评论按主题分成历史文化爱好者自然风光爱好者亲子休闲用户美食购物用户四类每类用户偏好什么类型的景点一目了然。这些分析结论让整个项目的逻辑闭环起来了采集数据是为了分析分析的结论用于展示展示的结果反哺推荐系统。5. 展示层Django ECharts搭建数据大屏的经验5.1 Django接口设计视图逻辑与数据聚合分离Django不是直接把数据库表丢给前端而是先通过ORM做聚合计算再以JSON格式输出。这种设计的核心好处是把数据库压力留在后端前端拿到的数据直接就是图表要用的结构。一个典型的热度排行接口长这样from django.http import JsonResponse from django.db.models import Count, Avg def hot_city_api(request): 返回城市旅游热度排行Top10含综合得分 result ( Spot.objects .values(city) .annotate( total_commentsSum(comment_count), avg_ratingAvg(rating_score), avg_sentimentAvg(sentiment_index), countCount(id) ) .order_by(-total_comments)[:10] ) # 计算综合热度评论数归一化 * 0.5 评分归一化 * 0.3 情感指数 * 0.2 max_comments max(item[total_comments] for item in result) data [] for item in result: score ( item[total_comments] / max_comments * 0.5 item[avg_rating] / 5.0 * 0.3 item[avg_sentiment] * 0.2 ) data.append({ city: item[city], score: round(score, 3), comments: item[total_comments], avg_rating: round(item[avg_rating], 2), }) return JsonResponse({code: 0, data: data})这里有一个很关键的Django使用技巧能用ORM聚合查询解决的绝不写循环里做数学运算。刚开始我图省事把所有景点数据一次性查出来然后在Python里循环计算城市级别指标结果数据量到8万条的时候接口直接超时。后来改成Django ORM的annotate聚合SQL帮我把计算量分担掉接口响应从12秒降到300毫秒体验完全是两个级别。5.2 ECharts大屏的图表选型与布局数据大屏我参考了很多开源大屏项目的布局最终确定为上下四块区域顶部项目标题 采集统计数字景点总数、评论总数、覆盖城市数滚动的实时采集速度展示左侧全国景点分布地图scatter地图、热门城市Top10柱状图中间情感分析仪表盘正面/负面占比环形图、热点词云右侧景点类型偏好饼图、评论数量趋势折线图、排序表格ECharts的初始化代码很简单核心是把上一节接口返回的数据通过fetch拿到塞进setOption里。举例来说地图部分是这样做的// 加载景区分布地图数据 fetch(/api/spot_map/) .then(response response.json()) .then(res { const spots res.data.map(item ({ name: item.city, value: [item.longitude, item.latitude, item.spot_count] })); myChart.setOption({ series: [{ type: scatter, coordinateSystem: geo, data: spots, symbolSize: val Math.max(5, Math.sqrt(val[2]) * 0.8), itemStyle: { color: #ff6600 } }] }); });ECharts的散点图自带coordinateSystem: geo配置配合中国地图GeoJSON就能直接把经纬度渲染成地图上的圆点这是做景观点位分布最省事的方案。symbolSize做成函数形式根据景点数量动态调整圆点大小视觉上能立刻看出热度差异。5.3 大数据量下前端渲染卡顿聚合、分片、懒加载三板斧这里我专门说说性能问题尤其是搜索引擎里高频出现qt 表格大数据卡顿优化这类关键词说明大表格卡顿是很多同学的痛点。网页端同样存在这个问题——如果你把采集到的几万条评论一次性塞进HTML表格浏览器直接卡死。我的处理方案有三层。第一层是后端聚合前端图表需要的是城市级、类型级这种汇总数据那么后端按维度聚合后再返回避免明细数据前传。第二层是数据分片表格类组件用Django的分页接口一页只返回50条明细记录用户点下一页才发起新请求。第三层是图表降采样时间序列折线图如果每天一条数据有几千个点ECharts的sampling: lttb参数会自动保形降采样视觉上几乎看不出差异。提示做可视化性能优化时不要一上来就想着换框架。先看数据量到底卡在哪一层——50%是后端查得慢30%是传输数据太大20%才是DOM渲染问题。先优化后端聚合和接口分页大部分卡顿都能解决。6. 大模型与Agent给毕设加上智能化亮点6.1 大模型在旅游数据场景的三条落地路径现在毕设题目里不带大模型都觉得没噱头但大模型不能只作为口号挂在论文里必须能演示出实际功能。我在这个项目里规划了三个大模型应用场景每个都有真实的落地方式。**第一个是旅游评论智能摘要。**采集的评论数量多、文本质量参差用户根本不可能逐条看完。我调用大模型API把某个景点的30条评论灌进去让模型生成3条要点式摘要并标注出游客最关注的正面点和负面点。比如故宫的摘要结果是游客普遍认可历史文化价值和建筑美感主要吐槽暑期排队时间过长、门票预约困难——这种总结人工整理要花十几分钟大模型几秒钟就能完成演示效果极佳。第二个是旅游知识问答机器人。这个功能相当于给系统加了一个对话入口用户问北京适合带孩子去的博物馆有哪些机器人先通过意图识别确定查询条件再在数据库中检索匹配的景点最后结合大模型组织自然语言回答。这里有两个关键点一是检索必须走真实数据库不能纯靠大模型编造二是回答要附带数据来源景点评分、评论数增强可信度。**第三个是基于Agent的智能行程推荐。**这是整个系统最有未来感的部分也是答辩时最容易引发讨论的地方。我设计的Agent工作流大概是用户给出口语化的需求北京三天两晚想多去几个历史古迹最好不要太累Agent自主规划执行步骤——先调用工具查询数据库按条件筛选景点再按地理位置规划路线最后调用大模型生成解释性的行程单。每一步Agent都会记录自己的决策理由我把它做成一个可观测的日志面板直接在演示环节展示Agent的思考过程。6.2 一个基于Agent的行程推荐工具是怎么设计的Agent的工程实现没有想象中那么神秘我用的核心思路是大模型API的函数调用机制。举一个简化版的例子import json import requests def search_spots(city: str, spot_type: str None, max_price: int None): 查询景点库返回匹配景点列表 url http://127.0.0.1:8000/api/spots/ params {city: city, spot_type: spot_type, price_lte: max_price} resp requests.get(url, paramsparams) return resp.json() def plan_trip(spots: list, days: int) - str: 根据景点分布规划行程 # 简化实现按热度排序后平均分配到每一天 spots.sort(keylambda x: x[comment_count], reverseTrue) per_day max(1, len(spots) // days) plan for i in range(days): day_spots spots[i * per_day: (i 1) * per_day] plan f第{i1}天: - .join(s[name] for s in day_spots) \\n return plan # 大模型需要识别用户意图并且把意图转成上面的函数调用参数 tools [ { type: function, function: { name: search_spots, description: 查询符合条件的旅游景点, parameters: { type: object, properties: { city: {type: string, description: 城市名}, spot_type: {type: string, description: 景点类型}, max_price: {type: integer, description: 最高门票价格} }, required: [city] } } }, { type: function, function: { name: plan_trip, description: 根据景点列表生成多日行程安排, parameters: { type: object, properties: { days: {type: integer, description: 旅游天数}, spots: {type: array, items: {type: object}} }, required: [days, spots] } } } ]关键逻辑是先把用户的问题发给大模型模型判断需要调用哪个函数、传什么参数返回一个标准的函数调用JSON我们的代码执行这个函数再把执行结果回传给模型模型基于真实数据生成最终回答。这个过程严格遵循数据真实性优先Agent是调用真实数据库的不是凭空编造的。6.3 大模型部分的成本控制与复现建议用大模型API做毕设有一个现实问题调用次数多了要花钱。我的经验是做缓存策略——同一个问题第一次调用后把回答存进Redis第二次直接查缓存答辩演示时完全不用怕网络波动和调用限额。另外再精选20个高频问题进行预先批处理把结果存成JSON文件万一现场调用失败也能直接展示预生成的答案保证答辩流程不中断。注意如果你担心大模型API在答辩现场不稳定可以准备两条路径。主路径是实时调用API展示Agent的完整思考和调用过程备用路径是预生成答案回放把精选问题的Agent日志和结果做成演示页面。这样不管网络状况如何演示都不会翻车。7. 踩坑记录与答辩经验把源码变成能讲清楚的项目7.1 做这类项目最容易翻车的几个点我把自己和周围同学做毕设的真实翻车经历汇总了一下你们可以对照自查。**环境依赖冲突。**这是头号杀手。Django、selenium、pandas、torch、transformers这一大堆库装在一起Python版本稍微不对就各种编译错误。我当时把依赖全部锁进requirements.txt里并且坚持用Python 3.10的虚拟环境先建一套基准环境再在上面一层层装库。建议你们一上来就固定版本号不要装最新版——最新版库之间兼容性反而不稳定。**数据量不够就讲不了大数据。**有些同学爬了100条景点数据就急着做大数据可视化结果柱状图里只有2根柱子答辩时特别尴尬。我的建议是至少采集5000景点基础数据和20000评论数据这个量级在单机selenium跑一天左右就能达到。数据量足够的前提下才能合理使用大规模数据处理分布式采集思路这类表述。**机器学习模型效果太差。**如果模型准确率只有60%不要硬吹而是准备对比策略展示数据清洗前和清洗后的准确率差异证明预处理的价值或者展示不同模型的性能对比把模型调优过程本身作为工作中的亮点。我最终的随机森林模型准确率82%这个数字不算高但我把特征重要性分析做得很充分评委反而觉得研究过程扎实。**论文和代码对不上号。**这是最影响答辩印象分的问题。论文里写采用多线程并发采集代码里却没看到线程论文里写实现了情感分析模型代码库里却找不到对应脚本。我最后的做法是把每个模块的代码按论文章节组织成目录每一节论文对应一个可运行的脚本或文件评委从论文翻到代码直接就能对上体验极度舒适。7.2 答辩时老师最常问的问题与准备思路我总结了答辩时大概率会被追问的五类问题提前准备答案比临场发挥靠谱得多。第一类技术选型问题——为什么用selenium而不是scrapy我的回答抓住了动态渲染这个关键点旅游平台大量内容依赖JavaScript渲染scrapy必须再搭配Splash或Playwright才能处理动态加载selenium一步到位。这里你要展示的不是哪个工具更好而是我基于什么场景做了什么决策。第二类数据质量与合规问题——你的数据可靠吗抓取是否合规回答思路数据来源是景点平台公开信息采集频率控制在合理范围只抓公开数据不涉及个人隐私数据更新记录在案符合学术研究的合理使用原则。要用公开信息、正常频率、研究用途这三个关键词框定边界。第三类系统瓶颈问题——你这个系统如果数据量增长100倍哪里会先崩这是陷阱题考的是你是否清楚系统架构的薄弱环节。我的回答是分两层单机采集速度会成为瓶颈解决方案是换用消息队列加分布式采集MySQL单表数据过大会影响查询性能解决方案是分表或引入ClickHouse做分析型存储。不需要真正改动代码能说清楚扩展路径就够了。第四类模型效果问题——深度学习比传统方法好在哪值不值得这个代价我拿出测试集数据朴素贝叶斯85%微调模型92%误差降低了约46%但训练时间和资源消耗增加了10倍以上。然后补一句因此在生产环境决策时需要根据场景权衡精度和成本——这句话一出口评委就知道你真的理解模型的应用价值而不只是会跑代码。第五类创新点问题——你这个项目和你参考的教程相比你自己的创新点在哪里这个问题我提前做了深度反思。我的回答集中在三个方面一是把大模型Agent和传统数据分析系统打通让智能推荐严格基于真实数据执行而不是模型自己编造二是多模块协调工作每个模块都有真实用户价值三是设计了完整的数据质量监控机制这是很多课程项目完全不涉及的工程化细节。7.3 毕设时间规划建议前紧后松留出两个月余量最后聊一下时间规划。我认识的绝大多数同学都死于拖延到最后一个月才开始写代码。按照正常节奏毕设整个周期建议预留四到五个月大概这么分配需求分析与技术验证3周爬取100条数据验证selenium能搞定目标站点跑通Django基础页面确认大模型API可以调用核心功能开发6周采集模块完成80%的数据采集和入库分析模块完成清洗脚本模型跑出第一版结果展示层完成大屏主体系统整合与深度优化4周三个模块联调补齐异常处理做性能优化、数据补采论文撰写3周论文的每个章节都对应实际代码和实验结果杜绝写的时候发现没做预答辩与修改2周请同学扮演答辩评委模拟提问重点练技术选型和架构问题这个节奏也许看起来慢但每一步都有明确的产出物不会出现学到一半发现此路不通的绝望感。我特别提醒一点技术验证阶段千万不能贪多先跑通最核心的30%功能后面的70%都是在这条路上慢慢铺开的。做毕设的本质其实是一次完整的工程实践训练而不是纯粹的知识考试。旅游景点大数据这个题目之所以适合大多数计算机方向的同学就是因为它让你在同一个项目里经历了数据采集、清洗、分析、建模、展示、智能应用这一整条数据流水线——做完之后你写在简历上的不是熟悉Python和Django而是独立完成了一个从数据采集到智能分析应用的全链路系统这两者的分量完全不一样。项目源码和完整代码整理完之后找个时间我会把关键模块再逐个拆开讲解你们先把环境和数据跑起来再说。