☰
大众点评爬虫数据规约详解:Sniper 项目搜索与评论字段的完整对齐方案
2026/10/5 13:02:02 网站建设 项目流程
  • 网页爬虫

【免费下载链接】dianping_spider

大众点评爬虫(全站可爬,解决动态字体加密,非OCR)。持续更新

项目地址:https://gitcode.com/gh_mirrors/di/dianping_spider
点击查看免费下载

大众点评反爬机制复杂,同一店铺信息可能来自网页解析、加密接口、cookie 池与 ip 代理等多种爬取通道,不同通道能见到的字段并不一致。本文基于 dianping_spider 仓库的 docs/data.md 文档,完整梳理该项目在搜索(search)与评论(review)两条链路上的数据规约(字段对齐)规则,并结合 function/search.py、function/review.py 等源码验证每个字段的真实解析来源,帮助你理解抓取结果的字段含义、值域形态以及"哪些字段只有接口才有、哪些只有网页才有",为后续数据清洗与入库提供可直接对照的参考。

为什么需要"数据规约":多爬取方式下的字段对齐问题

大众点评对搜索页、详情页和评论页都施加了严格的动态字体加密与反爬限制(本项目通过 utils/get_font_map.py 获取字体映射并替换加密字符串,非 OCR 方式破解)。为了对抗封禁,项目同时支持:

  • 网页 HTML 解析(携带 cookie 的登录态请求);
  • 加密匿名接口(通过uuid、tcv参数访问,未登录态,字段存在隐藏,详见 docs/json.md);
  • cookie 池与 ip 代理等防 ban 手段。

由于采用了多种爬取方式,有些数据对于其它爬取方式并不可见,因此项目在输出层采用"最大集"原则做数据规约:凡是任何一种爬取方式能拿到的字段,都统一放进最终字典中;拿不到的字段以-占位。同时,因为数据对齐的原因,有一些字段名字可能会轻微变化,使用方在对接下游任务时应以本规约为准。

字段标记体系:-、*、#的含义

数据规约文档中每个字段后都带有一个标记符号,这是理解整套数据的关键:

标记含义说明
-所有爬取方式均可见网页解析与加密接口都返回该字段
*接口特有只有加密接口(匿名接口)能拿到
#网页特有只有网页解析能拿到

该标记直接对应 docs/json.md 中"加密接口 + 网页解析融合"的设计:接口在未登录状态下会隐藏部分字段(如商家电话末两位),而网页在登录态下字段更全,但反过来接口能拿到一些网页拿不到的数据(如浏览量)。两者取并集,就构成了下面的最大集规约。

search:搜索页数据规约

搜索页爬取结果的整体结构与字段含义如下(数据结构定义于 function/search.py 的one_step_search_res字典):

