批量生成多个固定格式含表格数据的word文档


文章概况

本文仅作为知识点总结与教程引导,借用上篇文章的前期准备进行汇总。

中心问题

如何按照以下设定的word格式,批量生成多个word文档。
在这里插入图片描述


探讨问题:
1.如何生成固定范围的随机数以及在特定列表中随机选择一个元素。
2.dataframe如何按照某列数值从大到小顺序排序,以及如何选取最大值的对应行中的其他列数据。
3.如何通过python对docx进行格式设置与输出。


提示:以下是本篇文章正文内容,下面案例可供参考

一、知识点总结

1.如何生成固定范围的随机数以及在特定列表中随机选择一个元素。

(1)对于固定范围内生成一个随机数,采用的是random库的uniform函数:

random_rain   = random.uniform(0,120)

(2)在特定列表中,比如26个字母中随机选择一个元素,需要用到random库中的choice函数,其中26字母的列表得到的方式有两种:1.手动创建并书输入。2.接用string模块。
a_str = string.ascii_uppercase
'''
# 获取所有ascii码中字母字符的字符串(包含大写和小写)
# 字母:string.ascii_letters
# 大写:string.ascii_uppercase
# 小写:string.ascii_lowercas
'''

了解更多关于String模块可参考

https://blog.csdn.net/qq_41300019/article/details/79069697


(3)判断随机选择的字母是否在列表内:
if (random_letter not in letters_list):
	letters_list.append(random_letter)
else:
	pass

2.利用随机数得到相对应的数据及站点,生成dataframe表格,并按照某列数值从大到小顺序排序

从大到小的排列设置:

首先设置一个dataframe表格,用df.sort_values(ascending=False , by)进行排序:
ascending=False 为从大到小排序,True为从小到大。
by 为指定的行或列。


了解更多数据排序可查看

https://blog.csdn.net/weixin_40286872/article/details/108234357

比如我用随机数定制这样的表格:

  站点      降水量 降水等级
1  U  111.229  大暴雨
7  I  68.2513   暴雨
0  A  47.5457   大雨
5  W  30.2053   大雨
4  V  28.0151   大雨
3  Q  23.1953   中雨
2  R   21.553   中雨
8  N  15.8264   中雨
6  S   5.1173   小雨

代码编写:

#判断随机数据代表的降水量级。
def rainstrong(rain):
    if rain <25 and rain > 10:
        return '中雨'
    elif rain >25 and rain <50:
        return '大雨'
    elif rain >0 and rain<10:
        return '小雨'
    elif rain >25 and rain<100:
        return '暴雨' 
    elif rain >100:
        return '大暴雨'

# 得到一个随机字母的列表
def random_letters(num):
    #定义一个空列表保存随机字母
    letters_list = []
    rain_list    = []
    strong_list  = []
    #letter_list 的长度等于n时才结束循环。
    while len(letters_list) < num :
        a_str = string.ascii_uppercase
        random_letter = random.choice(a_str)
        random_rain   = random.uniform(0,120)
        
        #判断随机到的字母是否在列表里,没有则增加进去。
        if (random_letter not in letters_list):
            letters_list.append(random_letter)
            #如果降水量为0则剔除。
            while random_rain == 0:
                random_rain   = random.uniform(0,120)
            strong_list.append(rainstrong(random_rain))
            rain_list.append(random_rain)
        else:
            pass
    df = pd.DataFrame(data=[letters_list,rain_list,strong_list],index=(['站点','降水量','降水等级'])).T.sort_values(ascending=False , by= '降水量')
    return df

3.打印出dataframe最大值的那一行中的某列元素。

按照中心问题的要求,表格的内容分为:“站点名”、“降水量”、“降水强度”。
现在需要打印出下面降水量最大时所处在的站点U,怎么导出?

  站点      降水量 降水等级
1  U  111.229  大暴雨
7  I  68.2513   暴雨
0  A  47.5457   大雨
5  W  30.2053   大雨
4  V  28.0151   大雨
3  Q  23.1953   中雨
2  R   21.553   中雨
8  N  15.8264   中雨
6  S   5.1173   小雨

两种办法:

一、df[条件][index][columns]

使用这种方法则需要获取cf[条件]的index与columns,cf[条件].index---->得到一个Int64Index的列表
----->对于只有最大值满足条件的只有一个,所以也需要一个索引,在index后加上[0]
故而欲得到这个dataframe最大值的站点在哪,完整的案例写法为:
df | [df['降水量']==df['降水量'].max()] | ['站点'] | [ df[df['降水量']==df['降水量'].max()].index[0] ]
---  ----------------------------------  --------  -------------------------------------------------
 |                  |                       |                              |
 |                  |                       |                              |
 |                  |                       |                              |
