news 2026/4/15 1:53:19

Python爬虫实战:用Requests+正则搞定马蜂窝景点评论,数据直接存TXT

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python爬虫实战:用Requests+正则搞定马蜂窝景点评论,数据直接存TXT

Python爬虫实战:高效抓取旅游网站评论数据并存储为TXT

最近在研究旅游景点的用户评价数据时,发现手动收集效率实在太低。作为一个Python爱好者,我决定用爬虫技术来解决这个问题。本文将分享一个完整的实战案例,教你如何用Requests库和正则表达式从旅游网站抓取评论数据,并保存为易于分析的TXT格式。

1. 准备工作与环境搭建

在开始编写爬虫之前,我们需要确保开发环境已经准备就绪。Python 3.x是最佳选择,因为它对Unicode的支持更好,能有效处理中文网页内容。

首先安装必要的库:

pip install requests

Requests库是Python中最受欢迎的HTTP客户端库,相比内置的urllib,它提供了更简洁的API和更好的性能。我们还需要Python内置的re模块来处理正则表达式,无需额外安装。

提示:建议使用虚拟环境来管理项目依赖,避免不同项目间的库版本冲突。

对于初学者来说,理解网页结构是爬虫开发的第一步。现代网站通常采用前后端分离的架构,数据通过API接口提供,这正是我们要利用的。通过浏览器开发者工具(F12),我们可以轻松找到这些API接口。

2. 分析目标网站的数据接口

旅游网站通常会为每个景点提供专门的评论页面,这些评论数据往往通过AJAX请求动态加载。通过分析网络请求,我们发现评论数据实际上是通过一个特定的API接口获取的。

典型的评论API接口可能长这样:

https://api.example.com/comments?poi_id=12345&page=1

其中poi_id代表景点ID,page参数控制分页。理解这个接口结构对我们的爬虫开发至关重要。

为了模拟浏览器行为,我们需要设置合适的请求头。最常见的两个头部字段是:

  • User-Agent:标识客户端类型,避免被识别为爬虫
  • Referer:表明请求来源,有些网站会检查这个字段
headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36', 'Referer': 'https://www.example.com/poi/12345.html' }

3. 编写核心爬取逻辑

现在我们可以开始编写爬虫的核心代码了。首先定义一个函数来获取单页评论数据:

import requests import re def fetch_comments(poi_id, page=1): url = f'https://api.example.com/comments?poi_id={poi_id}&page={page}' headers = { 'User-Agent': 'Mozilla/5.0...', 'Referer': f'https://www.example.com/poi/{poi_id}.html' } try: response = requests.get(url, headers=headers) if response.status_code == 200: return response.text else: print(f"请求失败,状态码:{response.status_code}") return None except Exception as e: print(f"发生异常:{str(e)}") return None

获取到原始数据后,我们需要用正则表达式提取有用信息。评论数据通常包含以下几个关键字段:

  1. 评论日期
  2. 评分星级
  3. 评论内容

对应的正则表达式可能如下:

def parse_comments(html): # 提取日期 date_pattern = r'"date":"(.*?)"' dates = re.findall(date_pattern, html) # 提取星级 star_pattern = r'"star":(\d)' stars = re.findall(star_pattern, html) # 提取评论内容 content_pattern = r'"content":"(.*?)"' contents = re.findall(content_pattern, html) return list(zip(dates, stars, contents))

4. 数据存储与持久化

将爬取到的数据保存到本地文件是爬虫的最后一步。TXT格式简单易用,适合后续的数据分析。我们可以定义一个函数来处理数据存储:

def save_to_txt(data, filename): with open(filename, 'w', encoding='utf-8') as f: for item in data: date, star, content = item # 清理数据中的特殊字符和HTML标签 content = re.sub(r'<.*?>', '', content) content = content.replace('\n', ' ').replace('\r', '') f.write(f"{date}\t{star}\t{content}\n")

为了提高代码的健壮性,我们还需要考虑以下几点:

  1. 异常处理:网络请求可能失败,数据可能不完整
  2. 速率限制:避免对服务器造成过大压力
  3. 数据去重:防止重复存储相同数据
import time def crawl_all_comments(poi_id, max_pages=5): all_comments = [] for page in range(1, max_pages + 1): print(f"正在爬取第{page}页...") html = fetch_comments(poi_id, page) if html: comments = parse_comments(html) if comments: all_comments.extend(comments) time.sleep(1) # 礼貌性延迟 return all_comments

5. 完整代码示例与优化建议

将上述各部分组合起来,我们得到一个完整的爬虫实现:

