{T}

爬取数据的分析与可视化

前面几节完成了公众号文章的抓取与存储,本节进入数据分析环节:先搭建数据分析环境,然后用 Pandas 对爬取到的文章数据进行分析,最后用 Matplotlib 将分析结果可视化展示。

一、搭建数据分析环境

数据分析最常用的环境是 Anaconda(集成了 conda 包管理与 Jupyter Notebook)和 Jupyter Notebook(交互式笔记本)。

安装 Anaconda

前往 Anaconda 官网 下载对应平台的安装包。Anaconda 自带 Python、conda、Jupyter 以及 numpy、pandas、matplotlib 等常用数据科学包,安装后即可直接使用。

💡 轻量替代:如果不想安装庞大的 Anaconda,也可以只安装 Python 后通过 pip 安装所需包:

bash
pip install jupyter pandas numpy matplotlib

使用 conda 管理虚拟环境

conda 可以为不同项目创建隔离的 Python 环境:

bash
# 查看当前所有虚拟环境
conda info -e

# 创建新环境并指定 Python 版本
conda create -n crawler python=3.14

# 激活环境
conda activate crawler
# Windows 不加 source,Mac/Linux 加 source

💡 切换到某个环境后,用 pip install 安装的包只对当前环境生效。本教程使用默认的 base 环境(Jupyter 中的 Python3),它已包含全部数据分析相关包。

启动 Jupyter Notebook

bash
jupyter notebook
# 或
jupyter lab

启动后在浏览器中新建一个 Python3 笔记本即可开始分析。以下代码均在 Jupyter Notebook 中完成。

导入数据分析基础包

在做数据分析前,约定俗成地引入 Numpy、Pandas、Matplotlib 三个工具包,并使用简称 nppdplt

python
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

# 在 Jupyter 中加这行,图像直接内联显示,无需写 plt.show()
%matplotlib inline
  • numpy:科学计算基础包,pandas 依赖它。
  • pandas:数据分析核心包。
  • matplotlib:绘图工具包。

💡 版本说明:本教程基于 Pandas 3.0+、Matplotlib 3.10+ 版本。Pandas 3.0 是重大版本更新(详见下文"Pandas 3.0 重要变化"),安装方式:pip install "pandas>=3.0" "matplotlib>=3.10"

二、Pandas 数据分析

Pandas 是 Python 数据分析的基础包,提供灵活的数据结构和向量化计算工具,使 Python 能像 R 语言一样方便地进行数据分析。Pandas 有两种核心数据结构:SeriesDataFrame

Series:一维数据结构

Series 是增强型的一维数组,由 index(索引)和 values(值)组成,值的数据类型相同。

python
# 用列表创建 Series
s = pd.Series(['a', 'b', 'c'])
# 0    a
# 1    b
# 2    c

# 手动指定索引
s = pd.Series(['a', 'b', 'c'], index=['x', 'y', 'z'])
# x    a
# y    b
# z    c

# 通过索引获取元素、切片
s['x']     # 'a'
s[:2]      # x a, y b

# 用字典创建 Series(索引到值的映射)
s2 = pd.Series({1: "a", 2: "b", 3: "c"})

DataFrame:二维数据结构

DataFrame 是增强型的二维数组,类似 Excel 表格,有行索引(index)和列索引(columns),是 Pandas 最常用的数据结构。

python
# 用相等长度的列表组成的字典创建
data = {'state': ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada'],
        'year': [2000, 2001, 2002, 2001, 2002],
        'pop': [1.5, 1.7, 3.6, 2.4, 2.9]}
df = pd.DataFrame(data)

# 用 Numpy 二维数组创建
df2 = pd.DataFrame(np.random.randn(6, 4))

# 指定行索引和列索引
dates = pd.date_range('20130101', periods=6)
df3 = pd.DataFrame(np.random.randn(6, 4), index=dates, columns=list('ABCD'))