\/                 \/                      \/                             \/
主体              筛选条件                 columns                        index
                                                                           |
                                                                           |
                                                                           |
                                                                          \/
                                                               df[筛选条件].index[0]

二、df[index or columns][条件].values
df[index or columns][条件]
-- ---------------- -----
|          |         |
|          |         |
|          |         |
\/         \/        \/   
主体   选择的行或列   筛选条件
                     |
                     |
                     |
                    \/
                   选择的是列得到
                   是带有行的此列
                   的表格形式
                   例如:
                   
df['站点'][df['降水量']==df['降水量'].max()]
>>1    U
Name: 站点, dtype: object

完整的案例写法为:
df['站点'][df['降水量']==df['降水量'].max()].values[0]

两种方法得到的最大结果都一样,建议使用第二种。


4.python-docx设置word的文段各种格式

文段设置,个人的理解add_paragraph、add_heading以及add_XXX的是对文段的段落样式的设置。 而对于字体样式的设置,是在段落的基础上进行设置,所以需要对text进行add_run设置。
而add_paragraph等没有.font等设置。
借助font能够做到一段中存在多种句子的字体颜色大小的设置。

我个人的完整写法思路为:

from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.shared import Pt
from docx.shared import Cm
from docx.shared import RGBColor
from docx import Document
doc = Document()
paragraph = doc.add_paragraph()
text      = paragraph.add_run('文段内容')
text.font.size      = Pt(11)#设置字体大小为11磅
text.font.color.rgb = RGBColor(255,0,0) #设置字体颜色为红色,数值的设置与ps的颜色面板一样。
format_t    = paragraph.paragraph_format  #设置段落格式
format_t.alignment         = WD_ALIGN_PARAGRAPH.CENTER #设置居中
format_t.space_after       = Pt(5)                     #设置段后
format_t.space_before      = Pt(10)                    #设置段前


更多docx的设置可参考官方文档

https://python-docx.readthedocs.org/en/latest/user/text.html

也可查看python-docx处理word文档功能详细说明


5.另外针对对python-docx对于段落首行缩进的设置

在python-docx并没有给出字符这个单位,官方文件能用的长度单位为:Cm、Pt、Mm等,这里换算成使用Cm,而要做到根据字号大小进行首行缩进,就需要对其进行计算。
根据百度所记载的字号,磅与字号间的关系为:
在这里插入图片描述
同时磅与毫米之间的换算 1磅 ≈ 0.35mm ,准确的说 1磅 = 0.3527mm
而假设字号为11,缩进两个字符就等于缩进
11 X 0.3527 X 2 X 0.1 cm
#首行缩进两个字符就该如下编写:

format_t.first_line_indent = Cm(0.1*11*0.35*2)

二、实现批量导出中心问题所要求的word文档格式

思路

1.先随机生成降水量数据、字母拼凑成的“站点”元素、以及对降水数据的雨量大小判别。
2.将得到的三个列表通过dataframe构建表格。
3.设置word的输出格式,包含内容为:

  • 标题
  • 文段
  • 标题
  • 表格
  • 标题
  • 表格

具体源代码

import random
import string
import pandas as pd
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.shared import Pt
from docx.shared import Mm
from docx.shared import RGBColor


def rainstrong(rain):
    if rain <25 and rain > 10:
        return '中雨'
    elif rain >25 and rain <50:
        return '大雨'
    elif rain >0 and rain<10:
        return '小雨'
    elif rain >25 and rain<100:
        return '暴雨' 
    elif rain >100:
        return '大暴雨'

# 得到一个随机字母的列表
def random_letters(num):
    #定义一个空列表保存随机字母
    letters_list = []
    rain_list    = []
    strong_list  = []
    
    #letter_list 的长度等于n时才结束循环。
    while len(letters_list) < num :
        a_str = string.ascii_uppercase
        
        # random.choice 返回对象中的一个随机元素
        random_letter = random.choice(a_str)
        random_rain   = random.uniform(0,120)
        
        #判断随机到的字母是否在列表里,没有则增加进去。
        if (random_letter not in letters_list):
            letters_list.append(random_letter)
            while random_rain == 0:
                random_rain   = random.uniform(0,120)
                
            strong_list.append(rainstrong(random_rain))
            rain_list.append(random_rain)
        else:
            pass
        
    df = pd.DataFrame(data=[letters_list,rain_list,strong_list],index=(['站点','降水量','降水等级'])).T.sort_values(ascending=False , by= '降水量')
    return df


