Skip to content

6.1 自动化日报生成器

在企业日常运营中,定期生成和发送各类报告是一项常见但繁琐的工作。特别是日报这类高频次的报告,如果能够实现自动化,将大大提高工作效率。本节将介绍如何使用Python构建一个完整的自动化日报生成器,实现从数据收集、报告生成到邮件发送的全流程自动化。

需求分析

一个典型的自动化日报生成流程通常包括以下步骤:

  1. 数据收集与处理:从Excel表格中读取原始数据,进行必要的清洗和计算
  2. 报告生成:将处理后的数据生成为格式化的Word文档报告
  3. 邮件发送:将生成的报告作为附件,发送给指定收件人

技术选型

我们将使用以下Python库来实现各个环节:

  • pandas:用于Excel数据读取和处理
  • python-docx:用于生成Word文档报告
  • matplotlib/seaborn:用于生成数据可视化图表
  • smtplib/email:用于发送邮件

代码实现

第一步:读取和处理Excel数据

python
import pandas as pd
import numpy as np
from datetime import datetime, timedelta

def read_and_process_data(excel_path):
    """读取并处理Excel数据"""
    # 读取Excel文件
    df = pd.read_excel(excel_path)
    
    # 数据清洗
    df = df.dropna(subset=['日期', '销售额'])  # 删除关键字段为空的行
    
    # 数据转换
    df['日期'] = pd.to_datetime(df['日期'])
    df['销售额'] = df['销售额'].astype(float)
    
    # 按日期筛选最近一天的数据
    latest_date = df['日期'].max()
    today_data = df[df['日期'] == latest_date]
    
    # 计算关键指标
    total_sales = today_data['销售额'].sum()
    avg_sales = today_data['销售额'].mean()
    max_sales = today_data['销售额'].max()
    max_sales_product = today_data.loc[today_data['销售额'].idxmax()]['产品名称']
    
    # 按产品类别统计
    category_sales = today_data.groupby('产品类别')['销售额'].sum().reset_index()
    
    # 计算环比数据(与前一天相比)
    yesterday = latest_date - timedelta(days=1)
    yesterday_data = df[df['日期'] == yesterday]
    yesterday_sales = yesterday_data['销售额'].sum() if not yesterday_data.empty else 0
    sales_growth = ((total_sales - yesterday_sales) / yesterday_sales * 100) if yesterday_sales > 0 else 0
    
    # 返回处理后的数据
    return {
        'report_date': latest_date.strftime('%Y年%m月%d日'),
        'total_sales': total_sales,
        'avg_sales': avg_sales,
        'max_sales': max_sales,
        'max_sales_product': max_sales_product,
        'sales_growth': sales_growth,
        'category_sales': category_sales,
        'daily_data': today_data
    }

第二步:生成数据可视化图表

python
import matplotlib.pyplot as plt
import seaborn as sns
import os

def generate_charts(data, output_folder):
    """生成数据可视化图表"""
    # 确保输出文件夹存在
    os.makedirs(output_folder, exist_ok=True)
    
    # 设置中文字体
    plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
    plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号
    
    # 图1:产品类别销售额饼图
    plt.figure(figsize=(8, 6))
    plt.pie(data['category_sales']['销售额'], 
            labels=data['category_sales']['产品类别'],
            autopct='%1.1f%%', startangle=90)
    plt.title(f"{data['report_date']}销售额类别分布")
    plt.tight_layout()
    pie_chart_path = os.path.join(output_folder, 'category_sales_pie.png')
    plt.savefig(pie_chart_path)
    plt.close()
    
    # 图2:产品销售额条形图(Top 5)
    top_products = data['daily_data'].nlargest(5, '销售额')
    plt.figure(figsize=(10, 6))
    sns.barplot(x='销售额', y='产品名称', data=top_products)
    plt.title(f"{data['report_date']}销售额Top5产品")
    plt.tight_layout()
    bar_chart_path = os.path.join(output_folder, 'top_products_bar.png')
    plt.savefig(bar_chart_path)
    plt.close()
    
    return {
        'pie_chart_path': pie_chart_path,
        'bar_chart_path': bar_chart_path
    }

第三步:生成Word报告

python
from docx import Document
from docx.shared import Inches, Pt, RGBColor
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.enum.style import WD_STYLE_TYPE

