ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

民宿评论数据分析:从爬虫采集到情感分析的完整实践

民宿评论数据分析:从爬虫采集到情感分析的完整实践 简介一款基于Python开发的民宿用户生成内容UGC挖掘与分析软件面向旅游大数据分析人员、爬虫与NLP学习者专注解决美团、携程平台民宿评论的采集与深度分析难题。项目实现自动化评论采集、深度清洗、智能主题提取和细粒度情感分析并附带图形界面便于实时查看分析结果。资源共29个文件以Python脚本为核心包含携程与真果爬虫、GUI主程序、数据分析绘图脚本辅以png/jpeg可视化图表、xml工程配置、txt说明文档及README整体压缩包约1.86MB。目前已有79人学习浏览适合希望了解真实平台数据采集、评论文本挖掘或情感分析完整流程的开发者参考。通过该项目可掌握爬虫异常处理、评论数据清洗、主题建模及情感极性判别等实用技能并可直接运行GUI观察民宿评论多维度分析效果。1. 民宿评论分析卡在评分和文本对不上美团和携程的民宿评论区有个常见的怪现象用户打 4 分评论里却在骂房东态度差用户打 2 分写的内容却全是夸房间干净。评分和文本描述经常对不上导致只看分数根本没法判断一家民宿的真实口碑。这个项目就是围绕这个问题做的——它把美团和携程的民宿评论抓下来做深度清洗再用主题提取和细粒度情感分析把“用户到底在夸什么、骂什么”拆开。它解决的并不是爬虫本身而是爬下来之后怎么让文本变成可靠的分析结果。适合谁用做民宿运营的人需要知道差评集中在哪个房间、哪个环节做竞品分析的人需要批量看同城对手的评论结构做毕业设计或数据比赛的人需要一套完整的采集加分析流程参考。这套资源从 requests 采集到 pandas 清洗再到 LDA 主题提取和情感分析都有对应的 Python 代码拿来改一改就能接到自己的数据源上。2. 采集层设计美团和携程的反爬策略完全不同2.1 评论列表的抓取链路这个项目的采集模块并不是一个通用的爬虫而是针对美团和携程两家平台分别写的采集器。原因很简单——两个平台的页面渲染方式和反爬策略完全不一样。携程的民宿评论数据直接嵌在 HTML 里结构相对规整用 requests 加 BeautifulSoup 就能解析美团则大量走接口返回 JSON很多关键字段是异步加载出来的直接抓 HTML 什么都拿不到。我一般会先抓列表页再根据列表页里的评论链接去抓详情页但这个项目的做法更直接——抓评论列表本身就是抓目标不需要进入详情页。采集器构造了一个带基础 Cookie 的 session然后按城市和关键词去翻页拉评论列表。翻页方式上美团走的是 offset 分页参数携程则是 page 参数两者都需要在请求头里带上来源 referer否则服务器直接拒绝。import requests from bs4 import BeautifulSoup session requests.Session() session.headers.update({ User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36, Accept-Language: zh-CN,zh;q0.9, }) def fetch_meituan_comments(city_id, keyword, offset0): url https://www.meituan.com/api/comments params {cityId: city_id, keyword: keyword, offset: offset} resp session.get(url, paramsparams) data resp.json() return data.get(comments, []) def fetch_ctrip_comments(city_id, keyword, page1): url https://hotels.ctrip.com/comments params {cityId: city_id, keyword: keyword, page: page} resp session.get(url, paramsparams) soup BeautifulSoup(resp.text, html.parser) items soup.select(.commentItem) return [item.get_text(stripTrue) for item in items]这里有几个参数需要根据实际情况调整。city_id在城市列表页里能直接查到美团和携程的编码规则不同建议先手动打开网页确认offset美团接口一般以 0 起步每次加 10page携程从 1 开始每次加 1。评论字段里最有价值的是用户名、评分、评论时间、评论内容、房型、回复内容这几列清洗后基本能覆盖后续所有分析。2.2 增量采集与入库容错上一版我直接跑全量采集结果跑了两天发现数据库里一半是重复的。这个项目在入库前做了两层去重第一层用 MD5 对评论内容的指纹做唯一索引第二层用「用户 ID 评论时间」做逻辑判断因为同一个用户在同一时间对同一家民宿只能发一条评论。平台对采集频率非常敏感我习惯在每次请求之间加 2 到 3 秒的随机延时美团和携程都要加只是延时区间略有不同美团 2 到 4 秒携程 1.5 到 3 秒。import time import random from hashlib import md5 def dedup_and_save(comment, collection): fingerprint md5(comment[content].encode(utf-8)).hexdigest() if collection.find_one({fingerprint: fingerprint}): return False comment[fingerprint] fingerprint collection.insert_one(comment) return True # 抓完一页后进入入库流程 for c in page_comments: ok dedup_and_save(c, db.reviews) if ok: time.sleep(random.uniform(2, 4))爬虫的健壮性很大程度体现在异常处理上。网络请求超时、返回非 JSON、IP 被临时限流这三类异常必须分别处理。超时重试三次还失败就跳过非 JSON 说明返回的是验证页这时候要立刻停下来检查 Cookie 是否过期。限流通常会伴随 HTTP 429 状态码遇到后停 60 秒再继续。3. 深度清洗民宿评论比酒店评论脏得多3.1 文本噪声的常见来源民宿评论和酒店评论最大的区别是民宿用户写评语更随意什么玩意儿都往里面塞。表情符号、房间照片里的文字、房东回复里嵌套的客套话、各种平台的推广口令全都会混进评论文本里。如果不做清洗后面做主题提取和情感分析时这些噪声会直接污染词频统计结果。常见的噪声类型大致有这几类第一种是表情符号和特殊字符比如“房间很干净房东超好”这个大拇指必须去掉第二种是 URL 和微信号之类的内容很多民宿房东会在评论回复里留联系方式第三种是复制粘贴的户型描述很多用户直接复制平台上的房间介绍作为评论第四种是繁体字和异体字携程平台上有不少港澳台用户写的评论。这些在分词之前必须处理干净。import re import pandas as pd def clean_comment(text): # 去掉表情符号 text re.sub(r[\U0001F300-\U0001FAFF], , text) # 去掉URL text re.sub(rhttp[s]?://\S, , text) # 去掉微信号和手机号 text re.sub(r[vV][xX][:]\s*[a-zA-Z0-9_-], , text) text re.sub(r1[3-9]\d{9}, , text) # 全角转半角 text text.replace(, ,).replace(。, .).replace(, !).replace(, ?) # 繁体转简体需要引入zhconv from zhconv import convert text convert(text, zh-cn) return text.strip() df[cleaned] df[comment].apply(clean_comment)zhconv库负责繁体转简体转换前要先做全角转半角不然转换结果会混入异常字符。表情符号的正则范围用了\U0001F300-\U0001FAFF这个区间覆盖了绝大部分 Emoji但有些特殊符号比如 ™ 和 © 不在范围内需要另外写规则。3.2 重复评论去重与空值处理民宿评论有个很头疼的现象——同一家民宿的多个账号发的评论内容几乎一模一样这种是刷单产生的不做去重会直接扭曲情感分布。普通的 MD5 去重只对完全相同的文本有效稍微改几个字的重复评论就绕过了。所以我一般会用 SimHash 加海明距离的思路相似度超过阈值就视为重复。from simhash import Simhash def is_dup(new_text, existing_hashes, threshold3): new_hash Simhash(new_text) for h in existing_hashes: if new_hash.distance(h) threshold: return True return False清洗完之后的字段还要检查完整度评分缺失的评论直接丢内容为空的丢只有标点符号的丢。空评论和纯表情评论在民宿场景里很常见很多人习惯只打分不写字这种评论对文本分析没有任何贡献。处理完后会明显看到数据量缩水而且文本质量高了一大截。4. 主题提取与情感分析短文本里挖出真实口碑4.1 基于词典的主题匹配民宿评论文本的特殊性在于句子短、口语化严重、主题高度集中。直接上 LDA 往往效果很差因为一行十几个词的文本没有足够的共现信息支撑主题模型。这个项目采用的方式是构建民宿领域词典做关键词匹配把评论归类到「房间」「位置」「卫生」「服务」「餐食」「性价比」这几个主题下。词典的质量直接决定主题匹配的效果。项目里已经内置了一版约 120 个词的民宿词典覆盖了房间设施、周边交通、房东服务等维度。实际使用时需要根据本地数据增补比如“落地窗”“投影仪”“榻榻米”这类词在特定城市的民宿评论里出现频率很高。匹配用最简单的方式——遍历词典只要评论里出现该主题下的词就把这条评论计入该主题。topic_dict { 房间: [干净, 床品, 空调, 热水, 隔音, 窗户, 投影, 榻榻米], 位置: [地铁, 商圈, 步行, 交通, 方便, 找不到, 导航], 服务: [房东, 热情, 回复, 入住, 退房, 接送, 沟通], 餐食: [早餐, 厨房, 餐具, 冰箱, 做饭, 味道], 卫生: [蟑螂, 灰尘, 异味, 发霉, 整洁, 床单], } def assign_topic(text): matched [] for topic, words in topic_dict.items(): for w in words: if w in text: matched.append(topic) break return matched or [未分类]这里有一个需要注意的地方同一主题下的词要避免互斥比如“干净”既可以归房间也可以归卫生误分类会带来统计偏差。我一般会把这类词只保留在主导主题下或者允许一条评论归属多个主题统计时做多重计数。这是两种不同的统计口径看场景选项目里默认是多重计数。4.2 细粒度情感的本地化修正情感分析用的是 SnowNLP 作为基础模型但拿到民宿场景里直接用效果并不好。通用模型会在两个地方翻车一是“房东人很好”这种包含明确正面评价的句子被判成中性二是“绝绝子”“YYDS”这种网络表达完全不在模型语料里。项目在基础模型之上做了一层规则修正把民宿场景里的高频情感词做成正负向词典对模型结果做二次覆盖。from snownlp import SnowNLP positive_words [很棒, 满意, 推荐, 贴心, 舒适, 惊喜, 赞] negative_words [垃圾, 失望, 脏, 差, 坑, 后悔, 投诉, 气愤] def sentiment_correct(text, base_score): pos_count sum(1 for w in positive_words if w in text) neg_count sum(1 for w in negative_words if w in text) if pos_count neg_count and base_score 0.5: return base_score 0.3 if neg_count pos_count and base_score 0.5: return base_score - 0.3 return base_score def analyze_sentiment(text): score SnowNLP(text).sentiments return sentiment_correct(text, score)情感得分的阈值设定需要根据数据分布调整。默认以 0.5 为中立分界但民宿评论整体偏正向很多表达一般的评论得分也在 0.6 以上。实际操作中我会先把所有评论的得分跑一遍看直方图找到明显的分界谷值再设定正负向阈值而不是硬套一个 0.5。5. 避坑记录民宿评论分析最容易翻车的五个地方5.1 携程评论时间戳经常出现缺失值现象采集到的携程评论里有一部分评论的发布时间是空字符串。原因携程出于业务考虑部分老评论不展示具体日期只显示“入住后评价”之类的文案。解决不能直接丢弃这些评论它们是有效内容。我一般会把时间字段标记为“未知”在按时间维度做趋势分析时单独排除但在主题和情感统计时仍然计入。5.2 美团评论接口返回的评分值是乘以 2 的现象美团评论接口返回的评分字段最大值是 10而不是 5。原因美团内部存储评分时用的是十分制前端展示时做了除以 2 的处理但接口层没有处理。解决在清洗阶段统一除以 2转成五分制。否则后续不管做均值统计还是分箱分析数值都会整体偏高一倍。5.3 民宿名称和实际位置经常对不上现象美团上很多民宿的名称是“XX度假别墅”“XX花园小院”但实际坐标和名称描述的位置相差几公里。原因民宿主在平台注册时填写的地址比较随意加上平台对民宿位置的审核没有酒店严格。解决分析位置相关主题时不能依赖名称必须用评论里提到的地标词来判断实际区位比如“离地铁站 500 米”“步行到西湖”。5.4 情感分析对小样本分类极度不稳定现象同一条评论跑两遍情感分析结果判定的强度不一样。原因SnowNLP 内部用了贝叶斯分类训练语料对民宿领域覆盖不足导致边界样本的判定方差很大。解决对情感得分在 0.4 到 0.6 之间的评论强制归入中立区间不做正负判定。这样虽然损失了一部分细粒度但整体稳定性大幅提升。5.5 主题词典不覆盖网络新词现象大量评论被分到“未分类”原因是里面出现了“打卡”“出片”“氛围感”这类新词。原因静态词典对网络流行语的覆盖有滞后性。解决每个月用 TF-IDF 跑一次高频词增量提取人工审核后将新的高频词补充进词典。这个操作五分钟就能做完但往往能救回 10% 以上的未分类样本。6. 结果验证与可视化让分析结果能被信任民宿评论分析如果只停留在“跑出几个饼图”的阶段很难被信服。我习惯在交付结果前做一次完整的数据质量验证。最基础的一条是采样人工标注对比从全量数据里随机抽 200 条评论人工标注正负向再和模型判定结果做对比准确率到 85% 以上才算合格。主题分布做交叉验证时要特别注意把同一批评论按月份拆分分别跑主题分布如果两个月的分布差异超过 15%大概率是采集样本出了偏差而不是市场发生了变化。情感分析同理要按城市、按房型、按价格段三个维度分别统计才能发现真正有价值的结论。可视化层是这个项目比较出彩的地方——它内置了一套简单的交互式报表页面用 Flask 提供数据接口前端用 ECharts 渲染。采集和分析完成后可以直接在浏览器里按城市、月份、主题筛选评论数据看到不同主题的情感得分变化趋势。python app.py --port 8080 --data ./data/reviews_clean.csv启动后访问http://localhost:8080/dashboard就能看到完整的分析面板。这个面板对于民宿运营者来说非常实用能直观看出某个区域的民宿的主要差评集中在“卫生”还是“隔音”从而针对性改善。从那以后我每次跑民宿数据都强制先做一轮采样人工标注再决定要不要信模型的结果。这个习惯帮我避掉不少“模型说用户很满意、实际被投诉到平台”的尴尬情况。希望这份资源能帮你在民宿评论分析这条路上少走几个来回。本文还有配套的精品资源点击获取
返回列表