Python爬虫实战:抓取《疯狂动物城》相关社交媒体讨论

在信息爆炸的时代,社交媒体上的用户讨论蕴含着巨大的价值。无论是影视宣发效果评估,还是受众情感倾向分析,都需要从海量的社交媒体内容中提取有效信息。《疯狂动物城》作为一部兼具口碑与热度的经典动画电影,其相关社交媒体讨论至今仍保持着一定活跃度。本文将通过 Python 爬虫实战,详细讲解如何抓取微博平台上《疯狂动物城》的相关讨论数据,包括技术选型、核心逻辑实现、反爬规避及数据保存等关键环节,帮助读者掌握实用的爬虫开发技能。

一、技术选型与环境准备

1. 核心技术栈说明

爬虫开发的核心需求是发送网络请求、解析页面内容和数据存储,本次实战选用以下成熟工具库:

  • requests:轻量级 HTTP 请求库,支持 GET/POST 等请求方式,API 简洁易用,能高效处理网络请求与响应。
  • BeautifulSoup4:HTML/XML 解析库,支持多种解析器,可通过 CSS 选择器或标签树结构快速提取目标数据,无需复杂的正则表达式。
  • pandas:数据分析与处理库,提供强大的数据结构(DataFrame),支持将抓取的数据快速导出为 CSV/Excel 等格式,方便后续分析。
  • time 与 random:Python 内置库,用于实现请求延迟控制,避免高频请求触发目标网站反爬机制。

2. 环境搭建步骤

首先确保本地已安装 Python 3.7 及以上版本(推荐 3.9 版本)

二、爬虫核心逻辑分析

1. 目标平台结构解析

本次抓取的目标是微博搜索结果页,其核心特征如下:

  • 搜索 URL 格式:<font style="color:rgb(0, 0, 0);">https://s.weibo.com/weibo?q=关键词&page=页码</font>,其中<font style="color:rgb(0, 0, 0);">q</font>参数为搜索关键词(需 URL 编码,requests 库会自动处理),<font style="color:rgb(0, 0, 0);">page</font>参数为分页页码。
  • 页面结构:每一页包含多条微博卡片,每条卡片包含用户名、发布时间、内容、点赞数、评论数、转发数等核心数据。
  • 反爬机制:未登录状态下可访问有限页数,高频请求会触发 IP 封禁,页面内容通过静态 HTML 渲染(无复杂 JS 动态加载,适合 BeautifulSoup 解析)。

2. 爬虫工作流程设计

爬虫的整体工作流程遵循 "请求 - 解析 - 存储" 的经典模式,具体步骤如下:

  1. 配置关键参数:包括搜索关键词、抓取页数、请求头、数据保存路径等。
  2. 分页请求页面:循环拼接不同页码的 URL,发送网络请求获取页面 HTML 内容,加入随机延迟控制请求频率。
  3. 解析页面数据:使用 BeautifulSoup 解析 HTML,通过 CSS 选择器定位目标元素,提取用户名、内容、互动数据等信息。
  4. 数据整合存储:将多页抓取的数据整合为统一结构,通过 pandas 导出为 CSV 文件,便于本地查看与分析。

三、完整代码实现与详细解析

1. 全局配置与依赖导入

首先导入所需库并配置核心参数,其中请求头(Headers)是规避反爬的关键:

python

运行

python 复制代码
import requests
from bs4 import BeautifulSoup
import pandas as pd
import time
import random

# 全局配置参数(可根据需求调整)
KEYWORD = "疯狂动物城"  # 搜索关键词
PAGE_NUM = 10  # 计划抓取的页数(建议≤20,避免反爬)
SAVE_PATH = "zootopia_social_media_data.csv"  # 数据保存路径

# 伪装浏览器请求头(关键!模拟真实用户访问)
HEADERS = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36",
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
    "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
    "Referer": "https://s.weibo.com/",  # Referer字段,表明请求来源
    "Cookie": "请替换为你的微博Cookie(登录后获取,可选但推荐)"
}

关键说明

  • User-Agent:模拟 Chrome 浏览器访问,不同浏览器的 User-Agent 可通过 "浏览器 UA 查询" 获取。
  • Cookie:登录微博后,在浏览器开发者工具(F12)→ Network → 任意请求的 Request Headers 中复制,添加后可提升爬取页数和稳定性。

2. 页面请求函数实现

负责发送 HTTP 请求,获取单页 HTML 内容,并处理异常情况:

