Python爬虫实战㉕|数据分析报告自动化,一键生成PDF报告
·
author: 专注Python实战,分享爬虫与数据分析干货
title: Python爬虫实战㉕|数据分析报告自动化,一键生成PDF报告
update: 2026-04-26
tags: Python,报告自动化,PDF,数据分析,matplotlib,报表,jinja2
作者:专注Python实战,分享爬虫与数据分析干货
更新时间:2026年4月
适合人群:已掌握爬虫+Pandas+可视化,想做报告自动化的开发者
前言:每周做报表?让Python替你干!
老板每周要看数据报告:销量趋势、品类占比、异常数据。手动做PPT/Excel太累。
Python自动分析 + 自动画图 + 自动生成报告 = 解放双手。
一、报告自动化流程
原始数据(CSV/DB)
↓
Pandas数据清洗
↓
Pandas统计分析
↓
Matplotlib/Seaborn画图
↓
生成HTML/PDF报告
二、数据准备
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from datetime import datetime, timedelta
# 配置
plt.rcParams["font.sans-serif"] = ["SimHei"]
plt.rcParams["axes.unicode_minus"] = False
sns.set_theme(style="whitegrid", font="SimHei")
# 模拟数据
np.random.seed(42)
dates = pd.date_range("2026-01-01", "2026-03-31", freq="D")
df = pd.DataFrame({
"日期": dates,
"品类": np.random.choice(["手机", "电脑", "耳机", "键盘", "显示器"], len(dates)),
"城市": np.random.choice(["北京", "上海", "广州", "深圳"], len(dates)),
"销量": np.random.randint(10, 200, len(dates)),
"金额": np.random.uniform(100, 8000, len(dates)).round(2),
})
df["月份"] = df["日期"].dt.to_period("M")
df.to_csv("report_data.csv", index=False, encoding="utf-8-sig")
三、自动分析
class DataAnalyzer:
"""数据分析器"""
def __init__(self, df):
self.df = df
self.stats = {}
def run_all(self):
"""运行所有分析"""
self.basic_stats()
self.trend_analysis()
self.category_analysis()
self.city_analysis()
self.anomaly_detection()
return self.stats
def basic_stats(self):
"""基础统计"""
self.stats["总销量"] = self.df["销量"].sum()
self.stats["总金额"] = self.df["金额"].sum()
self.stats["平均客单价"] = self.df["金额"].mean()
self.stats["数据天数"] = self.df["日期"].nunique()
self.stats["品类数"] = self.df["品类"].nunique()
def trend_analysis(self):
"""趋势分析"""
monthly = self.df.groupby("月份").agg(
总销量=("销量", "sum"),
总金额=("金额", "sum"),
)
self.stats["月度趋势"] = monthly
def category_analysis(self):
"""品类分析"""
cat = self.df.groupby("品类").agg(
总销量=("销量", "sum"),
总金额=("金额", "sum"),
平均单价=("金额", "mean"),
).sort_values("总金额", ascending=False)
self.stats["品类统计"] = cat
def city_analysis(self):
"""城市分析"""
city = self.df.groupby("城市").agg(
总销量=("销量", "sum"),
总金额=("金额", "sum"),
).sort_values("总金额", ascending=False)
self.stats["城市统计"] = city
def anomaly_detection(self):
"""异常检测"""
Q1 = self.df["金额"].quantile(0.25)
Q3 = self.df["金额"].quantile(0.75)
IQR = Q3 - Q1
lower = Q1 - 1.5 * IQR
upper = Q3 + 1.5 * IQR
anomalies = self.df[(self.df["金额"] < lower) | (self.df["金额"] > upper)]
self.stats["异常数据"] = anomalies
self.stats["异常数量"] = len(anomalies)
四、自动画图
class ChartGenerator:
"""图表生成器"""
def __init__(self, df, output_dir="charts"):
self.df = df
self.output_dir = output_dir
import os
os.makedirs(output_dir, exist_ok=True)
def generate_all(self):
"""生成所有图表"""
self.trend_chart()
self.category_chart()
self.city_chart()
self.distribution_chart()
def trend_chart(self):
monthly = self.df.groupby(self.df["日期"].dt.to_period("M")).agg(
总销量=("销量", "sum"), 总金额=("金额", "sum")
)
monthly.index = monthly.index.astype(str)
fig, ax1 = plt.subplots(figsize=(10, 5))
ax1.bar(monthly.index, monthly["总销量"], color="#4472C4", alpha=0.7, label="销量")
ax1.set_ylabel("销量", color="#4472C4")
ax2 = ax1.twinx()
ax2.plot(monthly.index, monthly["总金额"], "ro-", label="金额")
ax2.set_ylabel("金额", color="red")
plt.title("月度销售趋势")
plt.tight_layout()
plt.savefig(f"{self.output_dir}/trend.png", dpi=150, bbox_inches="tight")
plt.close()
def category_chart(self):
cat = self.df.groupby("品类")["金额"].sum().sort_values(ascending=False)
plt.figure(figsize=(8, 5))
plt.pie(cat.values, labels=cat.index, autopct="%1.1f%%",
colors=sns.color_palette("Set2"))
plt.title("品类销售占比")
plt.tight_layout()
plt.savefig(f"{self.output_dir}/category.png", dpi=150, bbox_inches="tight")
plt.close()
def city_chart(self):
city = self.df.groupby("城市")["销量"].sum().sort_values()
plt.figure(figsize=(8, 5))
city.plot(kind="barh", color="#4472C4")
plt.title("各城市销量")
plt.tight_layout()
plt.savefig(f"{self.output_dir}/city.png", dpi=150, bbox_inches="tight")
plt.close()
def distribution_chart(self):
plt.figure(figsize=(8, 5))
sns.histplot(self.df["金额"], kde=True, color="#4472C4")
plt.title("金额分布")
plt.tight_layout()
plt.savefig(f"{self.output_dir}/distribution.png", dpi=150, bbox_inches="tight")
plt.close()
五、生成HTML报告
def generate_html_report(stats, charts_dir="charts", output="report.html"):
"""生成HTML报告"""
html = f"""
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>数据分析报告</title>
<style>
body {{ font-family: "Microsoft YaHei", sans-serif; max-width: 900px; margin: 0 auto; padding: 20px; }}
h1 {{ color: #2c3e50; border-bottom: 3px solid #3498db; padding-bottom: 10px; }}
h2 {{ color: #34495e; margin-top: 30px; }}
.stat-grid {{ display: grid; grid-template-columns: repeat(3, 1fr); gap: 15px; }}
.stat-card {{ background: #f8f9fa; border-radius: 8px; padding: 15px; text-align: center; }}
.stat-value {{ font-size: 24px; font-weight: bold; color: #2c3e50; }}
.stat-label {{ font-size: 14px; color: #7f8c8d; }}
img {{ max-width: 100%; border-radius: 8px; box-shadow: 0 2px 8px rgba(0,0,0,0.1); margin: 10px 0; }}
table {{ border-collapse: collapse; width: 100%; margin: 10px 0; }}
th, td {{ border: 1px solid #ddd; padding: 8px 12px; text-align: left; }}
th {{ background: #3498db; color: white; }}
tr:nth-child(even) {{ background: #f2f2f2; }}
</style>
</head>
<body>
<h1>📊 数据分析报告</h1>
<p>生成时间:{datetime.now().strftime("%Y-%m-%d %H:%M")}</p>
<h2>📌 核心指标</h2>
<div class="stat-grid">
<div class="stat-card">
<div class="stat-value">{stats["总销量"]:,}</div>
<div class="stat-label">总销量</div>
</div>
<div class="stat-card">
<div class="stat-value">¥{stats["总金额"]:,.0f}</div>
<div class="stat-label">总金额</div>
</div>
<div class="stat-card">
<div class="stat-value">¥{stats["平均客单价"]:,.0f}</div>
<div class="stat-label">平均客单价</div>
</div>
</div>
<h2>📈 趋势分析</h2>
<img src="{charts_dir}/trend.png" alt="趋势图">
<h2>🏷️ 品类分析</h2>
<img src="{charts_dir}/category.png" alt="品类图">
<h2>🏙️ 城市分析</h2>
<img src="{charts_dir}/city.png" alt="城市图">
<h2>📊 金额分布</h2>
<img src="{charts_dir}/distribution.png" alt="分布图">
<h2>⚠️ 异常数据</h2>
<p>检测到 <strong>{stats["异常数量"]}</strong> 条异常数据</p>
</body>
</html>
"""
with open(output, "w", encoding="utf-8") as f:
f.write(html)
print(f"报告已生成: {output}")
六、一键执行
# 完整流程
df = pd.read_csv("report_data.csv", encoding="utf-8-sig")
analyzer = DataAnalyzer(df)
stats = analyzer.run_all()
charts = ChartGenerator(df)
charts.generate_all()
generate_html_report(stats)
print("报告生成完成!")
七、知识卡
| 概念 | 说明 |
|---|---|
| DataAnalyzer | 数据分析器类 |
| ChartGenerator | 图表生成器类 |
| generate_html_report() | HTML报告生成 |
| plt.savefig() | 保存图表 |
| bbox_inches=“tight” | 去除空白边距 |
| HTML模板 | jinja2或f-string |
八、课后作业
必做题:
- 编写数据分析类,输出统计结果
- 自动生成4种图表
- 生成HTML格式报告
选做题:
- 将HTML报告转PDF
- 定时自动执行报告生成
有问题欢迎评论区留言,大家一起讨论!
标签:Python | 报告自动化 | PDF | 数据分析 | 报表 | HTML报告
更多推荐
所有评论(0)