Python根据EXCEL自动生成固定格式WORD报告

根据客户需求,为节省日常工作量,将平常需要从EXCEL选择、拷贝、粘贴数据到WORD文档中的工作,通过Python程序自动进行EXCEL数据采集、数据分析、数据计算、智能文字拼接工作。

一、新建了一个DataToExcel.py 

  此文件主要通过与excel进行交互,获取excel中的数据,并对数据进行分析和计算,返回word文档中所需的数据信息。

#!/usr/bin/env python3

#-*- coding:utf-8 -*-

#author:BAGGIO

from openpyxl import load_workbook

from openpyxl import Workbook#导入excel包

from docx import Document#导入Docx包

from docx.shared import Cm,Inches,Pt#导入单位换算函数

from docx.oxml.ns import qn#docx中文字体模块

from docx.enum.text import WD_ALIGN_PARAGRAPH#导入对齐选项

from openpyxl.cell import MergedCell

import time#导入时间

import datetime

import os

引用了以上工具包

在获取excel文件时,由于文件名中有需要拼接的字符串,文件名是由固定名称+每周跨度日期组成,如销售量周报0528-0603.xlsx,前面的“销售周报”为固定文字,后面的“0528-0603”是根据用户所需要生成的报告周期而定,如果用户在屏幕输入日期周则优先拼接输入的日期周,如果用户不输入,则默认取当前日期的 上周日到本周六的日期(因为周报是每周日下午需要完成生成),故先做了一个去日期的函数如下:

#region 获取上周周末日期信息

def get_last_weekdate(date=None):

    if date:

        today = datetime.datetime.strptime(str(date), '%Y-%m-%d')

    else:

        today = datetime.datetime.today()

    #获取上周日日期

    end_time = today - datetime.timedelta(days=today.isoweekday())

    #转为0528格式

    str_endtime = end_time.strftime("%m")+end_time.strftime("%d")

    #获取本周六的日期

    start_time = end_time + datetime.timedelta(days=6)

    str_starttime = '-'+start_time.strftime("%m")+start_time.strftime("%d")

    return  str_endtime + str_starttime

#endregion

然后初始化文件名,并根据相对路径获取到excel文件   

 str_name = input("请输入需要生成周报的日期(如0528-0603):")

    excelname = ''

   #判断用户是否输入日期周,输入则直接采用,未输入则取上周日到本周六日期

    if str_name == '' or len(str_name.strip()) ==0:

        excelname = f'销售量周报' + get_last_weekdate() + '.xlsx'

    else:

        excelname = f'销售量周报' + str_name + '.xlsx'

    LoadPath = excelname  #加载excel路径(这里为相对路径,excel表与该程序在同一文件夹下就能识别,所以只用excel文件名即可)

    #excel表格初始化

    book=load_workbook(LoadPath, data_only=True)#加载已有Excel文档

这里的data_only=True对于有计算公式的excel非常重要,如果excel的sheet页是有计算公式的,那么必须加上data_only=True,否则我们取到单元格里面的值将会是公式本身,而不是值。

单个数据取值赋值

sheet_current_week_result=book['本周结果']#加载需要的工作簿(这里为excel表中的sheet工作簿)

#日均销售量赋值
        str_day_esales = str(round(float(sheet_current_week_result['C6'].internal_value)/7,2))

一组数据取值赋值,在C列从16行至35行 循环取此列中的值

gyindex = 16
        while gyindex < 36:
            #工业本周销售量量数组
            strindex = str(gyindex)
            str_gy_week_sales.append(round(float(sheet_current_week_result['C'+strindex].internal_value),2))
           
            gyindex += 1

也可以将列定义,然后循环取一行里面每列的数据

last_weeklist = ['k','L','M','N','O','P','Q']

while user_index <= maxrows:
            if sheet_user_result['C' + str(user_index)].internal_value == '1.膨化食品':
                cell = sheet_user_result['B' + str(user_index)]
                lastvalue = 0.00
                currentvalue = 0.00
                #判断是否为合并单元格
                if isinstance(cell, MergedCell):
                    cell = sheet_user_result['B' + str(user_index-1)]
                    
                #if user_index == 392 or user_index == 96:
                #    cell = sheet_user_result['B' + str(user_index-1)]
                user_list.append(cell.internal_value)
                for lastweek in last_weeklist:
                    lastvalue += round(float(sheet_user_result[lastweek + str(user_index)].internal_value),4)