{ '店铺id': -, # 所有方式都有 '店铺名': -, # 所有方式都有 '评论总数': -, # 所有方式都有 '人均价格': -, # 所有方式都有 '标签1': -, # 所有方式都有 '标签2': -, # 所有方式都有 '店铺地址': -, # 所有方式都有 '详情链接': -, # 所有方式都有 '图片链接': -, # 所有方式都有 '店铺均分': -, # 所有方式都有 '推荐菜': *, # 接口特有 '店铺总分': -, # 所有方式都有 '店铺电话': -, # 所有方式都有 '其他信息': #, # 网页特有 '优惠券信息': *, # 接口特有 }

search 各字段的源码解析依据

在 function/search.py 中,搜索列表通过BeautifulSoup解析.shop-list下的每一个li,每个字段都有独立的 try/except 兜底逻辑——解析失败统一回退为-,这正是规约中占位符的来源:

  • 店铺id:取.txt > .tit > a的data-shopid属性;
  • 店铺名:取.txt > .tit > a的文本并strip();
  • 评论总数:取.comment > .review-num文本,去掉换行;
  • 人均价格:取.comment > .mean-price > b文本,解析失败时默认¥0;
  • 标签1/标签2:取.tag-addr > .tag列表的前两项,文本中的换行替换为空格;
  • 店铺地址:取.tag-addr > .addr文本;
  • 详情链接:取.txt > .tit > a的href;
  • 图片链接:取.pic > a > img的src;
  • 店铺均分:取.comment-list的文本(页面上的详细评分,如"口味 环境 服务"分项);
  • 推荐菜:取.recommend文本,即页面上的"推荐菜"区域;
  • 店铺总分:两种解析方式——优先解析.star_icon > span的class(如star_icon star_48取48除以 10 得 4.8),失败则解析.star_score的文本。

从源码结构看,推荐菜(*)在网页解析失败时会被置为-,而接口通道可以稳定返回;优惠券信息(*)同理仅出现在接口数据中。其他信息(#)则来自详情页网页解析(见下文 detail 部分),在纯接口通道下不可见。

搜索结果的典型展示

下面两张图展示了搜索页规约字段在真实页面上的形态(店铺列表项与店铺详情信息):

review:评论页数据规约

评论页爬取结果采用"摘要 + 精选评论列表"的两层结构,整体规约如下(数据结构定义于 function/review.py 的return_data与each_review字典):

{ '店铺id': -, # 所有方式都有 '评论摘要': -, # 所有方式都有 '评论总数': -, # 所有方式都有 '好评个数': -, # 所有方式都有 '中评个数': -, # 所有方式都有 '差评个数': -, # 所有方式都有 '带图评论个数': -, # 所有方式都有 '精选评论': [ { '店铺id': -, # 所有方式都有 '评论id': -, # 所有方式都有 '用户id': -, # 所有方式都有 '用户名': -, # 所有方式都有 '用户打分': -, # 所有方式都有 # 注意:接口为单评分,网页为多评分 '评论内容': -, # 所有方式都有 '点赞个数': *, # 接口特有 '回复个数': *, # 接口特有 '浏览次数': *, # 接口特有 '人均价格': -, # 所有方式都有 '喜欢的菜': -, # 所有方式都有 '发布时间': -, # 所有方式都有 '商家回复': -, # 所有方式都有 '评论图片': -, # 所有方式都有 } ], }

review 各字段的源码解析依据

在 function/review.py 中,评论页请求会携带uuid/tcv走加密接口,同时以网页解析结果兜底,字段同样全部带 try/except 回退-的容错:

摘要层(第一页一次性解析):

  • 评论摘要:解析.content > span,得到类似{'描述': '口味', '个数': '8.7'}的列表;
  • 好评个数/中评个数/差评个数:分别取.filter-good、.filter-middle、.filter-bad下的.count文本(去掉首尾括号);
  • 带图评论个数:取.filter-pic > .count;
  • 评论总数:由好评 + 中评 + 差评个数相加计算得出(计算失败回退-)。

精选评论层(逐条解析.main-review):

  • 评论id:取.actions > a的data-id;
  • 用户id:取.name链接href的末尾路径段;
  • 用户名:取.name文本;
  • 用户打分:解析.score文本,网页端可得到"口味:X 环境:X 服务:X"的多维评分字典(review_score_detail),而接口端只有单一评分——这是规约中注明"接口为单评分,网页为多评分"的原因;同时会解析.sml-rank-stars的 class 得到用户总分;
  • 评论内容:取.review-words文本,并清理"收起评价"、换行等杂质;
  • 人均价格:从.score文本中匹配"人均:X元"并剥离"元"字;
  • 喜欢的菜:取.review-recommend文本,去掉前 5 个字符后按空格拆分(如"招牌寿喜锅 极上M8霜降黑毛和牛 无菌蛋");
  • 发布时间:取.time文本;
  • 商家回复:取.shop-reply-content文本,无回复时为'';
  • 评论图片:收集.review-pictures > a的href,并拼接为http://www.dianping.com + 路径的完整链接列表。

点赞个数、回复个数、浏览次数(均为*)在网页端.main-review解析中没有对应选择器,从源码结构看它们主要来自加密接口的返回数据,因此规约中标记为接口特有;如需这三个字段,应确保走接口通道(配置uuid与tcv)。

评论数据的典型展示

下面这张图展示了单条精选评论在网页上的完整形态,与each_review字典中的字段一一对应(用户名、打分、人均价格、评论内容、喜欢的菜、发布时间、评论图片、商家回复等):

三种数据形态与存储:规约如何落地

数据规约最终通过 utils/saver/mongo_saver.py 写入 MongoDB,三类数据对应三个集合:

数据形态触发链路MongoDB 集合写入前处理
search搜索页爬取(controller.main()完整流程第一步)info按店铺id先删后插,保证覆盖更新
detail详情页爬取(可选链路)info_detail按店铺id先删后插
review评论页爬取(可选链路)review按店铺id先删后插

写入逻辑均为col.delete_many({'店铺id': ...})后col.insert(data),即同一店铺的每次爬取结果会整体覆盖,因此规约中的-占位符会在覆盖更新中体现为"本次通道不可见的字段被清空为-"——如果你后续用关系型数据库或 CSV 落地,需要按 docs/save.md 中的说明自行拆分表结构(该仓库目前仅维护 MongoDB 写入)。

使用规约时的注意点

  1. 字段名可能轻微变化:由于数据对齐,个别字段名在不同版本或不同通道下可能微调,请以 docs/data.md 当前版本为准,下游解析不要硬编码假定字段永远不变。
  2. -是合法值而非脏数据:规约中所有字段在"该通道拿不到"时都会置为-,清洗时应将其与真实缺失、真实为 0(如'0'、'¥0')区分开。
  3. *字段依赖接口通道:推荐菜、优惠券信息、点赞个数、回复个数、浏览次数只有配置了加密接口(uuid、tcv,获取方法见 docs/json.md)才会返回,未配置时这些字段在输出中会是-。
  4. #字段依赖网页通道:其他信息等网页特有字段只有走网页解析(登录态携带 cookie)才可见,接口通道下不可见。
  5. 评论详情是"谨慎选择"项:需要登录态才能获取更多评论(超过默认 10 条精选),频繁请求会造成封号(过段时间自动解开),相关开关在 require.ini 的shop_review段(need/more_detail/need_pages)以及 spider_config.py 中有对应加载逻辑。

总结

数据规约是 Sniper 项目"网页解析 + 加密接口"双通道融合设计的输出层契约:以-/*/#三个标记明确每个字段的可见性边界,以最大集原则保证下游无论走哪条链路都能拿到统一结构的字典。配合 function/search.py 与 function/review.py 的容错解析(失败统一回退-)以及 utils/saver/mongo_saver.py 的按店铺覆盖写入,你可以在拿到数据的第一时间就明确"这个字段从哪来、值是什么形态、能不能信",从而把精力集中在业务分析而非字段排查上。

  • 网页爬虫

【免费下载链接】dianping_spider

大众点评爬虫(全站可爬,解决动态字体加密,非OCR)。持续更新

项目地址:https://gitcode.com/gh_mirrors/di/dianping_spider
点击查看免费下载
上一篇:终极FastAPI部署自动化指南:GitHub Actions与CI/CD全流程实战
下一篇:【技术专题】LangChain4j实战指南:Java智能应用开发全解析

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询