DataFrame 由三部分组成:index(行索引)、columns(列索引)、values(数据):

python
df.columns   # 列索引
df.index     # 行索引
df.values    # 数据(numpy 数组)

DataFrame 常用操作

python
# 查看头部/尾部数据(默认前/后5行,可指定行数)
df.head(3)
df.tail()

# 按索引排序
df.sort_index(axis=1, ascending=False)      # 按列索引降序
df.sort_index(axis=0, ascending=False)      # 按行索引降序

# 按值排序
df.sort_values(by='B')                       # 按 B 列升序
df.sort_values(by=['A', 'B'], ascending=[True, False])  # 多列排序

# 选择数据
df['A']            # 选择一列,返回 Series
df[['A', 'B']]     # 选择多列,返回 DataFrame
df[0:3]            # 切片(按行)

# 高效获取:loc(按索引名)与 iloc(按位置)
df.loc["2013-01-01":"2013-01-03", ['A', 'B']]  # 按行索引切片+指定列
df.iloc[1:4, 0:2]                               # 按位置切片

# 条件过滤
df[df.A > 0]

# 聚合统计
df.sum()    # 求和
df.mean()   # 求平均值
df.max()    # 求最大值
df.min()    # 求最小值

# 分组
df.groupby('A').size()
# groupby 参数还可以是函数(如按时间列的年份分组)
df.groupby(lambda x: df.E[x].year).size()

Pandas 3.0 重要变化

💡 如果你从旧版 Pandas 迁移,请注意以下关键变化:

  1. Copy-on-Write(CoW):Pandas 3.0 默认启用写时复制机制,修改 DataFrame 的切片不再影响原始数据。df[df.A > 0]['B'] = 1 这种链式赋值将不再生效,应改用 df.loc[df.A > 0, 'B'] = 1

  2. 字符串数据类型:Pandas 3.0 默认使用专用的 StringDtype 而非 object 类型存储字符串,性能和内存使用更好。

  3. 弃用的 APIDataFrame.append() 已被移除,请使用 pd.concat()

更多 Pandas 用法可参考官方文档

三、Matplotlib 数据可视化

拿到爬取并存储的数据后,用 Pandas 结合 Matplotlib 进行可视化展示,能直观看出数据规律。下面以公众号文章数据为例。

加载数据

数据可以来自 MongoDB(上一节存储的)或 CSV 文件:

python
display_columns = ["title", "read_num", "like_num", "comment_num", "reward_num", "p_date"]

# 从 MongoDB 导入
import pymongo
from pymongo import MongoClient
c = MongoClient()
cursor = c.weixin['post'].find()
df = pd.DataFrame(list(cursor))
df = df.drop("_id", axis=1)
df = df.reindex(columns=display_columns)
df.p_date = pd.to_datetime(df['p_date'])

# 从 CSV 导入(示例数据)
df = pd.read_csv("post.csv")
df = df.reindex(columns=display_columns)
df.p_date = pd.to_datetime(df['p_date'])

文章与阅读数分析

加载数据后先看总体概览:公众号共发了若干篇文章,平均阅读量、标准差能反映阅读量波动情况。阅读量波动大通常是因为公众号初期订阅读者少、后期读者增多,导致阅读量差异明显。

获取阅读量最高的 10 篇文章:

python
top_read_num_10 = df.sort_values(by=['read_num'], ascending=False)[:10]
top_read_num_10 = top_read_num_10[display_columns]
top_read_num_10.reset_index(drop=True)

历史文章阅读量变化曲线:

python
ax = df.plot(y='read_num', x='p_date', title="文章阅读量趋势", figsize=(9, 6))
ax.set_ylabel("阅读量")
ax.set_xlabel("")
ax.legend().set_visible(False)

按年份统计文章数(柱状图):