代码中有一句非常关键的判断 if isinstance(cell, MergedCell):,这个就是判断当前单元格是否为合并单元格,因为很多计算类型的excel都有一些合并单元格的情形,如果直接取这个被合并的单元格,除非它是合并单元格中的第一个,否则其他所有被合并的单元格里面都没有值,比如一个大类A,下面有5中类a,b,c,d,e,当我们要取中类对应的大类名称,除了中类a能取到对应的大类A名称,其他b,c,d,e都只能取到空值,所以我们需要判断当前单元格是否为合并单元格,如果是则取上一行的单元格里面的值,当然这种只适合两个单元格合并的时候,如果出现多个单元格合并,就需要循环判断上一行是否为合并单元格,直到取到不是合并单元格的那个,然后获取到里面的值。

获取到excel里面的数据后,我们同样的方式打开相对路径下的word或者新建一个word文档,然后将对应的数据填充到word文档中

 #保存文件名更新:按获取的日期进行命名
    str_wordname = ''
    if DataToExcel.str_name == '' or len(DataToExcel.str_name.strip()) ==0:
        str_wordname = f'销售量周报' + DataToExcel.get_last_weekdate() + '.docx'
    else:
        str_wordname = f'销售量周报' + DataToExcel.str_name + '.docx'

    WordSavePath=(str_wordname)
    Word=Document()    #创建空Word

然后定义文档标题,以及添加相关内容

 #全局设置字体
    #Word.styles['Normal'].font.name=u'宋体'
    #Word.styles['Normal']._element.rPr.rFonts.set(qn('w:eastAsia'), u'宋体')

    #设置页面布局为A4纸张
    section=Word.sections[0]
    section.page_width = Cm(21) # 设置A4纸的宽度
    section.page_height = Cm(29.7) # 设置A4纸的高度
    section.left_margin = Cm(2.8) #设置左页边距
    section.right_margin = Cm(2.8) #设置右页边距

    Word.add_picture(open('title1.png', mode='rb'),width=Inches(2.83), height=Inches(0.84))

    #圖片格式
    str0=Word.add_paragraph(style=None) #增加一个段落
    str_run0 = str0.add_run(' ') #增加文字块
    str_run0.font.size= Pt(60)   #字体大小
    str_run0.font.name = "华文行楷"
    str_run0._element.rPr.rFonts.set(qn('w:eastAsia'), '华文行楷')  # 设置中文是华文行楷

    #首段 標題
    str1=Word.add_paragraph(style=None) #增加一个段落
    str1_run=str1.add_run('销售量周报') #增加文字块

    str1_run.afterLines = Pt(1)  # 段前1行
    str1_run.beforeLines = Pt(1) # 段后1行
    str1.paragraph_format.line_spacing_rule = WD_LINE_SPACING.EXACTLY  # 行距固定值
    str1.paragraph_format.line_spacing = Pt(58)  # 行间距,固定值56磅

    str1.alignment = WD_ALIGN_PARAGRAPH.CENTER#居中
    #str1_run.bold=True          #加粗
    str1_run.font.size= Pt(59)   #字体大小
    str1_run.font.color.rgb = RGBColor(255,0,0)  # 字体颜色
    str1_run.font.name = "华文行楷"
    str1_run._element.rPr.rFonts.set(qn('w:eastAsia'), '华文行楷')  # 设置中文是华文行楷
    
    strspace0=Word.add_paragraph(style=None) #增加一个段落
    strspace0 = strspace0.add_run(' ') #增加文字块
    strspace0.font.size= Pt(10)   #字体大小
    strspace0.font.name = "华文行楷"
    strspace0._element.rPr.rFonts.set(qn('w:eastAsia'), '华文行楷')  # 设置中文是华文行楷

如果文档中有许多的文字格式不同,这个就需要不断设置每一段文件的格式,虽然比较繁琐,但是非常灵活实用,只需要在一个段落里面添加不同的文字句,然后设置文字句的格式即可。

当然我们也可以在word中添加表格,并将excel里面的数据填充到表格当中