def generate_report(data, charts, output_path):
    """生成Word格式的日报"""
    doc = Document()
    
    # 设置文档样式
    styles = doc.styles
    style = styles.add_style('CustomHeading1', WD_STYLE_TYPE.PARAGRAPH)
    style.font.size = Pt(18)
    style.font.bold = True
    style.font.color.rgb = RGBColor(0, 0, 128)  # 深蓝色
    
    # 添加标题
    title = doc.add_paragraph(f"销售日报 - {data['report_date']}")
    title.alignment = WD_ALIGN_PARAGRAPH.CENTER
    title.style = 'CustomHeading1'
    
    # 添加摘要部分
    doc.add_heading('一、销售概况', level=1)
    summary = doc.add_paragraph()
    summary.add_run(f"报告日期:{data['report_date']}\n").bold = True
    summary.add_run(f"总销售额:{data['total_sales']:.2f}\n")
    summary.add_run(f"平均单品销售额:{data['avg_sales']:.2f}\n")
    summary.add_run(f"销售额最高产品:{data['max_sales_product']} ({data['max_sales']:.2f} 元)\n")
    
    # 添加环比分析
    doc.add_heading('二、环比分析', level=1)
    growth = doc.add_paragraph()
    if data['sales_growth'] > 0:
        growth.add_run(f"销售额较前日增长:{data['sales_growth']:.2f}%\n").bold = True
    else:
        growth.add_run(f"销售额较前日下降:{abs(data['sales_growth']):.2f}%\n").bold = True
    
    # 添加图表
    doc.add_heading('三、销售分布', level=1)
    doc.add_paragraph('3.1 产品类别销售分布')
    doc.add_picture(charts['pie_chart_path'], width=Inches(5))
    
    doc.add_paragraph('3.2 销售额Top5产品')
    doc.add_picture(charts['bar_chart_path'], width=Inches(6))
    
    # 添加详细数据表格
    doc.add_heading('四、销售明细', level=1)
    table = doc.add_table(rows=1, cols=4)
    table.style = 'Table Grid'
    
    # 设置表头
    header_cells = table.rows[0].cells
    header_cells[0].text = '产品名称'
    header_cells[1].text = '产品类别'
    header_cells[2].text = '销售数量'
    header_cells[3].text = '销售额'
    
    # 添加数据行
    for _, row in data['daily_data'].iterrows():
        cells = table.add_row().cells
        cells[0].text = row['产品名称']
        cells[1].text = row['产品类别']
        cells[2].text = str(row['销售数量'])
        cells[3].text = f"{row['销售额']:.2f}"
    
    # 保存文档
    doc.save(output_path)
    return output_path

第四步:发送邮件

python
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication
import os

def send_email(report_path, recipients, sender_email, sender_password, smtp_server, smtp_port):
    """发送邮件"""
    # 创建邮件对象
    msg = MIMEMultipart()
    msg['From'] = sender_email
    msg['To'] = ', '.join(recipients)
    
    # 获取当前日期作为邮件主题
    report_date = os.path.basename(report_path).split('.')[0].split('_')[-1]
    msg['Subject'] = f"销售日报 - {report_date}"
    
    # 邮件正文
    body = f"""
    尊敬的团队成员:
    
    附件是{report_date}的销售日报,请查收。
    
    主要内容包括:
    1. 销售概况
    2. 环比分析
    3. 销售分布图表
    4. 销售明细数据
    
    如有疑问,请回复此邮件。
    
    此致
    销售分析团队
    """
    msg.attach(MIMEText(body, 'plain'))
    
    # 添加附件
    with open(report_path, 'rb') as file:
        attachment = MIMEApplication(file.read(), _subtype="docx")
        attachment.add_header('Content-Disposition', 'attachment', filename=os.path.basename(report_path))
        msg.attach(attachment)
    
    # 发送邮件
    try:
        server = smtplib.SMTP(smtp_server, smtp_port)
        server.starttls()  # 启用TLS加密
        server.login(sender_email, sender_password)
        server.send_message(msg)
        server.quit()
        print(f"邮件已成功发送至{len(recipients)}位收件人")
        return True
    except Exception as e:
        print(f"发送邮件时出错: {e}")
        return False

第五步:整合所有功能

python
def generate_daily_report(excel_path, output_folder, report_filename, email_config=None):
    """生成并发送日报的主函数"""
    # 确保输出文件夹存在
    os.makedirs(output_folder, exist_ok=True)
    
    # 步骤1:读取和处理数据
    print("正在读取和处理Excel数据...")
    data = read_and_process_data(excel_path)
    
    # 步骤2:生成图表
    print("正在生成数据可视化图表...")
    charts_folder = os.path.join(output_folder, 'charts')
    charts = generate_charts(data, charts_folder)
    
    # 步骤3:生成Word报告
    print("正在生成Word报告...")
    report_path = os.path.join(output_folder, report_filename)
    generate_report(data, charts, report_path)
    print(f"报告已生成: {report_path}")
    
    # 步骤4:发送邮件(如果提供了邮件配置)
    if email_config:
        print("正在发送邮件...")
        send_email(
            report_path, 
            email_config['recipients'],
            email_config['sender_email'],
            email_config['sender_password'],
            email_config['smtp_server'],
            email_config['smtp_port']
        )
    
    return report_path

# 使用示例
if __name__ == "__main__":
    # 配置参数
    excel_path = "sales_data.xlsx"
    output_folder = "reports"
    report_date = datetime.now().strftime("%Y%m%d")
    report_filename = f"销售日报_{report_date}.docx"
    
    # 邮件配置
    email_config = {
        'recipients': ['team1@example.com', 'team2@example.com'],
        'sender_email': 'reports@company.com',
        'sender_password': 'your_password',  # 建议使用环境变量存储密码
        'smtp_server': 'smtp.company.com',
        'smtp_port': 587
    }
    
    # 生成并发送日报
    generate_daily_report(excel_path, output_folder, report_filename, email_config)

