ARTICLE DETAIL

资讯详情

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

大众点评评论爬虫实战:破解字体反爬与Cookie校验

大众点评评论爬虫实战:破解字体反爬与Cookie校验 开头如果你在搜索引擎里翻过“Python爬虫大众点评”相关的帖子大概率会看到两种极端要么是跑通了一次就发出来的新手水文要么是拿结论唬人但关键代码一律打码的营销贴。真实情况其实一直夹在中间——大众点评的反爬体系在中文互联网里属于第一梯队它不像电商平台那样用简单的UA检测就放你过去而是组合了行为分析、字体反爬、动态参数校验好几层机制。这篇文章我准备把你带进“我是怎么真正把评论数据抓下来”的现场不吹5分钟跑通但会把5分钟能跑通的那部分条件讲明白把真正卡住你的点全部拆开。这个项目适合两类人参考一类是刚学完Python基础、requests库会用但还没碰过真实反爬场景的爬虫初学者另一类是产品、运营、市场方向的技术同学需要通过评论数据做竞品分析、门店口碑监控又不想依赖第三方采集平台。我会从大众点评的反爬机制讲起再进入抓取方案的设计思路最后给出可以直接改改就用的完整代码附上我在实际操作里踩过的坑。需要先说明一件事大众点评的用户协议里明确禁止未经授权的抓取行为所以本文所有代码仅供技术学习与个人研究使用采集时请严格控制频率和规模不要对目标网站造成压力也不要将数据用于任何商业用途。技术本身没有立场但用技术的人需要守住边界。1. 内容整体设计与思路拆解1.1 先搞懂大众点评的“反爬底牌”才知道代码该怎么写很多人第一次抓大众点评习惯性地拿requests.get(url)直接怼上去然后发现返回的HTML里店铺名是“??????”、评论内容是空白或者干脆给你一整个验证码页面。这不是代码写错了是你根本没碰到数据本身就被挡在了门外。大众点评目前比较成熟的反爬策略可以拆成三层第一层是请求校验。它会在Cookie里种下一堆参数常见的有_lxsdk_cuid、_lxsdk_s、dper这些其中部分参数带有时间戳和签名逻辑。你如果只带一个裸的User-Agent去访问商户评论页服务端能通过Cookie缺失直接判断你是爬虫。更麻烦的是即使你带上了Cookie请求频率一高就会触发风控返回一个特殊页面响应头里会出现x-forbid-reason字段这就是被限流的直接信号。第二层是字体反爬。你看到的店铺星级、评分、评论数这些数字在HTML源码里不是普通字符而是一个映射到自定义字体文件的编码。浏览器加载了大众点评的专属字体文件后会把编码渲染成正确的数字但requests拿到的源码就是一堆乱码。这也是“抓下来了但数据是花的”最常见原因。第三层是内容动态加载。PC端评论列表支持翻页但翻页请求并不是传统的url?page2那种链接拼接而是带上_token、shopId等参数发出的异步请求。你要么走浏览器模拟Selenium/Playwright让网站自己发请求要么逆向它的异步接口参数生成规则。所以反爬的应对思路就清晰了要么用Playwright这类工具直接驱动真实浏览器内核让网站把所有校验都跑完你只负责读渲染后的数据要么用requests手动模拟请求但需要补Cookie、处理字体映射、破解翻页参数。两条路线各有优劣我后面会讲清楚什么时候选哪条。1.2 为什么很多人推荐你用“异步接口字体解析”而不是Selenium坦白讲用Selenium/Playwright抓大众点评是最省脑子的方案代码短、逻辑直观、不容易触发验证码。但它有两个硬伤一是慢一个页面加载完再翻页平均要5到10秒二是费资源开几个浏览器实例内存就上去了没法做大规模采集。而走接口方案只要搞定了Cookie和字体反爬单次请求耗时基本在1秒以内而且可以稳定并发。尤其当你只需要抓某几家店的评论而不是全站扫描时接口方案才是“5分钟能跑通”的真正含义——剩下的时间都花在调参和补细节上。我这次选择的是requests 字体映射解析的路线核心思路分四步先在浏览器里手动访问目标店铺的评论页面把完整Cookie复制出来备用。分析评论页面的真实请求链路找到店铺ID和加载下一页评论的异步接口。拿到HTML或者JSON后识别哪些字段被字体反爬下载字体文件做字符映射。把数据清洗成结构化表格存成CSV或者Excel。这套方案在Windows、macOS、Linux上都能跑依赖只有requests、fontTools、pandas这几个库非常适合个人电脑直接复现。2. 核心细节解析与实操要点2.1 x-forbid-reason到底在说什么以及怎样不被它盯上我最初入坑的时候被x-forbid-reason这个字段折磨了两天。第一次抓了十几页评论后突然返回的页面里全是“访问验证”响应头里赫然写着x-forbid-reason: referer。后来反复测试才发现问题出在我请求异步接口时没有带Referer头服务器认为这个请求不是从正常的浏览器页面跳转过来的。所以x-forbid-reason本质上就是一个“风控原因指示器”它告诉你这次请求是被哪个维度拦下来的。常见的几个值可以背一下referer请求头缺少Referer或者来源不对多半是翻页接口的校验。cookieCookie缺失、过期或者签名参数有问题。rate请求频率过高触发了单位时间内的访问次数限制。token异步接口里的动态token验证失败。应对方案也简单粗暴请求头尽量完整模拟真实浏览器的请求头包括User-Agent、Referer、Accept、Accept-Language这些全带上然后把请求频率降到你正常手速的十分之一以下另外每次请求前随机更换Cookie中的部分参数也不太实际最稳妥的做法是用一个长期稳定登录的账号Cookie不要频繁切换。注意响应头出现x-forbid-reason时不要立刻重试先停30秒到1分钟再继续否则会加剧风控判定后面可能直接封IP。2.2 字体反爬的原理拆解那些乱码数字是怎么还原的这是大众点评最有代表性的反爬手段也是很多新手最容易放弃的地方。我先用一个生活化的类比解释假设你写了一封信给朋友信里的数字“1234”全部用了只有你们俩看得懂的暗号代替。网站就是那个写信的人浏览器是那个朋友字体文件就是那本暗号对照表。普通人也就是我们这些爬虫开发者截获了信件但手里没有暗号表就完全不知道数字是什么。具体到实现上大众点评会把字体文件放在CSS的font-face里浏览器加载HTML时顺便下载这个字体文件然后把源码里的指定字符映射渲染。我们爬虫要做的就是从页面源代码里找到字体文件的URL一般是.woff或.svg格式。下载这个字体文件。用fontTools库解析字体文件提取每个字符的轮廓坐标或者cmap表。和正常的数字0-9的轮廓做比对建立“乱码字符 → 真实数字”的映射字典。遍历HTML源码把所有用字体反爬的字符替换成真实数字。听起来有点复杂但实际写代码时并不需要训练模型因为大众点评的字体文件每次虽然会变化但字符和数字的对应关系就在cmap表里而且数字本身只有10个字符做一次排列组合也不难。我后面会给出完整代码。2.3 评论接口与翻页参数拿不到真实数据就靠这个位置评论数据的来源需要先找到商户ID。在大众点评的搜索页搜到目标店铺后点进去看URL形如https://www.dianping.com/shop/xxx中间的那串数字就是shopId。评论页的URL一般是https://www.dianping.com/shop/{shopId}/review_all但直接request这个地址返回的HTML里只有前几页的评论数据之后再翻页就需要点击“加载更多”按钮触发异步请求。那么问题来了点击之后到底发了一个什么请求我用浏览器的开发者工具F12 → Network面板抓了一下发现翻页请求其实是一个POST请求URL形如https://www.dianping.com/shop/{shopId}/review_all/pN其中N是页码数字请求体里带着一个token参数。这个token隐藏在页面源码里需要从第一个response的HTML中提取。实操经验token在页面里往往以window.__TOKEN__或某个隐藏input节点的value形式出现。你只需要用正则或者XPath把它摘出来然后在每次翻页时带上它就行不需要知道它是怎么算出来的。2.4 环境依赖与工具准备跑代码前先把这个搞定在写代码之前先把环境搭好。我用的是Python 3.10实测3.8到3.12都能正常工作。需要安装的库只有三个命令如下pip install requests fonttools pandas如果下载字体文件速度慢可以加国内镜像源pip install requests fonttools pandas -i https://pypi.tuna.tsinghua.edu.cn/simple另外建议准备一个文本编辑器或者IDE我日常用的是VS Code配置好Python环境后直接新建文件就能跑。不需要安装浏览器驱动因为我们走的是requests方案这算是一个省心点。3. 实操过程与核心环节实现3.1 第一步从浏览器里拿Cookie把身份问题先解决掉这一步没法自动化也不需要自动化——你只要在你的浏览器里正常访问一次大众点评然后从开发者工具里把Cookie复制出来就行。具体操作打开Chrome登录自己的大众点评账号建议用手机App扫一下码这样登录状态更持久然后进入你想抓评论的那家店的评论页面。按下F12打开开发者工具切到Network标签刷新页面找到任意一个返回HTML的请求在请求头Request Headers里定位到Cookie:字段把冒号后面的整段内容复制下来。这段Cookie字符串很长但不要裁剪缺失一个参数都可能导致请求被判定为异常。我一般把它直接粘贴到代码文件顶部的COOKIE变量里像这样COOKIE _lxsdk_cuidxxx; _lxsdk_sxxx; dperxxx; ... # 你的完整Cookie实战提示Cookie不要明文提交到任何公开代码仓库这个就是你的登录凭证泄露了等于把账号送给别人用。我习惯把Cookie单独放在一个config.py文件里加进.gitignore。3.2 第二步解析评论页HTML定位评论区结构拿到店铺ID后先用requests把评论首页的HTML抓下来。这个步骤的目标不是直接提取评论而是做三件事验证Cookie是否有效、提取页面token、找到字体文件地址。代码大概长这样import re import requests HEADERS { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36, Accept: text/html,application/xhtmlxml,application/xml;q0.9,image/avif,image/webp,*/*;q0.8, Accept-Language: zh-CN,zh;q0.9,en;q0.8, Referer: https://www.dianping.com/, } def get_review_page(shop_id): url fhttps://www.dianping.com/shop/{shop_id}/review_all resp requests.get(url, headersHEADERS, cookiesparse_cookie(COOKIE), timeout10) resp.encoding utf-8 return resp.text def parse_cookie(cookie_str): pairs cookie_str.split(; ) return {k: v for k, v in (p.split(, 1) for p in pairs if in p)}这里有一个细节需要注意如果直接用字符串Cookie塞进requests的headers里requests会自动帮你处理但如果你用cookies参数传dict形式就得先做一次替换。两种方式都可以我习惯用cookies参数因为代码可读性更好。页面抓到后找一个靠谱的正则把token摘出来def extract_token(html): m re.search(rwindow\.__TOKEN__\s*\s*([^]), html) if m: return m.group(1) m re.search(rnametoken\svalue([^]), html) if m: return m.group(1) return None3.3 第三步处理字体反爬先把数字0-9的映射字典建出来这一步是整个项目里最有技术含量、也是最容易出bug的地方。先解释一下原理字体文件用字形轮廓来定义每个字符大众点评在渲染的时候给每个“数字字形”分配了一个私用区编码比如#xed23;而这个编码对应的真实数字需要通过解析字体文件才能知道。为了拿到这个映射我做了两件事一是从HTML源码里找到font-face的CSS地址二是下载并解析woff文件。找字体文件地址的正则def extract_font_url(html): m re.search(rfont-face\s*\{[^}]*font-family:\s*([^])[^}]*src:\s*url\(([^]\.woff)\), html, re.S) if m: return m.group(2) m re.search(rurl\(([^]\.woff)\), html, re.S) return m.group(1) if m else None然后下载这个字体文件用fontTools解析。这里我走了个捷径大众点评的字体文件虽然每个页面可能不同但字形的轮廓坐标其实和真实数字0-9非常接近。所以我可以先准备一份“标准数字轮廓库”然后把当前字体文件里的每个字形都做一个相似度匹配相似度最高的就是对应数字。但为了降低第一版代码的复杂度我实际使用的方法更简单粗暴——直接解析cmap表把私用区编码映射到字形名称然后通过人工比对一次生成一个静态字典。这种方法缺点是字体文件换一次就要重新跑一遍流程但胜在代码简洁适合教学。完整处理流程见下方代码这里我把映射字典的构建封装成函数from fontTools.ttLib import TTFont import io def load_font_mapping(woff_url): if not woff_url.startswith(http): woff_url https: woff_url resp requests.get(woff_url, headersHEADERS, timeout10) font TTFont(io.BytesIO(resp.content)) cmap font.getBestCmap() # 返回 {编码: 字形名称} # 手动映射示例实际使用时会根据解析结果调整 mapping {} for code, name in cmap.items(): if name.startswith(glyph): mapping[chr(code)] None elif name.isdigit(): mapping[chr(code)] name return mapping, font严格来说这一步不能完全自动化成“开箱即用”因为字体映射的准确率取决于代码里的对照表是否完整。所以我更推荐另一种思路预先抓取一个已知数字0-9的对照页面然后把当前地址里的字体文件和它做交叉比对。这个方法后续可以单开一篇推文详细讲这里点到为止。3.4 第四步解析评论区核心字段把脏数据清洗干净当HTML加载出来、字体映射也建立后剩下的就是常规的HTML解析工作了。我这里用的是正则 简单字符串切割因为大众点评的HTML结构相对稳定用XPath反而容易因为节点层级调整而失效。需要提取的核心字段包括用户名、评论时间、评论内容、评分口味、环境、服务、人均价格。下面是提取评价主体的函数def parse_reviews(html, font_mapping): reviews [] # 这里先定位到每条评论的包裹块再分别提取字段 blocks re.findall(rdiv classreview-words[^]*[^]*(.*?)/div, html, re.S) for block in blocks: text re.sub(r[^], , block).strip() text text.replace(收起回复, ).strip() # 如果text里有乱码数字用font_mapping替换 if font_mapping: for k, v in font_mapping.items(): if v is not None: text text.replace(k, v) reviews.append(text) return reviews每条评论里还会嵌套很多子元素包括通过字体反爬显示的人均价和星级所以我会在提取文本之后做一次“字体映射还原”处理把所有非标准数字字符统一替换回0-9。3.5 第五步翻页循环与异常重试设计一个带“呼吸感”的采集器抓取少量页面可以手动翻页但一旦页数超过10页就得写循环了。循环本身很简单真正考验的是节奏控制。我的策略是每请求一页随机暂停8到15秒每次触发反爬校验就停60秒再重试。这样做的目的很朴素——把人肉浏览的节奏模拟到位。你在手机上翻评论不可能一口气刷50页不带停顿爬虫也一样。翻页部分完整代码import time import random def fetch_all_reviews(shop_id, max_pages50): all_reviews [] base_url fhttps://www.dianping.com/shop/{shop_id}/review_all token None for page in range(1, max_pages 1): if page 1: url base_url else: url f{base_url}/p{page} resp requests.get(url, headersHEADERS, cookiesparse_cookie(COOKIE), timeout10) if resp.status_code ! 200 or 验证码 in resp.text: print(f第{page}页触发风控等待60s后重试) time.sleep(60) continue if not token: token extract_token(resp.text) page_reviews parse_reviews(resp.text, font_mapping) all_reviews.extend(page_reviews) print(f第{page}页抓取完成累计{len(all_reviews)}条) if page max_pages or len(page_reviews) 0: break time.sleep(random.uniform(8, 15)) return all_reviews这里有个隐性坑当len(page_reviews) 0时有可能是真的没有更多评论了也有可能是页面结构变了导致解析失败。所以我在打印日志时会额外输出响应码和页面长度方便排查到底是哪种情况。3.6 第六步数据落地输出成CSV避免“白抓”抓完的数据不能只留在内存里。我用pandas整理成DataFrame输出成CSV文件这样既有编码保障又方便Excel直接打开查看。import pandas as pd def save_to_csv(reviews, shop_id): df pd.DataFrame({content: reviews}) df.to_csv(fdianping_reviews_{shop_id}.csv, indexFalse, encodingutf-8-sig)之所以用utf-8-sig而不是utf-8是因为Excel打开UTF-8无BOM文件时中文容易乱码。这个小细节能帮你省掉很多数据清洗的麻烦。4. 常见问题与排查技巧实录4.1 死活拿不到数据先检查这两个地方Cookie和请求头如果你跑完代码后发现返回的页面里没有评论内容甚至打印出来的HTML里店铺名都是乱码那大概率是Cookie没有带全。很多教程建议只带关键的几个参数但大众点评的校验维度非常细只要缺一个就返回容器页但丢数据。另外检查一下请求头里的Referer。访问评论页时Referer一般指向前一个页面比如搜索页或店铺主页。如果你直接访问评论页而Referer留空风控系统很可能返回一个“访问异常”页面。我的习惯是在HEADERS里固定写一个Referer: https://www.dianping.com/实测不容易被拒绝。如果这些都没问题再看一下Accept-Language。缺失这个头时服务端可能返回英文版或者乱码增加解析难度。最好固定成zh-CN,zh;q0.9。4.2 字体文件解析报错或者映射对不上多半是这两个原因第一个原因是字体文件变了。大众点评会不定时更换字体文件的字形顺序所以你的本地映射字典可能只对某一天的页面有效。解决办法是每次请求页面前都动态拉一次字体文件用最新的映射字典替换旧的。第二个原因是.woff和.woff2格式混用。某些页面返回的是woff2格式fontTools默认可以读woff2但前提是你安装的版本足够新。如果解析报错先升级库pip install --upgrade fonttools如果还是报错检查一下下载的字节流是否被反爬脚本污染了——我在实操中遇到过多次返回了HTML验证码页面而不是字体文件内容的情况。所以下载字体文件时一定要校验响应内容的开头是不是wOFF或者OTTO不是的话先停一下说明IP已经被限流了。4.3 全部代码执行正常抓回来的评论里有大量重复记录怎么办重复的原因基本是两个翻页循环里第一页被抓了两次因为代码里page1和后续翻页可能访问同一个URL或者评论页本身在滑动加载时会重复返回上一页最后几条评论。我处理的方式是在保存前用内容去重df df.drop_duplicates(subset[content])如果连内容都相同但时间不同说明店铺有用户刷评论这种数据不建议直接丢弃而是保留后人工标记。竞品分析场景里评论时间重复是判断“异常评论”的一个重要特征。4.4 抓了十几页后必定触发验证码有没有办法绕过去这是所有大众点评采集场景都会撞上的墙坦白说没有任何一个爬虫能完全避开只能缓解。我的经验是控制页数单次任务不超过20页抓完一轮后停3到5分钟再继续下一轮。如果确实需要大量数据就分时段、分账号、构造完整的请求头组合再配合IP代理池分散请求源IP。重要我不推荐也不建议采用任何破解验证码的手段。遇到验证码就说明对方已经明确在拒绝你了此时最合适的选择是停止采集、降低频率或者通过官方渠道申请数据合作。网上那些“验证码自动识别”工具不但违规而且极容易连累你的IP段被人墙。5. 代码整理与扩展思路5.1 一版能直接跑的完整代码从入口函数到数据落地上面各节代码相对分散我在这部分把它们拼成一个可以直接执行的脚本。以下代码默认抓取单个店铺前10页评论保存为CSV文件。import io import re import time import random import requests import pandas as pd from fontTools.ttLib import TTFont SHOP_ID 12345678 # 改成你要抓的店铺ID COOKIE 你的完整Cookie HEADERS { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36, Accept: text/html,application/xhtmlxml,application/xml;q0.9,*/*;q0.8, Accept-Language: zh-CN,zh;q0.9,en;q0.8, Referer: https://www.dianping.com/, } def parse_cookie(cookie_str): return {k: v for k, v in (p.split(, 1) for p in cookie_str.split(; ) if in p)} def extract_token(html): m re.search(rwindow\.__TOKEN__\s*\s*([^]), html) if m: return m.group(1) m re.search(rnametoken\svalue([^]), html) return m.group(1) if m else None def extract_font_url(html): m re.search(rurl\(([^]\.woff2?)\), html, re.S) return m.group(1) if m else None def build_font_mapping(font_url): if not font_url: return {} if font_url.startswith(//): font_url https: font_url resp requests.get(font_url, headersHEADERS, timeout10) font TTFont(io.BytesIO(resp.content)) cmap font.getBestCmap() mapping {} for code, name in cmap.items(): char chr(code) if name.isdigit(): mapping[char] name return mapping def parse_reviews(html, font_mapping): items [] blocks re.findall(rdiv classreview-words[^]*[^]*(.*?)/div, html, re.S) for block in blocks: text re.sub(r[^], , block).strip() text text.replace(收起回复, ).strip() for k, v in font_mapping.items(): if v is not None: text text.replace(k, v) if text: items.append(text) return items def fetch_reviews(shop_id, max_pages10): all_items [] token None font_mapping {} base_url fhttps://www.dianping.com/shop/{shop_id}/review_all for page in range(1, max_pages 1): url base_url if page 1 else f{base_url}/p{page} try: resp requests.get(url, headersHEADERS, cookiesparse_cookie(COOKIE), timeout10) except requests.RequestException as e: print(f第{page}页请求异常: {e}) time.sleep(30) continue if resp.status_code ! 200 or 验证码 in resp.text: print(f第{page}页触发风控等待60秒) time.sleep(60) continue html resp.text if token is None: token extract_token(html) if not font_mapping: font_url extract_font_url(html) font_mapping build_font_mapping(font_url) page_items parse_reviews(html, font_mapping) all_items.extend(page_items) print(f第{page}页完成累计{len(all_items)}条token{token}, font_mapping{len(font_mapping)}个) if len(page_items) 0: print(当前页未解析到评论可能触底或结构变化) break time.sleep(random.uniform(8, 15)) return all_items if __name__ __main__: reviews fetch_reviews(SHOP_ID, max_pages10) df pd.DataFrame({content: reviews}).drop_duplicates() df.to_csv(fdianping_reviews_{SHOP_ID}.csv, indexFalse, encodingutf-8-sig) print(f保存完成共{len(df)}条评论)这个版本基本可以用但不保证所有大众点评页面结构都完全一样。如果你的目标店铺页面结构有调整优先检查正则表达式和class名是否需要改动。5.2 代码的后续演进方向并发、代理池与数据可视化当你的目标从“抓一家店”扩展成“抓一个商圈几十家店”时单线程串行抓取会变成瓶颈。但是请不要一上来就上高并发——大众点评对并发极其敏感我实测并发线程超过3个时触发验证码的概率成倍增长。结合我在评论区热词里看到有人讨论“爬虫并发设计到底哪个好”我的观点是抓大众点评这种高反爬站点并发设计的第一优先级不是快而是分散。可选的方向是用多线程分店铺并发每家店铺之间用不同的Cookie和出口IP每家店铺内部的评论页保持单线程顺序抓取。这样既保证了速度也把风控风险控制在了可接受的范围内。代理池方面如果要做大规模采集建议直接购买可靠的高匿代理服务不要使用免费的公共代理——那些代理IP大概率已经被大众点评标记上去就是死路一条。动态IP的切换策略建议每请求5到10个页面换一次IP且不要在同一秒内切换。数据拿到手之后还可以做评论情感分析、时间趋势分析、竞品口碑对比可视化。这部分我在实际项目里通常用jieba分词加SnowNLP做情感倾向打分再用pyecharts渲染成动态图表效果比干巴巴的Excel表格好得多。爬虫只是获取数据的手段数据背后的商业洞察才是价值所在。5.3 合规建议爬虫这件事底线比技术更重要在文章最后我想认真地说一句大众点评的评论数据是UGC内容属于用户和平台共同拥有的数字资产未经许可的规模化抓取有侵权风险。我写这篇文章的目的不是教你怎么绕过大众点评的防线而是帮你理解反爬机制明白自己能做什么、不能做什么。如果你只是拿代码跑通流程、学一下字体反爬和请求模拟的基本功那没问题。如果你想做商业采集请务必先走正规渠道比如和大众点评官方谈数据合作或者用第三方正规API。技术路线的尽头永远是法律和商业规则提前想清楚边界比调试一夜代码重要得多。结尾这套爬虫方案我从头到尾跑过很多遍最深的体会是大众点评的反爬其实并不存在“一招破解”的银弹它考验的是你对HTTP请求、前端渲染、字体文件这几个基础概念的掌握程度。很多人卡在字体反爬那一步就放弃了实际上静下心分析一次你就会发现字体映射并没有想象中那么神秘。我自己在踩过x-forbid-reason的坑之后学会的最重要一课反而是克制——把请求频率降到最低把采集规模控制在合理范围数据反而拿得更稳更全。最后再分享一个小技巧如果你只是临时想看少数几家店的评论走势用浏览器无痕模式手动翻页顺便复制数据可能比写代码还快技术选型永远是服务于具体场景的。
返回列表