class Main:
    def __init__(self,df):
        self.cf         = df
        self.heavy_rain = 0
        self.hard_rain  = 0
        self.down_pour  = 0
        for i in df['降水量']:
            if i >25 and i <50:
                self.heavy_rain += 1 
            elif i >25 and i<100:
                self.hard_rain += 1
            elif i >100:
                self.down_pour  += 1
    def mkdocument(self,ni):
        from docx import Document
        def re_date(ni):
            if ni+1 < 10:
                date = '0' +str(ni+1)
            else:
                date = str(ni+1)
            return date
        doc = Document()
        h1    = doc.add_heading()
        h1.add_run('雨量统计报表').font.color.rgb =RGBColor(255,0,0)
        h1.alignment = WD_ALIGN_PARAGRAPH.CENTER
        p1    =  doc.add_paragraph()
        print(self.cf['站点'][cf['降水量']==self.cf['降水量'].max()].values[0])
        print(self.cf['站点'][cf['降水量']==self.cf['降水量'].max()])
        #使用try区分有降水时的文段与无降水的文段。
        try:
            text1 = p1.add_run('2021年08月'+re_date(ni)+'日20时-'+re_date(ni+1)+'日20时,我区共有雨量站26个,其中'+
                  str(len(self.cf.index))+
                  '个站点出现降水。全区平均面雨量为'+
                  str( round(self.cf['降水量'].mean(axis=0)) )+
                  '毫米,最大降水量为'+
                  str(self.cf['降水量'].max())+
                  '毫米,出现在'+ 
                  self.cf['站点'][self.cf['降水量']==self.cf['降水量'].max()].values[0]+
                  '。'
                  )
        except:
            text1 = p1.add_run('2021年08月'+re_date(ni)+'日20时-'+re_date(ni+1)+'日20时,我区共有雨量站26个,其中'+
                  str(len(self.cf.index))+
                  '个站点出现降水。'
                  )
        #设置字号大小。
        s            = 11
        #text设置字体样式,p1设置段落样式
        text1.font.size = Pt(s)
        p1_format = p1.paragraph_format
        p1_format.first_line_indent = Pt(s*2)
        
        
        h2      = doc.add_heading()
        h2.add_run('雨量分级').font.color.rgb =RGBColor(255,0,0)
        h2.alignment = WD_ALIGN_PARAGRAPH.CENTER
        
        
        table1  = doc.add_table(rows=2,cols=6)
        t1_head = ['量级(mm)','站点数','量级(mm)','站点数','量级(mm)','站点数']
        t1_data = ['25-50mm',self.heavy_rain,'50-100mm',self.hard_rain,'100mm以上',self.down_pour]
        for i in range(len(t1_head)):
            table1.cell(0,i).text = t1_head[i]
            table1.cell(1,i).text = str(t1_data[i])
            
            
        h3      = doc.add_heading()
        h3.add_run('雨量明细').font.color.rgb =RGBColor(255,0,0)
        h3.alignment = WD_ALIGN_PARAGRAPH.CENTER
        table2  = doc.add_table(rows=len(self.cf.index)+1,cols=len(self.cf.columns))
        
        head    = ['站点','降水量','降水等级']
        
        for i in range(len(head)):
            table2.cell(0,i).text = head[i]
            
        for i in range(len(self.cf.index)):
            
            table2.cell(i+1,0).text = str(self.cf['站点'][self.cf.index[i]])
            
            table2.cell(i+1,1).text = str(self.cf['降水量'][self.cf.index[i]])
            
            if self.cf['降水量'][self.cf.index[i]] >= 50:
                
                table2.cell(i+1,2).paragraphs[0].add_run( self.cf['降水等级'][self.cf.index[i]] ).font.color.rgb =RGBColor(255,0,0)
            
            else:
                
                table2.cell(i+1,2).text = self.cf['降水等级'][self.cf.index[i]]
            
        doc.save('202108'+re_date(ni)+'.docx')
        
if __name__ == '__main__':
	#n为输出文件数量
	n = 15
    for i in range(n):
        num = int(random.uniform(0,27))
        df  = random_letters(num)
        cf = Main(df).cf
        mk = Main(df).mkdocument(i)

三、结语

以上仅供娱乐和学习,不考虑产生多大的实际作用,有错误的地方或者更加优质的写法请多多批评。

猜你喜欢

转载自blog.csdn.net/weixin_48458238/article/details/120391787