python

运行

python 复制代码
def fetch_weibo_page(page):
    """
    发送请求获取指定页码的微博搜索结果页面
    :param page: 页码(int)
    :return: 页面HTML内容(str)或None(请求失败)
    """
    # 拼接完整URL,requests会自动对关键词进行URL编码
    url = f"https://s.weibo.com/weibo?q={KEYWORD}&page={page}"
    try:
        # 随机延迟1-3秒,避免高频请求触发反爬
        time.sleep(random.uniform(1, 3))
        # 发送GET请求,设置超时时间10秒
        response = requests.get(
            url=url,
            headers=HEADERS,
            timeout=10,
            allow_redirects=True  # 允许重定向
        )
        # 检查响应状态码,非200则抛出异常
        response.raise_for_status()
        # 自动识别页面编码,避免中文乱码
        response.encoding = response.apparent_encoding
        print(f"第{page}页请求成功,状态码:{response.status_code}")
        return response.text
    except requests.exceptions.HTTPError as e:
        print(f"第{page}页请求失败,HTTP错误:{e}")
    except requests.exceptions.ConnectionError:
        print(f"第{page}页请求失败,网络连接错误")
    except requests.exceptions.Timeout:
        print(f"第{page}页请求失败,超时未响应")
    except Exception as e:
        print(f"第{page}页请求失败,未知错误:{str(e)}")
    return None

异常处理设计

  • 捕获 HTTP 错误(如 403 禁止访问、404 页面不存在)、网络连接错误、超时错误等常见异常,确保程序不会因单页请求失败而终止。
  • 随机延迟:通过<font style="color:rgb(0, 0, 0);">random.uniform(1,3)</font>生成 1 到 3 秒的随机延迟,模拟人类浏览行为,降低被识别为爬虫的概率。

3. 页面解析函数实现

使用 BeautifulSoup 解析 HTML,提取核心数据,这是爬虫的核心环节:

python

运行

python 复制代码
def parse_weibo_content(html):
    """
    解析微博页面HTML,提取核心数据
    :param html: 页面HTML内容(str)
    :return: 解析后的数据集(list of dict)
    """
    # 初始化BeautifulSoup对象,使用html.parser解析器(内置无需额外安装)
    soup = BeautifulSoup(html, "html.parser")
    # 定位所有微博卡片容器(通过CSS选择器,可通过浏览器开发者工具查看)
    weibo_cards = soup.select(".card-wrap")
    parsed_data = []
    
    for card in weibo_cards:
        # 过滤非微博内容卡片(如广告、推荐关注、话题卡片等)
        content_container = card.select_one(".content")
        if not content_container:
            continue
        
        # 1. 提取用户名(class="name"下的a标签文本)
        username_elem = content_container.select_one(".name a")
        username = username_elem.get_text(strip=True) if username_elem else "未知用户"
        
        # 2. 提取发布时间(class="time"的span标签文本)
        time_elem = content_container.select_one(".time")
        pub_time = time_elem.get_text(strip=True) if time_elem else "未知时间"
        
        # 3. 提取微博内容(class="txt"的div标签,去除多余空格和换行)
        content_elem = content_container.select_one(".txt")
        if content_elem:
            # 清除内容中的多余标签(如em、a等),保留纯文本
            for extra_tag in content_elem.select("em, a[target='_blank']"):
                extra_tag.extract()
            content = content_elem.get_text(strip=True, separator=" ")
        else:
            content = "无有效内容"
        
        # 4. 提取互动数据(点赞、评论、转发)
        # 互动数据容器:class="card-act"的div标签
        act_container = card.select_one(".card-act")
        if act_container:
            # 转发数(class="repost"的span标签)
            repost_elem = act_container.select_one(".repost")
            repost_num = repost_elem.get_text(strip=True) if repost_elem else "0"
            # 评论数(class="comment"的span标签)
            comment_elem = act_container.select_one(".comment")
            comment_num = comment_elem.get_text(strip=True) if comment_elem else "0"
            # 点赞数(class="like"的span标签)
            like_elem = act_container.select_one(".like")
            like_num = like_elem.get_text(strip=True) if like_elem else "0"
        else:
            repost_num = comment_num = like_num = "0"
        
        # 处理互动数据格式(将"万"转换为数字,如"1.2万"→12000)
        def format_interaction_num(num_str):
            if "万" in num_str:
                try:
                    return str(int(float(num_str.replace("万", "")) * 10000))
                except:
                    return num_str
            return num_str
        
        repost_num = format_interaction_num(repost_num)
        comment_num = format_interaction_num(comment_num)
        like_num = format_interaction_num(like_num)
        
        # 整理单条微博数据为字典
        weibo_item = {
            "用户名": username,
            "发布时间": pub_time,
            "微博内容": content,
            "转发数": repost_num,
            "评论数": comment_num,
            "点赞数": like_num
        }
        parsed_data.append(weibo_item)
    
    return parsed_data