实际应用场景

1. 销售团队日报

销售团队可以使用此工具自动生成每日销售报告,包括销售额、订单数、客户转化率等关键指标,帮助团队及时了解销售情况并做出决策。

2. 运营数据日报

网站或APP运营团队可以自动生成包含用户活跃度、新增用户、页面访问量等数据的日报,监控产品运营状况。

3. 财务日报

财务部门可以自动生成包含收入、支出、利润等财务指标的日报,帮助管理层掌握公司财务状况。

4. 生产线监控报告

制造业可以自动生成包含生产效率、质量指标、设备运行状态等数据的日报,及时发现并解决生产问题。

进阶优化

1. 定时任务调度

使用schedule库或系统的cron任务实现定时自动执行:

python
import schedule
import time

def job():
    print("开始生成每日报告...")
    generate_daily_report(excel_path, output_folder, report_filename, email_config)
    print("报告生成完成!")

# 设置每天早上9点执行
schedule.every().day.at("09:00").do(job)

while True:
    schedule.run_pending()
    time.sleep(60)  # 每分钟检查一次是否有待执行的任务

2. 数据源扩展

除了从Excel读取数据,还可以扩展为从数据库、API或其他数据源获取数据:

python
def get_data_from_database():
    """从数据库获取销售数据"""
    import sqlite3
    conn = sqlite3.connect('sales.db')
    query = """SELECT date, product_name, category, quantity, amount 
              FROM sales WHERE date = date('now', '-1 day')"""
    df = pd.read_sql_query(query, conn)
    conn.close()
    return df

def get_data_from_api():
    """从API获取销售数据"""
    import requests
    response = requests.get('https://api.company.com/sales/daily',
                          headers={'Authorization': 'Bearer YOUR_API_KEY'})
    data = response.json()
    df = pd.DataFrame(data['sales'])
    return df

3. 报告模板化

使用Word模板进一步简化报告生成过程:

python
from docxtpl import DocxTemplate

def generate_report_from_template(data, charts, template_path, output_path):
    """使用模板生成Word报告"""
    doc = DocxTemplate(template_path)
    
    # 准备模板变量
    context = {
        'report_date': data['report_date'],
        'total_sales': f"{data['total_sales']:.2f}",
        'avg_sales': f"{data['avg_sales']:.2f}",
        'max_sales_product': data['max_sales_product'],
        'max_sales': f"{data['max_sales']:.2f}",
        'sales_growth': f"{data['sales_growth']:.2f}"
    }
    
    # 渲染模板并保存
    doc.render(context)
    doc.save(output_path)
    
    # 在保存后添加图片(需要使用python-docx)
    doc_with_images = Document(output_path)
    for paragraph in doc_with_images.paragraphs:
        if '{{pie_chart}}' in paragraph.text:
            paragraph.text = ''
            run = paragraph.add_run()
            run.add_picture(charts['pie_chart_path'], width=Inches(5))
        elif '{{bar_chart}}' in paragraph.text:
            paragraph.text = ''
            run = paragraph.add_run()
            run.add_picture(charts['bar_chart_path'], width=Inches(6))
    
    doc_with_images.save(output_path)
    return output_path

4. 多格式报告支持

除了Word格式,还可以支持生成PDF、HTML或Markdown格式的报告:

python
def convert_word_to_pdf(word_path, pdf_path):
    """将Word文档转换为PDF"""
    from docx2pdf import convert
    convert(word_path, pdf_path)
    return pdf_path

def generate_html_report(data, charts):
    """生成HTML格式的报告"""
    import jinja2
    
    # 加载HTML模板
    template_loader = jinja2.FileSystemLoader(searchpath="./templates")
    template_env = jinja2.Environment(loader=template_loader)
    template = template_env.get_template("report_template.html")
    
    # 准备模板变量
    context = {
        'report_date': data['report_date'],
        'total_sales': f"{data['total_sales']:.2f}",
        'avg_sales': f"{data['avg_sales']:.2f}",
        'max_sales_product': data['max_sales_product'],
        'max_sales': f"{data['max_sales']:.2f}",
        'sales_growth': f"{data['sales_growth']:.2f}",
        'pie_chart': charts['pie_chart_path'],
        'bar_chart': charts['bar_chart_path']
    }
    
    # 渲染HTML
    html_content = template.render(context)
    
    # 保存HTML文件
    html_path = f"reports/销售日报_{data['report_date']}.html"
    with open(html_path, 'w', encoding='utf-8') as f:
        f.write(html_content)
    
    return html_path

小结

通过本节的学习,我们实现了一个功能完整的自动化日报生成器,它能够:

  1. 从Excel表格中读取和处理数据
  2. 生成数据可视化图表
  3. 创建格式化的Word报告
  4. 通过邮件发送报告
  5. 支持定时执行和多种数据源

这个自动化工具可以为企业节省大量人力和时间成本,提高工作效率,同时保证报告的一致性和准确性。通过进一步的扩展和定制,它可以适应各种不同的业务场景和需求。

在实际应用中,你可以根据自己的需求调整报告的内容和格式,添加更多的数据分析和可视化,或者集成到更大的自动化工作流程中。