#region 标题表格
    #添加标题表格 一行两列
    table = Word.add_table(rows=1, cols=2,style=None)
    table.style.font.size = Pt(16)
    table.style.font.color.rgb = RGBColor(255,0,0)  # 字体颜色
    set_cell_border(
        table.cell(0,0),
        top={},
        bottom={"sz": 20, "val": "single", "color": "#FF0000", "space": "0"},
        left={},
        right={},
        insideH={},
        end={}
    )
    set_cell_border(
        table.cell(0,1),
        top={},
        bottom={"sz": 20, "val": "single", "color": "#FF0000", "space": "0"},
        left={},
        right={},
        insideH={},
        end={}
    )

    #设置行高为1.2厘米
    table.rows[0].height = Cm(1.2)
    table.cell(0,0).width = Cm(8.92)
    table.cell(0,1).width = Cm(7.14)

我们也可以通过对excel表格中的数值进行判断,从而根据数值的变化使用不同的文字拼接,使得word报告更加实用确切:

#环比
    str_zw4 = '环比'
    str_zw4_desc = ''

    if DataToExcel.str_day_esales_ratio < 0:
        str_zw4_desc = '下降'
    else:
        str_zw4_desc = '增长'

    str_zw4 = str_zw4 + str_zw4_desc + str(abs(DataToExcel.str_day_esales_ratio))+'%,'
    str_zw4_run=str_zw2.add_run(str_zw4) #增加文字块
    str_zw4_run.font.size= Pt(16)   #字体大小
    str_zw4_run.font.name = "方正仿宋_GBK"
    str_zw4_run._element.rPr.rFonts.set(qn('w:eastAsia'), '方正仿宋_GBK')  # 设置中文是华文行楷

    #增速
    str_zw5 = '增速较上周'
    str_zw5_desc = ''

    if DataToExcel.str_day_esales_increase < 0:
        str_zw5_desc = '下降'
    else:
        str_zw5_desc = '增长'

    str_zw5 = str_zw5 + str_zw5_desc + str(abs(DataToExcel.str_day_esales_increase))+'个百分点。'
    str_zw5_run=str_zw2.add_run(str_zw5) #增加文字块
    str_zw5_run.bold=True          #加粗
    str_zw5_run.font.size= Pt(16)   #字体大小
    str_zw5_run.font.name = "方正仿宋_GBK"
    str_zw5_run._element.rPr.rFonts.set(qn('w:eastAsia'), '方正仿宋_GBK')  # 设置中文是华文行楷

当然我们在word中添加表格时,不可避免的会需要设置表格的边框样式,这里我们单独新建了一个函数来设置边框样式

#region 设置表格的边框
def set_cell_border(cell, **kwargs):
    """
    Set cell`s border
    Usage:
    set_cell_border(
        cell,
        top={"sz": 12, "val": "single", "color": "#FF0000", "space": "0"},
        bottom={"sz": 12, "color": "#00FF00", "val": "single"},
        left={"sz": 24, "val": "dashed", "shadow": "true"},
        right={"sz": 12, "val": "dashed"},
    )
    """
    tc = cell._tc
    tcPr = tc.get_or_add_tcPr()

    # check for tag existnace, if none found, then create one
    tcBorders = tcPr.first_child_found_in("w:tcBorders")
    if tcBorders is None:
        tcBorders = OxmlElement('w:tcBorders')
        tcPr.append(tcBorders)

    # list over all available tags
    for edge in ('left', 'top', 'right', 'bottom', 'insideH', 'insideV'):
        edge_data = kwargs.get(edge)
        if edge_data:
            tag = 'w:{}'.format(edge)

            # check for tag existnace, if none found, then create one
            element = tcBorders.find(qn(tag))
            if element is None:
                element = OxmlElement(tag)
                tcBorders.append(element)

            # looks like order of attributes is important
            for key in ["sz", "val", "color", "space", "shadow"]:
                if key in edge_data:
                    element.set(qn('w:{}'.format(key)), str(edge_data[key]))
#endregion 

表格里面的单元格,我们也可以像操作excel一样,合并单元格

 # 往合并单元格中写入
    cell3 = table_ddfhyc1.cell(0, 5)
    cell4 = table_ddfhyc1.cell(0, 8)
    cell4.merge(cell3)

最后所有的赋值、拼接完成后,我们需要保存word文档

Word.save(WordSavePath)

你可能感兴趣的:(python,excel,word,python)