解析逻辑关键点

  • CSS 选择器定位:通过浏览器开发者工具(F12→Elements)选中目标元素,右键→Copy→Copy selector 获取准确的 CSS 选择器。
  • 数据清洗:去除内容中的多余标签(如话题链接、@用户链接),统一互动数据格式(处理 "万" 单位),确保数据准确性。
  • 容错处理:每个元素提取时都进行非空判断,避免因部分卡片结构异常导致程序崩溃。

4. 数据保存函数实现

将解析后的多页数据整合,导出为 CSV 文件:

python

运行

python 复制代码
def save_crawled_data(all_data):
    """
    将抓取的所有数据保存为CSV文件
    :param all_data: 整合后的数据集(list of dict)
    :return: 无返回值
    """
    if not all_data:
        print("无有效数据可保存")
        return
    
    # 转换为DataFrame格式(pandas核心数据结构)
    df = pd.DataFrame(all_data)
    
    # 保存为CSV文件,encoding="utf-8-sig"支持中文正常显示
    df.to_csv(
        path_or_buf=SAVE_PATH,
        index=False,  # 不保存索引列
        encoding="utf-8-sig",
        sep=","  # 字段分隔符
    )
    
    # 输出保存结果统计信息
    print(f"\n数据保存完成!文件路径:{SAVE_PATH}")
    print(f"共抓取有效讨论:{len(all_data)} 条")
    print(f"数据字段:{list(df.columns)}")
    # 输出前5条数据预览
    print("\n数据预览:")
    print(df.head())

数据保存优势

  • 使用<font style="color:rgb(0, 0, 0);">utf-8-sig</font>编码,解决 CSV 文件中文乱码问题,兼容 Excel 和 WPS 打开。
  • 输出数据统计信息和预览,方便快速验证数据质量。

5. 主程序入口实现

整合上述函数,实现批量抓取逻辑:

python

运行

python 复制代码
def main():
    """主程序:协调请求、解析、保存流程"""
    print(f"===== 开始抓取【{KEYWORD}】相关微博讨论 =====")
    print(f"计划抓取页数:{PAGE_NUM} 页")
    print(f"数据保存路径:{SAVE_PATH}")
    print("=" * 50)
    
    # 存储所有页面的抓取数据
    total_data = []
    
    # 循环抓取指定页数
    for page in range(1, PAGE_NUM + 1):
        print(f"\n正在抓取第{page}页...")
        # 1. 请求页面
        html_content = fetch_weibo_page(page)
        if not html_content:
            print(f"第{page}页抓取跳过")
            continue
        # 2. 解析页面
        page_data = parse_weibo_content(html_content)
        # 3. 整合数据
        total_data.extend(page_data)
        print(f"第{page}页解析完成,新增 {len(page_data)} 条数据")
    
    # 4. 保存数据
    save_crawled_data(total_data)
    print("\n===== 抓取任务结束 =====")

# 程序入口(仅当直接运行该脚本时执行)
if __name__ == "__main__":
    main()

四、反爬规避与优化技巧

1. 进阶反爬策略

  • IP 代理池:若需要大量抓取(超过 50 页),可搭建 IP 代理池(推荐使用亿牛云代理),轮换 IP 地址避免被封禁。
  • 动态请求头 :随机切换 User-Agent、Referer 等字段,模拟不同用户的访问行为,可通过<font style="color:rgb(0, 0, 0);">fake-useragent</font>库自动生成随机 User-Agent。
  • 登录态维护:通过 Cookie 保持登录状态,不仅能提升爬取页数限制,还能获取更多用户互动数据,建议定期更新 Cookie。