python
# year_df 为按年份 groupby 统计的文章数
ax = year_df.plot(x='p_date', y='total', kind='bar', figsize=(9, 6), fontsize=15)
ax.set_ylabel("文章数")
ax.set_xlabel("")
ax.legend().set_visible(False)
# 柱状图上显示数字
for p in ax.patches:
    ax.annotate(str(p.get_height()), xy=(p.get_x(), p.get_height()))

文章与赞赏分析

获取赞赏数最高的 10 篇文章:

python
top_reward_num = df.sort_values(by=['reward_num'], ascending=False)[:10]
top_reward_num = top_reward_num[display_columns]
top_reward_num.reset_index(drop=True)

横向条形图展示赞赏数:

python
ax = top_reward_num.plot(x='title', y='reward_num', kind='barh',
                         figsize=(9, 6), fontsize=14)
ax.set_ylabel("")
ax.set_xlabel("赞赏数")
ax.legend().set_visible(False)
# kind 用 "barh" 表示横向条形图

文章与点赞分析

用散点图观察点赞数与阅读数的关系:

python
# 散点图
ax = df.plot(kind="scatter", y='like_num', x='read_num', s=10, figsize=(9, 6), fontsize=15)
ax.set_xlabel("阅读量")
ax.set_ylabel("点赞数")

# 添加线性拟合线
z = np.polyfit(df.read_num, df.like_num, 1)
p = np.poly1d(z)
plt.plot(df.read_num, p(df.read_num), "r--")

可以看出点赞数大部分集中在某个区间,且与阅读数存在线性正相关:阅读量越高,点赞数越高。如果某篇文章阅读量很高但点赞数很低,则可能是标题党或资讯类文章。

标题关键字词云

最后,基于文章标题生成词云,观察标题常用的关键字。需要用到结巴分词(jieba)和词云(wordcloud)两个包:

bash
pip install jieba wordcloud
python
from wordcloud import WordCloud
import jieba

words = []
for i in df.title:
    seg_list = jieba.cut(i, cut_all=False)
    words.append(" ".join(seg_list))

# 需要指定中文字体路径,否则 wordcloud 无法处理中文
# macOS: /System/Library/Fonts/PingFang.ttc
# Windows: C:/Windows/Fonts/simhei.ttf
# Linux: /usr/share/fonts/truetype/droid/DroidSansFallbackFull.ttf
font_path = '/System/Library/Fonts/PingFang.ttc'  # macOS

wordcloud = WordCloud(
    font_path=font_path,
    background_color="white",
    max_words=80,
).generate(" ".join(words))

plt.figure(figsize=(9, 6))
plt.imshow(wordcloud, interpolation="bilinear")
plt.axis("off")
plt.show()

把所有文章的标题用 jieba 分词后加入 words 列表,传递给 WordCloud 组件。max_words 指定最多显示的词语数量。

小结

本节完成了从环境搭建到数据分析可视化的完整流程:

  1. 环境搭建:安装 Anaconda、管理 conda 虚拟环境、启动 Jupyter Notebook。
  2. Pandas 分析:掌握 Series/DataFrame、排序、选择、聚合、分组等核心操作。
  3. Matplotlib 可视化:通过折线图、柱状图、散点图、词云展示阅读数、赞赏数、点赞数、标题关键字等维度的分析结果。

通过这样的分析,可以发现数据背后的规律(如哪些类型文章阅读量高、阅读量与点赞数的关系等),为后续的运营决策提供依据。

版本差异(爬虫技术栈 → 当前版本)

本文编写时当前稳定版
requests2.28/2.312.32.x
Scrapy1.x/2.02.11.x(API 稳定)
httpx0.240.28.x
Playwright1.3x1.6x(Python 版)
lxml/BeautifulSoup旧版保持稳定
Python3.8-3.123.14(推荐)

本文讲解的爬虫原理(HTTP、解析、反爬、存储)与核心 API 在最新版本中成立;注意 Python 3.9 及以下已 EOL,新项目使用 3.13/3.14。