ARTICLE DETAIL

资讯详情

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

Python爬虫实战:用requests+BeautifulSoup采集大众点评评论数据

Python爬虫实战:用requests+BeautifulSoup采集大众点评评论数据 用python爬大众点评评论这个需求我接过不止一次。做竞品调研的要对比各家门店的用户反馈做本地生活服务的要分析口碑变化还有很多刚学爬虫的朋友想找一个真实网站练手。大众点评的评论数据恰好是这种“想用又不好拿”的类型页面结构清晰、数据量大、公开可看但反爬又会给你制造一点小麻烦算是一个很经典的爬虫练手项目。这篇博文不是给你讲一堆抽象的概念而是直接给你一套思路清晰、注释到位、可以直接复制运行的python爬虫代码框架。核心技术上用的是python爬虫里最常见也最好上手的requests BeautifulSoup组合不需要Selenium不需要复杂的环境配置只要你的电脑能装python、能跑pip就能跟着走一遍。不管你是刚学完python基础语法想动手写点东西的新手还是需要评论数据做分析的同学这篇都值得你花十分钟看完。1. 内容整体设计与思路拆解1.1 为什么用requests BeautifulSoup而不是Selenium很多朋友一上来就问我能不能用Selenium模拟浏览器因为它能自动点击、滚动、翻页看起来很省事。其实对于大众点评评论页这种场景Selenium属于“杀鸡用牛刀”。你要额外下载浏览器驱动要维护一个浏览器实例启动慢、内存占用高而且代码里到处都是driver.find_element一旦页面多了一层遮罩或者加载慢脚本就各种报错对新手来说排查问题非常痛苦。大众点评的评论内容绝大多数情况是直接封装在服务器返回的HTML里的哪怕页面看起来是异步加载你也可以在Network面板里找到真正返回评论数据的请求。我们用requests把页面源码拉下来再用BeautifulSoup从HTML里把评论精确地“找”出来这个方案又轻又快还方便观察每一步的结果。等以后你去做其他更复杂的采集项目时requests BeautifulSoup这套底子照样能用它永远是爬虫领域最基础、最通用的组合。1.2 爬虫整体流程与数据流设计任何一个爬虫项目本质上都是下面这条流水线大众点评评论采集也不例外构造请求参数 - 发起HTTP请求 - 获取响应内容 - 解析HTML - 数据清洗 - 保存结果我在设计这套代码时重点考虑了三个地方。第一是请求参数。大众点评的反爬策略比普通网站要严格一些请求头里的User-Agent、Referer、Cookie都需要处理代码里我用requests的Session对象来统一管理这样后续所有请求都会自动带上同样的请求头。第二是解析策略。评论数据在HTML里的结构相对固定一般有用户名、评分、评论文本、评论时间等字段。解析时我从一个大的评论容器节点出发再逐条提取字段代码清晰后续也好改。第三是存储方式。为了“直接copy就能运行”我没有引入数据库这些额外依赖而是把数据写入CSV文件。CSV格式轻量、通用Excel可以直接打开pandas也能直接读取对初学者来说是最友好的落地方式。2. 环境准备与依赖安装2.1 Python环境与编辑器准备这一步很基础但很多人卡在环境上。如果你的电脑还没有python先去官网下载安装包版本选3.8以上就行最新稳定版更好。安装时记得勾选“Add Python to PATH”这个勾选很重要不勾的话后面在命令行里打python会提示找不到命令。装完以后打开命令行输入python --version能输出版本号就说明环境没问题。编辑器方面如果你不是那种命令行玩得很溜的老手直接用VSCode就好。VSCode轻巧装好python扩展后就能直接运行脚本调试也很方便。当然如果你习惯用记事本或者IDE也都行。用文本文档保存成.py后缀然后在命令行执行python 文件名.py就能跑没有任何魔法。很多人问“文本文档怎么运行代码”其实就是这个流程先确保python装好了再把文件后缀改成.py最后在命令行里调用。2.2 依赖库安装与验证这个项目只需要两个第三方库requests负责发HTTP请求beautifulsoup4负责解析HTML。在命令行里执行pip install requests beautifulsoup4如果安装速度慢可以加国内镜像源这个属于常规操作。另外我建议顺手安装lxml解析库因为BeautifulSoup支持多种解析器默认的html.parser也能解析但lxml是用C语言写的解析速度快很多当评论数据量大的时候能明显感受到差别pip install lxml安装完成后用一行代码验证一下python -c import requests, bs4; print(requests.__version__, bs4.__version__)能打印出版本号依赖就齐了。如果你用的是Anaconda环境这些库通常已经预装不用再单独安装。2.3 跑代码前必须准备的两样东西在跑代码之前有两样东西必须自己动手准备店铺链接和Cookie。店铺链接很简单浏览器打开大众点评网页端搜索你要采集的目标店铺点击进入店铺详情页把地址栏里的URL复制出来就行。Cookie稍微麻烦一点但跟着操作也很好拿。用浏览器打开大众点评登录你的账号没有账号就注册一个这一步不能省略因为大众点评的评论数据在未登录状态下能看到的很有限。登录后按F12打开开发者工具切到Network标签页刷新一下页面随便点击一个请求在Request Headers里找到Cookie:那一行把后面的内容整个复制出来后面代码里会用。这里有个重要提醒Cookie是跟账号和登录状态绑定的会过期。如果代码跑着跑着你发现突然被拦截了多半就是Cookie失效重新去浏览器里复制一个新的替换掉就行。3. 核心代码实现复制粘贴就能跑通的爬虫3.1 请求头与Cookie为什么这样设置先说请求头为什么要这样设置。大众点评会对没有浏览器标识的请求直接拒绝所以User-Agent必须伪造。Referer的作用更直接它告诉服务器“我是从这个页面跳过来的”大众点评的服务器会校验这一点不带Referer很容易被识别成机器请求。Cookie则表明“我是一个已登录用户”有了它评论数据的完整度会高很多。代码里我用了requests.Session()这个东西最大的好处就是能保持会话状态。你用同一个session发出去的每一个请求都会自动复用已经设置好的请求头不需要在每次请求时重复传参数。对于后续翻页、拉取更多评论这个设计能省很多事。另外要注意请求频率绝对不能太快。大众点评对单位时间内的请求次数很敏感如果频率太高轻则返回空数据重则直接弹验证码。我习惯在每两次请求之间sleep一个随机时间比如2到4秒既不会太慢也不至于触发风控。3.2 完整可运行代码改两个参数直接跑下面是我整理好的完整代码。结构上我封装成了一个类这样做的好处是代码清晰、便于扩展。你把代码保存为dianping_spider.py替换掉文件里的店铺URL和Cookie然后直接运行就可以了。# -*- coding: utf-8 -*- 大众点评评论采集脚本 依赖库requests、beautifulsoup4 运行方式python dianping_spider.py 注意请自行登录大众点评网页端从浏览器开发者工具中复制Cookie import csv import time import random import requests from bs4 import BeautifulSoup class DianpingSpider: def __init__(self, shop_url, cookie): self.shop_url shop_url self.cookie cookie self.session requests.Session() self.session.headers.update({ 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, Referer: https://www.dianping.com/, Cookie: self.cookie, 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, }) def fetch_html(self, url): 发起请求返回页面HTML源码 try: response self.session.get(url, timeout10) response.encoding utf-8 return response.text except requests.exceptions.RequestException as e: print(f[请求失败] {url} {e}) return def parse_comments(self, html): 从HTML中解析评论数据 soup BeautifulSoup(html, lxml) # 常见的评论列表容器如果页面改版优先检查这里 items soup.find_all(div, class_[review-list-item, comment-item]) comments [] for item in items: try: # 用户名 nick_node item.find(a, class_name) # 有些页面用户名不带链接直接用span if nick_node is None: nick_node item.find(span, class_name) nickname nick_node.get_text(stripTrue) if nick_node else 匿名用户 # 评分 rating_node item.find(span, class_score) rating rating_node.get_text(stripTrue) if rating_node else 无 # 评论内容 content_node item.find(div, class_review-content) if content_node is None: content_node item.find(p, class_content) content content_node.get_text(stripTrue) if content_node else 无内容 # 评论时间 time_node item.find(span, class_time) comment_time time_node.get_text(stripTrue) if time_node else 未知时间 comments.append({ nickname: nickname, rating: rating, content: content, time: comment_time, }) except Exception as e: print(f[解析单条评论出错] {e}) continue return comments def save_to_csv(self, comments, filenamedianping_comments.csv): 保存到CSV文件 if not comments: print([提示] 本次没有采集到评论数据跳过保存) return with open(filename, a, newline, encodingutf-8-sig) as f: fieldnames [nickname, rating, content, time] writer csv.DictWriter(f, fieldnamesfieldnames) if f.tell() 0: writer.writeheader() writer.writerows(comments) print(f[保存成功] 新增 {len(comments)} 条评论 - {filename}) def run(self): print(f[开始采集] 目标店铺{self.shop_url}) html self.fetch_html(self.shop_url) if not html: print([提示] 页面源码为空请检查网络或Cookie是否有效) return comments self.parse_comments(html) print(f[解析完成] 共得到 {len(comments)} 条评论) self.save_to_csv(comments) if __name__ __main__: SHOP_URL https://www.dianping.com/shop/123456 # 替换成你要采集的店铺URL COOKIE 这里粘贴你的Cookie从浏览器开发者工具里复制 # 替换成你登录后的Cookie spider DianpingSpider(SHOP_URL, COOKIE) spider.run() # 每次请求之间随机休息避免频率太高 time.sleep(random.uniform(2, 4))这段代码的运行逻辑不复杂。fetch_html负责把页面源码抓回来parse_comments用BeautifulSoup逐条提取评论数据save_to_csv把结果追加写入CSV文件run负责把整条流水线串起来。你只需要改两个变量SHOP_URL和COOKIE。3.3 解析逻辑说明最容易被忽略的细节代码里最关键的地方就是parse_comments函数这里的选择器必须跟页面实际结构匹配。我在代码里写了两种常见的class作为备选review-list-item和comment-item。大众点评的页面在不同版本、不同城市下评论容器的class可能会不太一样所以你如果发现解析出的评论数是0第一件事就是在浏览器里按F12定位到某一条评论的DOM节点看看它外层容器到底是什么class然后把这个class填进find_all里。后面的用户名、评分、评论内容、评论时间也是同样的道理。页面上标签字体会变class也可能会从name改成其他名字这些都需要你根据实际页面微调。我给的是“能跑通的框架”而不是“永远不变的死代码”这一点希望大家理解。还有一个细节item.find(div, class_review-content)注意这里的下划线写成class_因为class是python的保留关键字这是BeautifulSoup的固定写法很多人第一次写会踩这个坑。3.4 CSV保存与数据去重思路保存数据时我用的是encodingutf-8-sig而不是普通的utf-8。为什么因为要用Excel直接打开CSV文件时普通utf-8编码的中文很容易出现乱码而utf-8-sig会在文件开头写入BOM标识Excel就能正确识别中文内容了。重复数据是爬虫里最常见的脏数据问题。如果脚本连续跑了很多次CSV里会积累大量重复评论。最简单的去重方式是在解析完数据后按“用户名评论内容”作为唯一标识用集合去过一遍或者每次跑完后在pandas里做drop_duplicates()。我平时习惯在保存数据这一步就用内容做检查避免垃圾数据越积越多。下面是去重的简化写法可以加在save_to_csv里seen set() unique_comments [] for c in comments: key c[nickname] c[content] if key not in seen: seen.add(key) unique_comments.append(c)跑完以后unique_comments就是去重后的评论列表再交给DictWriter写入就行。这样跑多次也不会出现同一批评论反复堆在CSV里的情况。4. 常见问题排查与避坑实录4.1 返回403或被弹验证码时的处理顺序这个问题几乎每个人都会遇到。403状态码说明服务器识别出了请求不是正常浏览器访问最常见的原因有三个User-Agent太简单、没有带Cookie、请求频率太快。排查顺序我建议这样先看代码里有没有设置合适的User-Agent再看Cookie是不是最新、有没有过期最后看是不是连续跑太多次导致触发了风控。如果是最后一种建议停止脚本等几分钟再继续不要硬闯验证码硬闯只会让风控升级。4.2 页面返回200但解析结果为空能用浏览器打开页面但代码解析出来一条评论都没有这种情况也很常见。大概率是页面结构变了或者find_all里写的class跟实际HTML不一致。遇到这种问题先别急着改代码把抓回来的HTML保存成文件用浏览器打开本地文件直接在开发者工具里搜索你解析的关键字一眼就能看出哪里对不上。改完选择器再重新跑。4.3 只能抓取第一页评论的翻页方案网络上很多评论分布在多个页面。翻页的常见做法有两种一是很多站点的翻页链接里带着页码参数比如?page2只需要循环拼接URL即可二是有的站点会通过动态请求接口加载下一页数据这时候就不能只靠解析HTML了得去Network里找真正的数据接口。大众点评这类网站的不同页面、不同端翻页机制也有差异。要先在浏览器里点击“下一页”看地址栏URL有没有变化再决定用什么方式。4.4 高频问题快速排查表现象可能原因解决办法运行报ModuleNotFoundError依赖库没装好检查pip install requests beautifulsoup4是否成功请求返回403反爬拦截检查User-Agent、Referer、Cookie是否配置完整返回200但解析为0条页面结构改版或选择器不匹配用开发者工具核对评论容器的class中文写入CSV乱码编码不对使用encodingutf-8-sig连续请求后出现空白内容请求频率过高触发风控增加sleep时间停止一段时间再继续Cookie失效导致数据变少登录状态过期重新从浏览器复制最新Cookie这张表基本覆盖了我平时被问到的高频问题。如果你遇到的问题不在表里最快的排查方式不是瞎改代码而是把自己抓到的HTML保存下来再对照页面源码一步步看比任何猜测都有效。5. 从单页采集到数据分析的扩展方向5.1 从单页到多页翻页循环与多店铺批量采集把单页代码跑通之后就可以考虑扩展了。最简单的扩展是翻页把run方法改成接收一个页码参数循环调用fetch_html每页之间sleep一个随机时间。再进一步多店铺批量采集可以维护一个店铺URL列表用两层循环依次采集。如果你想多线程并发建议用ThreadPoolExecutor但并发数一定控制在3个以内并且在每次请求之间保留合理的间隔重点是不给目标服务器制造压力。这套框架不只适用于大众点评。换一下URL规则、调整一下选择器和字段映射同样的思路也可以用来采集其他平台的公开数据。比如爬取淘宝商品评论、统计酷狗音乐数据、抓取得物商品信息本质上都是“构造请求、解析HTML、清洗保存”这套流程。学会一套方法再迁移到不同场景比背一大堆零散代码要高效得多。5.2 评论数据的词频统计与简单情感分析采集只是第一步拿到评论数据之后你能做的事情很多。比如用python的jieba库做分词然后统计词频看看用户提到最多的词是“味道”“服务”还是“排队”再比如做简单的评分分布分析看看店铺口碑到底是靠一两个5星撑起来还是整体评分稳定。情感分析也可以玩提前准备一份正向词表和负向词表按评论内容里出现的词汇数量打分就能粗略判断用户评论是偏好评还是差评。import jieba from collections import Counter # 假设comments是一个包含评论文本的列表 texts [c[content] for c in comments] words [] for t in texts: words.extend(jieba.lcut(t)) word_count Counter(words) print(word_count.most_common(20))这段代码跑完后你能看到评论里反复出现的高频词再结合评分字段差不多就能画出店铺口碑的大致轮廓。这些分析脚本本身不复杂但数据必须是干净、量大的这就是爬虫代码值得打磨的原因。5.3 性能优化与合规使用提醒整个代码跑通后性能上最值得优化的地方是解析部分lxml解析器比默认的html.parser要快不少代码里已经指定了lxml。存储方面如果数据量特别大CSV可能不够用建议换成SQLitepython自带sqlite3库不需要额外安装依赖数据查询也方便多了。最后我必须多说一句合规的事。写爬虫是为了学习技术、研究公开数据不是用来对抗目标网站的防护更不能拿别人平台的数据做精细化营销或者牟利。采集公开的评论信息要遵守目标网站的服务条款控制在合理频率内不要影响对方网站的正常运行也不要收集评论中可能涉及的个人隐私内容。技术本身是中性的但使用方式决定了它是工具还是问题。我自己一直的原则是用于学习研究可以用于商业化必须确认版权和使用边界。写在最后这几个项目做完以后我最大的感受是爬虫从业余到“真会用”真正拉开差距的不是代码技巧而是排查问题的思路。刚开始跑大众点评评论采集时我也被403、被写进CSV的乱码、被选择器匹配不到折腾过无数次后来慢慢养成一个习惯——先把页面HTML完整保存下来再像查字典一样去对结构问题一下就清晰了。最后分享一个小技巧所有直接copy的代码一定要先看明白再跑。建议你跑通之后再花半小时把代码里每个方法单独改写一遍改成你自己的风格这个过程比看十篇教程都管用。
返回列表