2. 代码优化方向

  • 多线程 / 异步请求 :使用<font style="color:rgb(0, 0, 0);">threading</font>(多线程)或<font style="color:rgb(0, 0, 0);">aiohttp</font>(异步)替代单线程请求,提升抓取效率(注意控制并发数,避免给服务器造成压力)。
  • 断点续爬:将已抓取的页码和数据保存到本地(如 JSON 文件),下次运行时从上次中断的页码继续抓取,避免重复工作。
  • 数据去重 :通过微博内容哈希值(如<font style="color:rgb(0, 0, 0);">hash(content)</font>)或微博 ID 去重,避免抓取到重复内容。

3. 常见问题排查

  • 403 Forbidden:IP 被封禁,解决方案:更换网络、增加延迟、使用代理 IP、更新 Cookie。
  • 中文乱码 :检查页面编码是否正确(<font style="color:rgb(0, 0, 0);">response.encoding = response.apparent_encoding</font>),保存文件时使用<font style="color:rgb(0, 0, 0);">utf-8-sig</font>编码。
  • 解析不到数据:微博页面结构更新,需重新通过浏览器开发者工具获取最新的 CSS 选择器。

五、数据应用场景与扩展方向

1. 数据应用价值

  • 情感分析 :使用<font style="color:rgb(0, 0, 0);">jieba</font>分词和<font style="color:rgb(0, 0, 0);">snownlp</font>库对微博内容进行情感倾向判断,分析用户对《疯狂动物城》的正面 / 负面 / 中性评价占比。
  • 热度趋势:结合发布时间,分析电影相关讨论的时间分布,判断热度峰值和长尾效应。
  • 关键词提取 :通过<font style="color:rgb(0, 0, 0);">jieba.analyse</font>提取高频关键词,了解用户讨论的核心话题(如角色、剧情、台词等)。

2. 多平台扩展

本文以微博为例,可快速扩展到其他社交媒体平台:

  • 知乎 :搜索 URL:<font style="color:rgb(0, 0, 0);">https://www.zhihu.com/search?q=疯狂动物城&type=content</font>,解析时定位<font style="color:rgb(0, 0, 0);">.List-item</font>类的回答卡片。
  • B 站 :搜索 URL:<font style="color:rgb(0, 0, 0);">https://search.bilibili.com/all?keyword=疯狂动物城</font>,解析视频评论区时需处理 AJAX 请求(推荐使用<font style="color:rgb(0, 0, 0);">requests</font>模拟接口请求)。
  • 小红书 :搜索 URL:<font style="color:rgb(0, 0, 0);">https://www.xiaohongshu.com/search_result?keyword=疯狂动物城</font>,需处理登录态和动态渲染(可使用<font style="color:rgb(0, 0, 0);">Selenium</font>模拟浏览器)。

六、合规性与伦理说明

爬虫开发需严格遵守以下原则,避免法律风险和道德问题:

  1. 遵守目标网站的<font style="color:rgb(0, 0, 0);">robots.txt</font>协议(可通过<font style="color:rgb(0, 0, 0);">https://s.weibo.com/robots.txt</font>查看),不抓取禁止访问的内容。
  2. 控制抓取频率,避免给目标网站服务器造成过载压力,建议单 IP 请求频率不超过 1 次 / 秒。
  3. 抓取数据仅用于学习、研究等非商业用途,不得泄露用户隐私,不得用于非法营销等活动。
  4. 若目标网站有明确的 API 接口,优先使用官方 API 获取数据,减少对页面的直接抓取。
相关推荐
_一路向北_3 小时前
爬虫框架:Feapder使用心得
爬虫·python
皇族崛起4 小时前
【3D标注】- Unreal Engine 5.7 与 Python 交互基础
python·3d·ue5
你想知道什么?4 小时前
Python基础篇(上) 学习笔记
笔记·python·学习
曼巴UE54 小时前
UE5 C++ 动态多播
java·开发语言
steins_甲乙4 小时前
C++并发编程(3)——资源竞争下的安全栈
开发语言·c++·安全
Swizard5 小时前
速度与激情:Android Python + CameraX 零拷贝实时推理指南
android·python·ai·移动开发
一直跑5 小时前
Liunx服务器centos7离线升级内核(Liunx服务器centos7.9离线/升级系统内核)
python
leocoder5 小时前
大模型基础概念入门 + 代码实战(实现一个多轮会话机器人)
前端·人工智能·python
Buxxxxxx5 小时前
DAY 37 深入理解SHAP图
python
ada7_5 小时前
LeetCode(python)108.将有序数组转换为二叉搜索树
数据结构·python·算法·leetcode