- 网页爬虫
【免费下载链接】dianping_spider
大众点评爬虫(全站可爬,解决动态字体加密,非OCR)。持续更新
本文以开源仓库 dianping_spider 中 js/README.md 描述的浏览器端油猴(Tampermonkey)脚本为核心,讲解如何在不写一行 Python 代码的情况下,直接在浏览器中采集大众点评某店铺"全部评论"页的完整评论内容,并深入剖析脚本解决动态字体加密(非 OCR)的实现原理。读完本文,你将掌握该油猴脚本的安装、使用、浏览器兼容性边界,以及 CSS + SVG 字体映射还原加密字符的完整技术链路,并能与仓库内 Python 版爬虫的加密处理逻辑相互印证。
一、脚本定位:Python 爬虫之外的"零成本"采集方案
dianping_spider 主项目是 Python 全站爬虫(搜索页、详情页、评论页),其 README.md 明确将"浏览器油猴插件"列为已支持的功能之一。而js/目录下的这套浏览器端脚本,核心目标只有一个:在店铺的"全部评论"页面,把当前页面渲染出的全部评论内容一次性提取出来。
与 Python 爬虫需要配置 cookie 池、IP 代理、uuid/tcv 等 30 多个参数不同,油猴脚本直接寄生在真实浏览器环境里,天然拥有合法渲染上下文、真实 cookie 与页面 DOM,因此上手成本极低——装上脚本、打开页面、点一下按钮即可。
适用页面为大众点评的"全部评论"页,例如:
http://www.dianping.com/shop/H3CxO06M73m8Kmvc/review_all二、安装与运行环境
2.1 安装方式
脚本通过 Tampermonkey(油猴)插件运行,可直接在线安装。仓库 js/README.md 提供了官方脚本地址;脚本头部元数据(js/spider.user.js 第 1~11 行)同样声明了匹配规则与依赖:
// ==UserScript== // @name 大众点评评论 // @namespace http://tampermonkey.net/ // @version 0.10 // @description 获取大众点评网页评论,解决动态字体加密 // @match http://www.dianping.com/shop* // @match https://www.dianping.com/shop* // @grant GM.xmlHttpRequest // ==/UserScript==关键声明解读:
@match限定了脚本仅在www.dianping.com/shop*页面生效,因此需要先在浏览器中打开店铺相关页面,脚本才会注入;@grant GM.xmlHttpRequest授权脚本跨域请求字体资源(CSS、SVG 文件均托管在s3plus.meituan.net的 CDN 上),这是破解字体加密的基础能力。
2.2 浏览器兼容性(重要)
文档明确给出了实测结论:
- FireFox 搭配 Tampermonkey 插件可完美使用;
- Chrome 浏览器下点击"更多评论"会刷新页面,原因未知。
也就是说,如果你的主力浏览器是 Chrome,建议改用 Firefox 运行该脚本,否则展开评论时页面可能被刷新导致采集中断。这一限制属于脚本作者实测反馈,使用前需自行评估。
三、使用流程:两个悬浮按钮
脚本注入后会在页面右下角生成两个悬浮按钮(js/spider.user.js 第 149~179 行):
| 按钮 | 行为 |
|---|---|
| 开始采集 | 自动点击页面中所有.fold("展开")按钮以展开长评论,隐藏.unfold("收起")按钮,然后调用核心提取逻辑getResult(),将结果以固定面板形式展示在页面左下角 |
| 下一页 | 模拟点击.NextPage翻页按钮,用于继续采集下一页评论 |
核心流程对应源码:
btn.onclick = async () => { const moreBtns = $(moreBtnClass); // '.fold' moreBtns.forEach(b => { b.click(); // 展开被折叠的评论 b.style.opacity = 0; // 隐藏展开按钮 }); const lessBtns = $(lessBtnClass); // '.unfold' lessBtns.forEach(l => l.style.opacity = 0); const res = await getResult(); // 提取当前页全部评论 showResult(res); // 渲染结果面板 }采集结果通过showResult()渲染为一个固定定位(position: fixed)、宽高 600px、带滚动条的浮层,每条评论以独立<div>展示,方便直接复制。
四、核心难点:动态字体加密的非 OCR 破解
大众点评评论内容并非普通文本,而是通过动态字体渲染:HTML 中的文字实际是加密字体编码,肉眼看到的内容由浏览器通过字体文件绘制而成,直接抓取 DOM 文本得到的是乱码。该脚本的核心价值就在于不依赖 OCR,而是用「CSS 定位 + SVG 字形表」还原出真实字符。
整套逻辑集中在getResult()(js/spider.user.js 第 23~133 行),分四个阶段:
4.1 阶段一:收集 CSS 与 SVG 资源 URL
先序列化当前 DOM,正则提取页面内引用的所有样式表地址(均以//s3plus.meituan.net/v1/...形式出现),补全为https:协议:
const getCssUrl = () => { const bar = documentTxt.matchAll(/href=\"(\/\/s3plus\.meituan\.net\/v1\/.*?)\"/g); ... return baz.map(b => 'https:' + b[1]); }再对每份 CSS 内容匹配 SVG 雪碧图的地址,并记录其前缀 class([class^="..."]):
const getSvgUrl = (content) => { const bar = content.matchAll(/\[class\^=\"(.*?)\"\].*?url\((\/\/s3plus.meituan.net\/v1\/.*?)\)/g); ... }4.2 阶段二:解析 CSS 中的字符坐标表
每个加密字符对应一个形如.className { background:-Xpx -Ypx; }的 CSS 规则,其中的(X, Y)是该字符在字体雪碧图中的坐标。脚本通过GM.xmlHttpRequest跨域拉取 CSS 文本,用正则抽取所有坐标映射,并过滤掉带[的规则(那些是 SVG 雪碧图的声明而非字符):
const matchs = cssContent.matchAll(/.(.*?)\{background:-(.*?)px -(.*?)px;}/mg); ... if (!name[0].includes('[')) { cssNameMap[name[1]] = [+Number(name[2]).toFixed(0), +Number(name[3]).toFixed(0)] }4.3 阶段三:解析 SVG 字形表并建立字体偏移
SVG 字体文件内包含y坐标与字符的对应关系(<text x="..." y="...">字符</text>),脚本据此建立「行坐标 → 行号」映射。更关键的是字体存在特征色偏移:SVG 内若包含#333则高度偏移量为 23,包含#666则高度偏移量为 15(宽度偏移量均为 0):
if (svgContent.includes('#333')) { fontHeightOffset = 23; fontWeightOffset = 0; } if (svgContent.includes('#666')) { fontHeightOffset = 15; fontWeightOffset = 0; }4.4 阶段四:坐标反查还原字符
对每个 CSS 类名,取其坐标(locX, locY),叠加字体偏移后换算到 SVG 的"格子"位置,反查出真实字符:
const locXLine = Math.floor((locX + fontWeightOffset) / 14); // 每字宽度 14px const locYLine = fontLoc[locY + fontHeightOffset]; // y 坐标 + 高度偏移 → 行号 let val = ''; if (fontLocMap[locYLine - 1]) val = fontLocMap[locYLine - 1][2][locXLine]; cssNameMap[key].push(val);最终cssNameMap从「class 名 → 坐标」升级为「class 名 → 坐标 + 真实字符」。提取评论时,脚本遍历.review-words节点下的每个子节点:带 class 的节点查表还原字符,普通文本节点直接取textContent,拼接后即得到完整可读的评论(js/spider.user.js 第 115~130 行)。
五、与 Python 端实现相互印证
这套浏览器端破解逻辑并非孤例,仓库 Python 端在评论爬取中采用了完全同源的算法,两者可互为对照:
- utils/get_font_map.py 的
get_review_map_file()同样先解析页面中的s3plus.meituan.netCSS,再抽取.xxx{background:-Xpx -Ypx;}坐标规则并过滤含[的项; - 同样的特征色偏移判定:
#333→ 高度偏移 23,#666→ 高度偏移 15(utils/get_font_map.py 第 390~398 行); - 同样的坐标换算公式:
loc_x_line, loc_y_line = (loc_x + font_weight_offset) // 14, ...(utils/get_font_map.py 第 428 行); - Python 端还将解析结果落盘为
./tmp/*.json缓存并做二次复用(文件存在则跳过解析),且若 SVG 中既无#333也无#666,会提示"评论页字体变更"并退出——这说明字体特征标记一旦变化,两端代码都需要同步适配(见 docs/problems.md 第 8 条)。
而在爬虫侧,function/review.py 的get_review()会依次调用get_review_map_file()获取映射文件、requests_util.replace_review_html()将页面源码中的加密字符替换为真实文本(utils/requests_utils.py 第 386~400 行),再交给 BeautifulSoup 解析出用户名、评分、评论内容、图片等结构化字段。也就是说:油猴脚本是这套字体还原算法在浏览器端的实时版,Python 爬虫则是同算法的离线批处理版。
六、注意事项与使用边界
- 作用范围:脚本只处理"全部评论"页(
/review_all),且每次采集的是当前页面已渲染的评论,需要多页数据时请配合"下一页"按钮逐页操作; - 展开折叠评论:"开始采集"会自动展开
.fold长评论并隐藏收起按钮,避免截断; - 浏览器差异:Chrome 下点击"更多评论"可能触发页面刷新,建议使用 Firefox;
- 合规声明:本项目遵循 GPL-3.0 协议且仅限学习交流使用(见 README.md),采集时请注意遵守目标网站的服务条款与相关法律法规;
- 时效性:字体特征(
#333/#666)与 CSS 结构若被大众点评更新,脚本可能失效,届时需要同步调整偏移量与正则,这与 docs/problems.md 中记录的 Python 端故障排查逻辑一致。
七、小结
js/ 目录下的油猴脚本以极低的接入成本,实现了大众点评全部评论页的完整评论采集,其核心价值在于:用 CSS 背景坐标 + SVG 字形表反查的方式,在浏览器端实时破解动态字体加密,全程无需 OCR。配合"展开评论 + 翻页"两个按钮,即可完成整页乃至多页评论的浏览式采集。理解 js/spider.user.js 中"拉 CSS → 抽坐标 → 拉 SVG → 建行映射 → 反查字符"这条链路,也能帮助你更好地理解仓库 Python 端 utils/get_font_map.py 的字体解析实现,从而在网站字体规则更新时快速定位需要调整的代码位置。
- 网页爬虫
【免费下载链接】dianping_spider
大众点评爬虫(全站可爬,解决动态字体加密,非OCR)。持续更新
相关推荐
ScriptHookV深度解析:构建GTA V自定义模组的核心技术框架
ScriptHookV深度解析:构建GTA V自定义模组的核心技术框架 ScriptHookV作为《侠盗猎车手V》(GTA V)的开源脚本钩子框架,为开发者提供
CSDNGreener 用户脚本:彻底净化CSDN浏览体验
CSDNGreener 是一款专为 Tampermonkey 插件设计的 CSDN 绿化脚本,拥有超过 160 个版本迭代的稳定表现。这款脚本能够完全过滤 CS
前端OpenCLI 大众点评(dianping)浏览器适配器实战:基于登录态 Chrome 的店铺搜索与详情采集
OpenCLI 大众点评(dianping)浏览器适配器实战:基于登录态 Chrome 的店铺搜索与详情采集 本篇指南围绕 OpenCLI 项目中的大众点评(d
开发工具CLI人工智能AI 应用浏览器控制GUI 自动化
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考