import requests import re import time from typing import List, Tuple class CommentCrawler: def __init__(self): self.session = requests.Session() self.session.headers.update({ 'User-Agent': 'Mozilla/5.0...', 'Accept-Language': 'zh-CN,zh;q=0.9' }) def fetch_page(self, poi_id: str, page: int) -> str: url = f'https://api.example.com/comments?poi_id={poi_id}&page={page}' referer = f'https://www.example.com/poi/{poi_id}.html' try: response = self.session.get(url, headers={'Referer': referer}) response.raise_for_status() return response.text except requests.RequestException as e: print(f"请求第{page}页失败: {str(e)}") return None def parse_comments(self, html: str) -> List[Tuple[str, str, str]]: date_pattern = r'"date":"(.*?)"' star_pattern = r'"star":(\d)' content_pattern = r'"content":"(.*?)"' dates = re.findall(date_pattern, html) stars = re.findall(star_pattern, html) contents = re.findall(content_pattern, html) # 简单的数据校验 min_length = min(len(dates), len(stars), len(contents)) return list(zip(dates[:min_length], stars[:min_length], contents[:min_length])) def save_comments(self, comments: List[Tuple[str, str, str]], filename: str): with open(filename, 'w', encoding='utf-8') as f: for date, star, content in comments: # 数据清洗 clean_content = re.sub(r'[\\\/]', '', content) clean_content = re.sub(r'<.*?>', '', clean_content) clean_content = clean_content.replace('\n', ' ').strip() f.write(f"{date}\t{star}\t{clean_content}\n") def crawl(self, poi_id: str, max_pages: int = 5): all_comments = [] for page in range(1, max_pages + 1): print(f"处理第{page}页...") html = self.fetch_page(poi_id, page) if html: comments = self.parse_comments(html) if comments: all_comments.extend(comments) time.sleep(1.5) # 增加延迟避免被封 return all_comments # 使用示例 if __name__ == '__main__': crawler = CommentCrawler() comments = crawler.crawl('7391903') # 替换为实际景点ID crawler.save_comments(comments, 'travel_comments.txt') print(f"成功爬取并保存了{len(comments)}条评论")

对于想要进一步优化的开发者,可以考虑以下几点:

  1. 使用代理IP:防止单一IP被封锁
  2. 实现断点续爬:记录已爬取的页码,意外中断后可继续
  3. 添加日志系统:便于调试和监控爬虫运行状态
  4. 支持多种存储格式:如CSV、JSON等,适应不同需求

6. 常见问题与解决方案

在实际开发过程中,你可能会遇到以下问题:

问题1:请求返回403 Forbidden错误

可能原因

  • 缺少必要的请求头
  • IP被暂时封锁
  • 需要处理Cookie或Token

解决方案

headers = { 'User-Agent': '...', 'Referer': '...', 'Accept': 'application/json', 'X-Requested-With': 'XMLHttpRequest' }

问题2:数据提取不完整

可能原因

  • 正则表达式不够精确
  • 数据是动态加载的
  • 响应格式发生了变化

解决方案

# 更精确的正则表达式示例 content_pattern = r'"content":"((?:[^"\\]|\\.)*)"'

问题3:编码问题导致乱码

处理方法

# 确保使用正确的编码 response.encoding = 'utf-8' content = response.text

对于更复杂的反爬机制,可能需要考虑:

  • 使用Selenium模拟浏览器行为
  • 解析JavaScript生成的内容
  • 处理验证码挑战

7. 数据清洗与分析建议

获取到原始数据后,通常需要进行清洗才能用于分析。常见的清洗操作包括:

  1. 去除HTML标签和特殊字符
  2. 处理空白和换行符
  3. 标准化日期格式
  4. 过滤无效或重复数据

这里有一个简单的数据清洗函数示例:

def clean_comment_text(text): # 移除HTML标签 text = re.sub(r'<[^>]+>', '', text) # 替换HTML实体 text = text.replace('&amp;', '&').replace('&lt;', '<').replace('&gt;', '>') # 标准化空白字符 text = ' '.join(text.split()) return text.strip()

对于想要进行情感分析的开发者,可以考虑:

  1. 使用中文分词工具(如jieba)处理评论内容
  2. 构建情感词典或使用预训练模型
  3. 分析评分与情感倾向的关系
import jieba from collections import Counter def analyze_comments(comments): all_words = [] for _, _, content in comments: words = jieba.cut(content) all_words.extend(words) word_counts = Counter(all_words) print("最常见的20个词:", word_counts.most_common(20))

这个爬虫项目最让我惊喜的是,只需要不到100行代码就能完成从数据获取到存储的完整流程。在实际使用中,我发现合理设置请求间隔(1-2秒)能显著降低被封风险,而使用Session对象可以保持连接复用,提高效率。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/15 1:53:11

先免费试用下Claude code安装使用(教程)

&#x1f9d1;‍&#x1f4bb; 写在开头 点赞 收藏 学会&#x1f923;&#x1f923;&#x1f923; 2026年了&#xff0c;如果还不会使用一款AI编程工具&#xff0c;未来将会越来越难行。 今天我们先来使用一个终端编程比较火的工具&#xff1a;Claude code 一、安装 1、node…

作者头像 李华
网站建设 2026/4/15 1:47:09

高效盘点光学污泥界面分析仪的适用场景

光学污泥界面分析仪是一种基于光学散射或透射原理&#xff0c;通过测量污泥层与清液层的光学特性差异来实时监测污泥界面高度的设备。其非接触式测量、响应速度快、精度高的特点&#xff0c;使其在多个领域成为污泥界面监测的理想工具。1、市政污水处理厂 在活性污泥法处理工艺…

作者头像 李华
网站建设 2026/4/15 1:39:35

健身房|基于springboot + vue健身房管理系统(源码+数据库+文档)

健身房管理系统 目录 基于springboot vue健身房管理系统 一、前言 二、系统功能演示 详细视频演示 三、技术选型 四、其他项目参考 五、代码参考 六、测试参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 基于springboot vue健身房管理系统 一、前言 博…

作者头像 李华