
1. 先说清楚2026年为啥还要自己写脚本抓大众点评评论大众点评上那些密密麻麻的评论对做餐饮、开店、搞本地生活运营的人来说是最直接的用户声音。星级评分可能是综合计算出来的但一条条具体吐槽是造不出来的。我自己去年帮朋友做一个餐饮品牌的口碑监测每周要看几十家店的评论变化手动翻页面眼睛都快翻瞎了记到表格里还经常串行。最后老老实实写了个Python脚本把评论批量抓下来做汇总分析加上2026年1月这波大众点评改版整套流程又重新折腾了一遍。这篇就是从那次实操里整理出来的完整记录包括页面数据入口的变化、反爬应对思路、核心代码框架和几个交了学费的坑。这篇文章适合谁看想做本地生活竞品分析的运营人员想给自家门店做自动化口碑监控的老板或者纯粹想练手Python爬虫的开发者都能在这篇里找到能直接用的东西。前提是你有最基本的Python基础——会装依赖、懂一点点requests和json就够遇到具体概念我会尽量拆开讲明白。1.1 评论数据的价值到底在哪开店的人都知道大众点评评分是及格线评论内容才是试卷。一家店评分4.8但评论里全是上菜太慢服务冷漠跟另一家评分4.5但评论里全是老板很实在菜品惊喜口碑质地完全不同前者可能正在走下坡路后者则是值得关注的潜力股。做竞品分析的时候逐个门店人工翻页的效率太低——一家店平均几百条评论10家店就是几千次页面操作耗时一整天不说还容易漏数据漏楼层。脚本化之后把这些变成一键批量处理半小时能把原本一天的活儿干完而且结果还能标准化进表格。1.2 现成数据服务和自建脚本怎么选市面上确实有第三方数据服务省心是真省心但痛点也很明显数据字段是固定打包的不能只挑你要的评论内容、评分、时间这几个维度价格不便宜包年订阅动辄几千上万时效性难以保证有些平台的数据滞后好几天甚至几周拿来分析还行拿来监控就误事了。自己写脚本的投入主要是一次性的开发时间成本换来的是按需定制、实时采集、存储格式完全可控。代价是得持续维护——大众点评一改版代码就要跟着改这是一个会长期存在的养代码过程后文我会专门讲这部分真实体验。用表格直观对比一下对比维度现成数据服务自建Python脚本成本按年订阅费用高一次性开发持续维护字段灵活性固定字段不可定制完全按需提取时效性可能存在数日滞后随跑随取实时性高学习门槛几乎为零需要基础Python能力长期依赖依赖服务商稳定运营依赖自己维护代码2. 动手前必须想清楚的合规边界与账号准备开始写代码之前先泼一盆冷水大众点评官方目前没有开放公开的评论查询接口任何个人脚本采集行为都处于平台规则的灰色地带。所以动手前必须给自己划清楚底线。我的习惯是几条只采集公开展示、不需要登录穿透就能看到的评论内容绝不碰用户的敏感信息评论人昵称之外的账号维度数据一律不取控制请求频率不给目标服务器造成超出正常用户浏览的压力抓下来的数据仅供个人学习研究或获授权的商业分析使用不做转售不公开传播原始数据库。这不是走过场。最近几年个人信息和数据合规方面的要求越来越明确相关案例也不少把自己摘在安全线以内是长期能玩下去的前提。评论区有人问我能不能教我绕过登录抓全部评论我的回答一直是不能也没必要公开页面能看到的评论数量对绝大多数分析场景已经足够了。2.1 合理采集边界怎么判断我给自己定的判断标准很简单用浏览器直接打开能看到的内容才采集需要登录、需要破解验证码、需要逆向加密参数才能拿到的数据一律不碰。这个标准的好处是双重的——技术上省去了大量逆向的精力法律和平台规则风险也降到最低。其实想清楚这件事之后脚本反而好写了因为定位到的都是真实浏览器也会正常加载的数据。2.2 环境准备与依赖安装我的运行环境是Python 3.103.9及以上都没问题操作系统不限Windows、Linux、macOS都验证过。依赖清单如下pip install requests beautifulsoup4 lxml pandas openpyxlrequests发HTTP请求、维持会话状态beautifulsoup4lxml解析HTML页面结构pandasopenpyxl把采集结果整理成Excel或CSV另外强烈建议准备一个浏览器。这不是用来炫技的而是做人工对照。我在脚本抓不到数据时第一件事永远是打开浏览器手动访问一下目标页面看看现在页面真实长什么样。这个简单的习惯帮我省掉了大量瞎猜时间后面会反复提到。3. 2026年1月这版大众点评的评论数据入口在哪大众点评的页面改版频率不低2026年1月这版跟去年比又有一些结构调整。但有一个规律始终没有变页面里展示的评论数据要么直接嵌在首屏HTML里要么通过异步XHR接口加载。整个采集过程的第一道工序就是把这个数据入口精确定位出来。3.1 用开发者工具定位真实请求以PC网页版为例。打开一家门店的评论页按F12进入开发者工具切到Network面板刷新页面然后在筛选栏输入XHR就能看到页面加载过程中的所有异步请求。逐个点开看响应内容找到返回体里包含评论文本的那个请求它的URL里通常带有review或comment之类的关键字。也有一部分门店的评论是直接渲染在首屏HTML里的这种情况不需要找接口用BeautifulSoup直接解析即可。这一步操作的时候我建议顺手记录四个关键信息请求URL、请求方法GET还是POST、核心请求头User-Agent、Referer、是否带有加密参数。这套抓包-定位-复现的思路是跨平台通用的不管网站改成什么样只要它还要在浏览器里展示数据这条路就永远走得通。我后来抓过好几个其他本地生活平台的评论都是同一套方法论。3.2 Cookie和请求头决定你是真人还是机器人大众点评的反爬筛选相当严格裸请求所有请求头都不带、直接用requests.get大概率返回的是一张安全验证页而不是正常页面。实测跑下来下面这几样缺一不可Cookie首次访问时站点会种下几个基础标识尤其是_lxsdk_cuid这类访客标识。不带这些后端基本直接判定为异常流量。User-Agent必须模拟一个正常浏览器UA不能用Python默认的python-requests。Referer标明从哪个页面跳转过来的缺失会让服务端觉得请求路径可疑。把这些整理成一份请求头模板用requests.Session统一管理。如果某家店需要登录才能查看完整评论就在浏览器里手动登录一次然后把登录后的Cookie导出给脚本使用。注意Cookie会过期过期的特征通常是评论区域数据为空或直接跳登录页遇到这种情况重新导出一次即可。4. 核心代码实现从发送请求到评论落盘下面这套代码是我实际跑过的最简可用框架突出一个够用且不臃肿。整体分三步建会话、翻页拉数据、解析入库。代码的定位是教学级别的参考框架真正落到你自己项目里时页面选择器和参数部分大概率需要微调——这是正常的不是脚本写错了。4.1 会话与请求头的构建import requests from bs4 import BeautifulSoup import time import random import pandas as pd HEADERS { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36, Referer: https://www.dianping.com/, Accept: text/html,application/xhtmlxml,application/xml;q0.9,*/*;q0.8, Accept-Language: zh-CN,zh;q0.9,en;q0.8, } COOKIES { # 把浏览器里登录后的Cookie按 keyvalue 拆开放进来 # 例如: _lxsdk_cuid: xxx, dper: xxx, ua: xxx } session requests.Session() session.headers.update(HEADERS) session.cookies.update(COOKIES)这里有个实操细节别把Cookie当成固定值写死后就不管了。我习惯把Cookie拆成字典放配置文件里用的时候单独加载过期后只改配置文件不动主逻辑。另外千万别把含登录态的Cookie提交到公开仓库泄露账号风险很大。4.2 发送请求并判断返回是否正常def fetch_page(shop_id, page1): url fhttps://www.dianping.com/shop/{shop_id}/review_all?queryTypeallpage{page} resp session.get(url, timeout10) if resp.status_code ! 200: print(f请求失败: HTTP {resp.status_code}) return None # 判断是否命中安全验证页 if 验证 in resp.text and 安全 in resp.text: print(触发安全验证停止采集等待人工处理) return None return resp.text代码里我用了一段关键词检测来判断是否命中安全验证页——如果HTML里出现了验证安全这类字样说明风控介入。这时候继续请求没有意义反而会加重账号风险最稳妥的做法是停下来等一段时间再去浏览器里手动过掉验证。4.3 用BeautifulSoup解析评论文本def parse_reviews(html): soup BeautifulSoup(html, lxml) reviews [] # 注意选择器需要按实际页面结构调整下面只是常见结构示例 for item in soup.select(div.review-list li): try: nickname item.select_one(a.name).text.strip() content item.select_one(div.review-words).text.strip() rate_class item.select_one(div.star-line span).get(class, [])[0] time_text item.select_one(span.time).text.strip() if item.select_one(span.time) else reviews.append({ nickname: nickname, content: content, rate: rate_class, time: time_text, }) except AttributeError: continue return reviews页面结构选择器是我调试最频繁的地方大众点评每隔一段时间就会调整CSS类名。我的调试方法是先在浏览器里右键检查某个评论块对照实际DOM改选择器改完先跑一页验证再放量。这比凭记忆里的旧结构硬猜效率高得多。4.4 翻页、去重与数据落盘def crawl_shop(shop_id, max_pages5): all_reviews [] seen set() for page in range(1, max_pages 1): html fetch_page(shop_id, page) if html is None: break page_reviews parse_reviews(html) if not page_reviews: print(f第{page}页无数据停止翻页) break for r in page_reviews: if r[content] in seen: continue seen.add(r[content]) all_reviews.append(r) time.sleep(random.uniform(2, 5)) return all_reviews if __name__ __main__: shop_id 填入实际门店ID data crawl_shop(shop_id, max_pages20) df pd.DataFrame(data) df.to_excel(reviews.xlsx, indexFalse) print(f共采集 {len(df)} 条评论已保存至 reviews.xlsx)这里有两个我反复踩过的点值得单独拎出来说。第一翻页终止条件。有些门店评论不足一页有些则有几百页。我在代码里同时设置了页面返回为空和最多翻20页两个约束实测下来很稳。如果某一页解析出来的评论数和上一页完全一样排除广告和推荐位多半已经翻到重复内容了再往下翻没意义。第二随机延时不是摆设。短时间高频请求不仅容易被风控还可能让IP进黑名单。我在每次翻页之间加了random.uniform(2, 5)秒随机睡眠虽然总耗时变长了一些但稳定性和可持续性大幅提升。宁可慢一点不要一波流把路走死。5. 反爬与风控我最常遇到的三种情况和应对思路跑了一段时间之后我把大众点评的反爬机制粗略分成三个层级。每一层的触发表现和相应对策都不一样下面逐个说。5.1 第一层请求频率限制最常见的表现是请求能正常发出去但返回页面里评论区域为空或者直接跳到登录页。这在连续快速翻页十几页之后非常典型。我的对策就是前面说的随机延时加总页数上限跑完一批之后休息更久。如果需要采集大量门店我会把任务拆成多天分批执行而不是一天内集中打完。频率控制本质上是在采集效率和账号/IP安全之间取一个平衡点我个人宁愿效率低30%也不想账号挂了重新养。5.2 第二层验证码和安全验证页这一层比较直观——页面直接变成一块安全验证页通常需要点击或拖动完成验证。硬闯基本没有胜算我通常的做法是脚本里检测到验证页后立即停止当前任务保留已采集的数据然后人工在浏览器里正常访问同一页面手动通过验证。等验证状态恢复之后再让脚本从断点继续。这里不建议去研究自动化过验证码的方案技术成本高且容易把账号搭进去对于个人采集项目来说完全不划算。下面这张表是我自己整理的应对对照不同触发表现会有不同的处理路径反爬层级典型表现我的应对策略频率限制评论区域为空、跳登录页随机延时、页数上限、分批采集验证码页面变为安全验证页立即停止、人工过验证、断点续跑参数签名接口返回异常或空数据不逆向改用浏览器自动化方案5.3 第三层参数签名与加密接口这一层我在实际采集里没有强行逆向过。主要原因是大众点评的部分接口使用了带签名的参数签名逻辑由前端JavaScript动态生成纯requests复现成本高而且每次版本迭代都可能变化。真到了这一步我建议换个思路用Playwright这类浏览器自动化工具让真实浏览器去渲染页面脚本直接读取渲染后的DOM。虽然速度和效率会打折扣但稳定性好很多而且完全不需要碰逆向加密的灰色逻辑。下面是一个Playwright的参考用法框架from playwright.sync_api import sync_playwright with sync_playwright() as p: browser p.chromium.launch(headlessTrue) page browser.new_page() page.goto(https://www.dianping.com/shop/填入门店ID/review_all) page.wait_for_timeout(3000) items page.query_selector_all(div.review-list li) for item in items[:5]: print(item.inner_text()[:100]) browser.close()Playwright的优势是它本身就是一个完整Chromium浏览器JavaScript渲染、动态加载、部分验证逻辑都由浏览器自己处理了。缺点也很明显——占用资源大跑大批量任务时机器负载高而且速度远慢于纯HTTP请求。作为个人项目的补充方案我认为它恰到好处。6. 拿到评论之后清洗、存储和简单的口碑分析采集只是上半场。评论数据拿到手以后清洗和分析才是真正产生价值的部分。很多新手容易忽略这一步结果辛苦抓下来的数据又脏又乱根本没法用。6.1 文本清洗的基本操作爬下来的内容里多多少少会有噪声HTML标签残留、多余空白、表情符号、用户、无意义的打卡文案等。我通常做三步处理去掉HTML残留和多余空白过滤掉字数过少比如少于10个字的灌水评论把相似度极高的重复评论合并——有些用户会在不同店铺下发相同内容这种多半是铺量广告留着会污染分析结果。import re def clean_text(text): text re.sub(r[^], , text) text re.sub(r\s, , text).strip() return text清洗规则不必搞得太复杂抓到主要噪声源就够了。我在实际项目里还加了一条按评论长度过滤的规则太短的评论信息量低分析时直接剔除。6.2 不需要训练模型的简易情感倾向分析如果不想引入大模型或机器学习库可以先用手工情感词典的方式做粗粒度判断把评论分成正面、负面、中性三类。这个方法简单直接胜在零依赖、完全可控pos_words [好吃, 推荐, 满意, 服务好, 环境棒, 值得] neg_words [难吃, 失望, 慢, 差, 不推荐, 态度差] def simple_sentiment(text): pos_cnt sum(1 for w in pos_words if w in text) neg_cnt sum(1 for w in neg_words if w in text) if pos_cnt neg_cnt: return positive elif neg_cnt pos_cnt: return negative return neutral这当然是演示级别的精度词表需要按你所在行业加词才实用。餐饮赛道就加份量小油腻等位久美容美发赛道就加剪坏了预约难推销办卡。真要做扎实的负面口碑分析我会对负面评论做高频短语统计“上菜慢”“分量少”“价格贵”这类负面表述按门店维度聚合就能直观看到每家店被集中吐槽的点在哪。这个结果对商家调整运营策略特别有价值。6.3 数据存储的格式选择我的默认存储方案是CSV或Excel简单够用pandas一行代码就能写进去。但如果你打算做长期监控我建议改用SQLite按月或按门店分表方便增量更新和去重查询。字段上至少包含门店ID、评论内容、评分、评论时间、评论人昵称、采集时间。采集时间是我后期补上的字段特别有用——它标明数据是什么时候抓的避免时间久了之后搞不清楚数据时效性。7. 几个真实踩坑记录希望你别再踩一遍这部分的坑我全是真金白银换来的。写出来是想让你知道爬虫脚本最大的风险往往不在代码本身而在对目标站点行为变化的适应能力上。7.1 坑一太依赖一套固定的选择器第一次写脚本时我把评论块的CSS选择器写死后就没再管结果脚本用了两周突然一条评论都抓不到。打开页面一看类名换了DOM结构也调整了。从那以后我养成一个习惯每次大规模采集前先用一条测试数据跑通选择器再放量跑。宁可多花五分钟验证也不要白跑一小时拿回一堆空数据。这个习惯救了我很多次。7.2 坑二Cookie过期导致数据中断有一次采集到一半脚本报错排查了半小时才发现是登录Cookie过期了。大众点评的Cookie有效期不算长活跃会话还可能被顶掉。我的方案是把Cookie管理和采集流程分开写一个独立函数专门读取和校验Cookie过期时给出明确提示而不是让脚本带着失效Cookie继续请求。失效Cookie请求返回的页面往往也是空数据或异常内容而且容易误导排查方向。7.3 坑三忽略评论的分页懒加载机制大众点评的评论列表在PC端是有明确分页的但移动端页面是滚动加载的。如果你混用两种入口会发现数据量对不上。解决办法是固定只用一种入口并在代码里做总量校验采集完成后把实际条数和页面显示的评论总数对比一下差距太大就要检查是否漏掉了懒加载部分。我自己的习惯是PC端为主移动端只做补充验证。7.4 我的最终建议用Python写大众点评评论采集本质上是一个完整的方法论实践理解目标网站定位数据入口模拟正常访问解析结构化数据再落到存储和分析。代码框架本身不难难的是对页面改版的快速跟进和对风控机制的敬畏。我的个人体会是把请求频率放低一点把数据边界守牢一点把代码结构写得容易维护一点这套脚本就能长期稳定地为你服务。采集本身不是终点能把评论转成可执行的经营判断那才是数据真正产生价值的时刻。后面我打算给这套脚本加上定时调度和简单的看板展示让口碑监控变成全自动的日常动作如果你也在做类似的事欢迎在评论区聊聊你的方案。