标签归档:办公

Pyzbar 两步批量识别快递单号条形码实战教程

这是Python改变生活系列的第三篇,讲到了如何通过Python的pyzbar批量识别快递单号的条形码,以提高我们的生活工作效率,这是一篇实战教程。

1.识别快递单号的前情提要

了解我的小伙伴可能都知道,小五经常给大家送书。最近一年,不算联合抽奖送书,单独我自购+出版社赞助已送出1000本书籍。

如果是自购的话,还需要自己联系快递小哥寄出书籍。

寄出后快递小哥会给我截图来反馈,然而我想要单号的时候就遇到问题了。

每次寄完书,我都只能得到n个截图(内含快递信息)。

为了及时反馈大家物流信息,我需要尽快将快递单号提取出来。

2.思考解决办法

每次大概都有十几到几十张截图,手动去识别真的太麻烦。

不如先看看每张截图大概是什么样子,再去想想批量处理的办法吧。

主要是为了批量获取图片中的快递单号,我想到了两个解决办法:

  1. 用python识别条形码来直接获得准确快递单号

  2. 用python调用ocr,识别截图中的快递单号文字

大家觉得哪个更简单更准确呢?

今天我先聊聊第一种方法的流程和踩坑经历。

 

3.实战教程-遍历图片

首先,第一步需要先获取文件夹中的所有截图,再依次进行条形码识别。

具体操作可以参考注释

import os

def get_jpg():
    jpgs = []
    path = os.getcwd()
    for i in os.listdir(path):  #获取文件列表
        if i.split(".")[-1] == "jpg":  #筛选jpg文件(截图)
            oldname=os.path.join(path,i)  #旧文件名
            i = i.replace('微信图片_','')
            newname=os.path.join(path,i)  #新文件名
            os.rename(oldname,newname)  #改名
            jpgs.append(i)
    return jpgs

上面的代码中除了遍历筛选图片,还涉及了改名的操作。

这是因为我在后面使用 opencv 时,打开的路径只要含有中文就会一直报错,于是我就干脆把截图名称里的中文去除。

执行构建的get_jpg()函数,得到

这些就是演示文件中的四个截图文件,下面开始对他们进行识别。

4.实战教程-识别条形码

python的第三方模块 pyzbar 可以很方便地处理二维码的识别。我们这次用它来识别一维条形码的话,用法也大致一样。不过还要搭配 cv2 使用,主要是为了利用cv2.imread()来读取图片文件。

注意:对于cv2模块,安装时需要输入pip3 install opencv-python,但在导入的时候采用import cv2

识别条形码的具体语句如下所示:

import pyzbar.pyzbar as pyzbar
import cv2

def get_barcode(img):
    image = cv2.imread(img)
    barcodes = pyzbar.decode(image)
    barcode = barcodes[0]
    barcode_data = barcode.data.decode("utf-8")
    return barcode_data

上面构建的get_barcode()函数可以实现识别条形码,并返回结果数据。

我们可以用for循环遍历前文获取的所有图片,再依次使用get_barcode()函数来识别条形码。

data_m =[]
for i in jpgs:
    data = get_barcode(i)
    data_m.append(data)
data_m

可以发现,成功识别了四张截图里的条形码,并获取了对应的快递单号。

小结

回顾今天的问题案例,我先通过思考想出了两种解决办法。第一种的优点是识别条形码比OCR更准确,但是其只获取了快递单号。后续在给获得赠书的同学反馈时,我还需要手动将名字和单号对应,不够偷懒。后续将给大家介绍第二种方法的流程和优缺点。

如果想看更多python改变生活的真实问题案例,给本文右下角点个赞吧👍

如果你也有一直想用python解决的问题,欢迎在评论区告诉我🚀

本文转自快学Python。

我们的文章到此就结束啦,如果你喜欢今天的Python 实战教程,请持续关注Python实用宝典。

有任何问题,可以在公众号后台回复:加群,回答相应红字验证信息,进入互助群询问。

原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!

点击下方阅读原文可获得更好的阅读体验

Python实用宝典 (pythondict.com)
不只是一个宝典
欢迎关注公众号:Python实用宝典

实用的 Python 汉字转拼音工具 — pypinyin 实战教程

Pypinyin 将汉字转拼音,可以用于批量汉字注音、文字排序、拼音检索文字等常见场景。

现在互联网上有许多拼音转换工具,基于Python的开源模块也不少,今天给大家介绍一个功能特性最多的模块: pypinyin,它支持以下特性:

  • 1. 根据词组智能匹配最正确的拼音。
  • 2. 支持多音字。
  • 3. 简单的繁体支持, 注音支持。
  • 4. 支持多种不同拼音/注音风格。
  • 5. 命令行工具一键转化

1.准备

开始之前,你要确保Python和pip已经成功安装在电脑上,如果没有,请访问这篇文章:超详细Python安装指南 进行安装。

(可选1) 如果你用Python的目的是数据分析,可以直接安装Anaconda:Python数据分析与挖掘好帮手—Anaconda,它内置了Python和pip.

(可选2) 此外,推荐大家用VSCode编辑器来编写小型Python项目:Python 编程的最好搭档—VSCode 详细指南

Windows环境下打开Cmd(开始—运行—CMD),苹果系统环境下请打开Terminal(command+空格输入Terminal),输入命令安装依赖:

pip install pypinyin

2.汉字转拼音 基本使用

最普通的拼音转化方法如下:

# Python实用宝典
from pypinyin import pinyin, lazy_pinyin, Style
pinyin('中心')
# [['zhōng'], ['xīn']]

识别多音字:

# Python实用宝典
from pypinyin import pinyin, lazy_pinyin, Style
pinyin('中心', heteronym=True)  # 启用多音字模式
# [['zhōng', 'zhòng'], ['xīn']]

设置输出风格,只识别首字母:

# Python实用宝典
from pypinyin import pinyin, lazy_pinyin, Style
pinyin('中心', style=Style.FIRST_LETTER)  # 设置拼音风格
# [['z'], ['x']]

修改音调输出位置,在相应字母的后面显示音调,或者拼音的最后显示音调:

# Python实用宝典
from pypinyin import pinyin, lazy_pinyin, Style

# TONE2 在相应字母的后面显示音调
pinyin('中心', style=Style.TONE2, heteronym=True)
# [['zho1ng', 'zho4ng'], ['xi1n']]

# TONE3 拼音的最后显示音调
pinyin('中心', style=Style.TONE3, heteronym=True)
# [['zhong1', 'zhong4'], ['xin1']]

不考虑多音字的情况:

# Python实用宝典
from pypinyin import pinyin, lazy_pinyin, Style
lazy_pinyin('中心')  # 不考虑多音字的情况
# ['zhong', 'xin']

不使用v来代替ü:

# Python实用宝典
from pypinyin import pinyin, lazy_pinyin, Style
lazy_pinyin('战略', v_to_u=True)  # 不使用 v 表示 ü
# ['zhan', 'lüe']

标记轻声:

# Python实用宝典
from pypinyin import pinyin, lazy_pinyin, Style
# 使用 5 标识轻声
lazy_pinyin('衣裳', style=Style.TONE3, neutral_tone_with_five=True)
# ['yi1', 'shang5']

使用命令行一键识别拼音:

# Python实用宝典
python -m pypinyin 音乐
# yīn yuè

3.Pypinyin 高级使用

自定义拼音显示风格

我们还可以通过 register() 来实现自定义拼音风格的需求:

from pypinyin import lazy_pinyin

from pypinyin.style import register

@register('kiss')
def kiss(pinyin, **kwargs):
    return '😘 {0}'.format(pinyin)

  
lazy_pinyin('么么', style='kiss')
# ['😘 me', '😘 me']

可以见到,通过定义一个 kiss 函数,使用 register 装饰器,我们生成了一个新的 style,这个 style 可以直接被用于拼音的转换参数,非常方便。

另外,所有模块自带的 style 及其效果如下:

@unique
class Style(IntEnum):
    """拼音风格"""

    #: 普通风格,不带声调。如: 中国 -> ``zhong guo``
    NORMAL = 0
    #: 标准声调风格,拼音声调在韵母第一个字母上(默认风格)。如: 中国 -> ``zhōng guó``
    TONE = 1
    #: 声调风格2,即拼音声调在各个韵母之后,用数字 [1-4] 进行表示。如: 中国 -> ``zho1ng guo2``
    TONE2 = 2
    #: 声调风格3,即拼音声调在各个拼音之后,用数字 [1-4] 进行表示。如: 中国 -> ``zhong1 guo2``
    TONE3 = 8
    #: 声母风格,只返回各个拼音的声母部分(注:有的拼音没有声母,详见 `#27`_)。如: 中国 -> ``zh g``
    INITIALS = 3
    #: 首字母风格,只返回拼音的首字母部分。如: 中国 -> ``z g``
    FIRST_LETTER = 4
    #: 韵母风格,只返回各个拼音的韵母部分,不带声调。如: 中国 -> ``ong uo``
    FINALS = 5
    #: 标准韵母风格,带声调,声调在韵母第一个字母上。如:中国 -> ``ōng uó``
    FINALS_TONE = 6
    #: 韵母风格2,带声调,声调在各个韵母之后,用数字 [1-4] 进行表示。如: 中国 -> ``o1ng uo2``
    FINALS_TONE2 = 7
    #: 韵母风格3,带声调,声调在各个拼音之后,用数字 [1-4] 进行表示。如: 中国 -> ``ong1 uo2``
    FINALS_TONE3 = 9
    #: 注音风格,带声调,阴平(第一声)不标。如: 中国 -> ``ㄓㄨㄥ ㄍㄨㄛˊ``
    BOPOMOFO = 10
    #: 注音风格,仅首字母。如: 中国 -> ``ㄓ ㄍ``
    BOPOMOFO_FIRST = 11
    #: 汉语拼音与俄语字母对照风格,声调在各个拼音之后,用数字 [1-4] 进行表示。如: 中国 -> ``чжун1 го2``
    CYRILLIC = 12
    #: 汉语拼音与俄语字母对照风格,仅首字母。如: 中国 -> ``ч г``
    CYRILLIC_FIRST = 13

处理特殊字符

默认情况下,对于文字中的特殊字符会不做任何处理,原样返回:

pinyin('你好☆☆')
# [['nǐ'], ['hǎo'], ['☆☆']]

不过如果你想对这些特殊字符做处理也是可以的,比如:

ignore : 忽略该字符

pinyin('你好☆☆', errors='ignore')
# [['nǐ'], ['hǎo']]

replace : 替换为去掉 \u 的 unicode 编码:

pinyin('你好☆☆', errors='replace')
# [['nǐ'], ['hǎo'], ['26062606']]

callable 对象 : 提供一个回调函数,接受无拼音字符(串)作为参数, 支持的返回值类型: unicode 或 list 或 None 。:

pinyin('你好☆☆', errors=lambda x: 'star')
# [['nǐ'], ['hǎo'], ['star']]

pinyin('你好☆☆', errors=lambda x: None)
# [['nǐ'], ['hǎo']]

返回值类型为 list 时,会自动 expend list

pinyin('你好☆☆', errors=lambda x: ['star' for _ in x])
# [['nǐ'], ['hǎo'], ['star'], ['star']]

# 指定多音字
pinyin('你好☆☆', heteronym=True, errors=lambda x: [['star', '☆'] for _ in x])
# [['nǐ'], ['hǎo'], ['star', '☆'], ['star', '☆']]

自定义拼音库

如果你觉得模块输出效果不合你意,或者你想做特殊处理,可以通过  load_single_dict() 或 load_phrases_dict() 以自定义拼音库的方式修正结果:

from pypinyin import lazy_pinyin, load_phrases_dict, Style, load_single_dict
hans = '桔子'
lazy_pinyin(hans, style=Style.TONE2)
# ['jie2', 'zi3']
load_phrases_dict({'桔子': [['jú'], ['zǐ']]})  # 增加 "桔子" 词组
lazy_pinyin(hans, style=Style.TONE2)
# ['ju2', 'zi3']

hans = '还没'
lazy_pinyin(hans, style=Style.TONE2)
# ['hua2n', 'me2i']
load_single_dict({ord('还'): 'hái,huán'})  # 调整 "还" 字的拼音顺序
lazy_pinyin('还没', style=Style.TONE2)
# ['ha2i', 'me2i']

我们的文章到此就结束啦,如果你喜欢今天的 Python 教程,请持续关注Python实用宝典。

有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。

原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!

给作者打赏,选择打赏金额
¥1¥5¥10¥20¥50¥100¥200 自定义

​Python实用宝典 ( pythondict.com )
不只是一个宝典
欢迎关注公众号:Python实用宝典

对比Excel数据透视表,学习pandas pivot_table

Excel的数据透视表非常有用,但是Pandas也有这个功能你知道吗?今天我们来对比Excel数据透视表,学习pandas pivot_table

1.Excel中做数据透视表

① 选中整个数据源;

 

② 依次点击“插入”—“数据透视表”

 

③ 选择在Excel中的哪个位置,插入数据透视表

 

④ 然后根据实际需求,从不同维度展示结果

 

⑤ 结果如下

2. pandas 用 pivot_table 做数据透视表

1)语法格式
pd.pivot_table(data,index=None,columns=None,
               values=None,aggfunc='mean',
               margins=False,margins_name='All',
               dropna=True,fill_value=None)

2)对比excel,说明上述参数的具体含义

 

参数说明:

  • data 相当于Excel中的”选中数据源”;

  • index 相当于上述”数据透视表字段”中的行;

  • columns 相当于上述”数据透视表字段”中的列;

  • values 相当于上述”数据透视表字段”中的值;

  • aggfunc 相当于上述”结果”中的计算类型;

  • margins 相当于上述”结果”中的总计;

  • margins_name 相当于修改”总计”名,为其它名称;

     

下面几个参数,用的较少,记住干嘛的,等以后需要就百度。

  • dropna 表示是否删除缺失值,如果为True时,则把一整行全作为缺失值删除;

  • fill_value 表示将缺失值,用某个指定值填充。

3. 案例说明

1)求出不同品牌下,每个月份的销售数量之和

 

① 在Excel中的操作结果如下

 

② 在pandas中的操作如下

df = pd.read_excel(r"C:\Users\黄伟\Desktop\pivot_table.xlsx")
display(df.sample(5))

df.insert(1,"月份",df["销售日期"].apply(lambda x:x.month))
display(df.sample(5))

df1 = pd.pivot_table(df,index="品牌",columns="月份",
                     values="销售数量",aggfunc=np.sum)
display(df1)

结果如下:

 

2)求出不同品牌下,每个地区、每个月份的销售数量之和

 

① 在Excel中的操作结果如下

 

② 在pandas中的操作如下

df = pd.read_excel(r"C:\Users\黄伟\Desktop\pivot_table.xlsx")
display(df.sample(5))

df.insert(1,"月份",df["销售日期"].apply(lambda x:x.month))
display(df.sample(5))

df1 = pd.pivot_table(df,index="品牌",columns=["销售区域","月份"],
                     values="销售数量",aggfunc=np.sum)
display(df1)

结果如下:

 

3)求出不同品牌不同地区下,每个月份的销售数量之和

 

① 在Excel中的操作结果如下

 

② 在pandas中的操作如下

df = pd.read_excel(r"C:\Users\黄伟\Desktop\pivot_table.xlsx")
display(df.sample(5))

df.insert(1,"月份",df["销售日期"].apply(lambda x:x.month))
display(df.sample(5))

df1 = pd.pivot_table(df,index=["品牌","销售区域"],columns="月份",
                     values="销售数量",aggfunc=np.sum)
display(df1)

结果如下:

 

4)求出不同品牌下的“销售数量之和”与“货号计数”

 

① 在Excel中的操作结果如下

 

② 在pandas中的操作如下

df = pd.read_excel(r"C:\Users\黄伟\Desktop\pivot_table.xlsx")
display(df.sample(5))

df.insert(1,"月份",df["销售日期"].apply(lambda x:x.month))
display(df.sample(5))

df1 = pd.pivot_table(df,index="品牌",columns="月份",
                     values=["销售数量","货号"],
                     aggfunc={"销售数量":"sum","货号":"count"},
                     margins=True,margins_name="总计")
display(df1)

结果如下:

本文转自凹凸数据。

我们的文章到此就结束啦,如果你喜欢今天的Python 实战教程,请持续关注Python实用宝典。

有任何问题,可以在公众号后台回复:加群,回答相应红字验证信息,进入互助群询问。

原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!

点击下方阅读原文可获得更好的阅读体验

Python实用宝典 (pythondict.com)
不只是一个宝典
欢迎关注公众号:Python实用宝典

Pandas实战教程:将Excel转为html格式

大家谈及用Pandas导出数据,应该就会想到to.xxx系列的函数。

这其中呢,比较常用的就是pd.to_csv()pd.to_excel()。但其实还可以将其导成Html网页格式,这里用到的函数就是pd.to_html()

读取Excel

今天我们要实现Excel转为html格式,首先需要用读取Excel中的表格数据。

import pandas as pd
data = pd.read_excel('测试.xlsx')

查看数据

data.head()

下面我们来学习把DataFrame转换成HTML表格的方法。

生成Html

to_html()函数可以直接把DataFrame转换成HTML表格,只需一行代码即可实现:

html_table = data.to_html('测试.html')

运行上面代码后,工作目录中多了测试.html文件,使用网页浏览器打开它,显示内容如下👇

print(data.to_html())

通过print打印,可以看到DataFrame的内部结构被自动转换为嵌入在表格中的<TH>,<TR>,<TD>标签,保留所有内部层级结构。

调整格式

我们还可以自定义修改参数,来调整生成HTML的格式。

html_table = data.to_html('测试.html',header = True,index = False,justify='center')

再次打开新生成的测试.html文件,发现格式已经发生了变化。

如果想对格式进行进一步调整(增加标题、修改颜色等),就需要一些HTML知识了,可以对生成的测试.html文件中的文本进行调整。

对于有些小伙伴可能需要进行页面展示,就要搭配Flask库来使用了。

小结

Pandas提供read_html()to_html()两个函数用于读写html格式的文件。这两个函数非常有用,一个轻松将DataFrame等复杂的数据结构转换成HTML表格;另一个不用复杂爬虫,简单几行代码即可抓取Table表格型数据,简直是个神器!

今天篇幅很短,主要讲了Pandas中to_html()这个函数。使用该函数最大的优点是:我们在不了解html知识的情况下,就能生成一个表格型的HTML。本文转自快学Python

我们的文章到此就结束啦,如果你喜欢今天的 Python 教程,请持续关注Python实用宝典。

有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。

原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!

给作者打赏,选择打赏金额
¥1¥5¥10¥20¥50¥100¥200 自定义

​Python实用宝典 ( pythondict.com )
不只是一个宝典
欢迎关注公众号:Python实用宝典

只需 10 行代码,Python 教你自制屏幕翻译工具,高效办公

1. 场景

大家如果平常遇到不认识的英文,相信大部分的人都会复制内容后,使用翻译软件,或者拷贝到网站上去执行翻译。

当然,对于 IDE、浏览器可以装一些插件来翻译,有道也有划词翻译。

但是,经常会有一些解析对话框,没法拷贝文本内容,上面的方式都就变得束手无策。

今天教大家利用 10 行 Python 代码制作一个翻屏软件,随处翻译,高效办公。

2. 实现步骤

首先,我们使用 PIL 依赖库剪切板读取图片,然后下载到本地。

# 安装PIL依赖
# 从剪切板读取图片
img = ImageGrab.grabclipboard()

# 保存到本地
image_result = './temp.png'

img.save(image_result)

接着,使用 pytesseract 依赖库的 OCR 功能,识别图片中的英文内容。

# OCR识别
# 识别图片中的英文
content_eng = pytesseract.image_to_string(Image.open(image_result), lang='eng')

然后,就是翻译上面识别的英文内容了。

为了保证英文翻译的准确性,这里利用 Google 翻译的简易依赖库:googletrans

# 翻译
# Google翻译
translator = Translator(service_urls=['translate.google.cn'])

# 翻译成中文
content_chinese = translator.translate(content_eng, src='en', dest='zh-cn').text

最后,使用 Python 自带的 GUI tkinker,将识别后的中文显示出来。

# 初始化
root = Tk()
root.withdraw()

# 显示翻译后的结果,以对话框的形式
tkinter.messagebox.showinfo('翻译结果', content_chinese)

3. 简化步骤

为了加快翻译的步骤,先将上面的脚本保存到本地,然后设置快捷键执行脚本。

PC 端,可以打包成 EXE 后设置快捷键,或者利用 WinHotKey 设置脚本执行。

MAC OSX,使用自动操作( 运行 Shell 脚本 )+ 键盘快捷键(服务),即可以快速执行脚本。

如此,后面只需要截图 + 快捷键,两步快速执行翻译操作。

本文转自AirPython.

我们的文章到此就结束啦,如果你喜欢今天的 Python 教程,请持续关注Python实用宝典。

有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。

原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!

给作者打赏,选择打赏金额
¥1¥5¥10¥20¥50¥100¥200 自定义

​Python实用宝典 ( pythondict.com )
不只是一个宝典
欢迎关注公众号:Python实用宝典

同事要我帮忙补写178份Word日报!Python自动化办公实战教程

作者:Ryoko

来源:凹凸数据

不久前,一个同事有个项目要向领导交差,其中一部分工作是根据 excel 表中的每日数据,按格式整理成日报写入 word。

好家伙!足足 178 天的量要补,如果要靠复制粘贴,岂不是肝到吐血,(你给我自己解决啊!)

好吧ojbk,是时候祭出 Python 办公自动化了。

一、基础数据整理

首先让我们来看看数据样本和输出文档的需求(敏感数据已做和谐处理):原始 excel 文件中有 n 个子表,每个子表为一天的数据,存在无记录和有记录(部门数 ≥ 1,每个部门记录数 ≥ 1)两种情况,需分别整理成两种日报,一为纯文本描述,二为附带表格的文档。

撸起袖子,开骂!

哦不,开始写代码!

先将子表合成一个,便于统一观察每日数据记录的规律,也方便后期处理。使用 xlrd 库读表,获取工作簿中的活动表名,再使用 pandas 库遍历子表以合并,dataframe 格式的数据对 excel 表的相性绝佳。

def merge_sheet(filepath): # 合并多个同表头的子表
    wb = xlrd.open_workbook(filepath)
    sheets = wb.sheet_names()
    df_total = pd.DataFrame()
    for name in sheets:
        df = pd.read_excel(filepath, sheet_name=name)
        df_total = df_total.append(df)
    df_total.to_excel("merge.xlsx", index=False)

二、输出两种日报

(一)纯文本文档

根据需要输出的日报样式,输出无记录的日报只需读取【日期】列和【填报部门】列,将【填报部门】列为无的日期段按每日输出即可。观察原表数据,直接筛选无填报记录的数据丢到命名为“无”的子表里。

这里也可以利用 .groupby() 对【填报部门】列分组,取“无”的那一组,可是要注意一点:虽然 Python 很强大,但不需要将所有事情都交给 Python 做。

导入库和模块如下:

import pandas as pd
import xlrd
from docx import Document
from docx.shared import Pt
from docx.shared import Inches
from docx.oxml.ns import qn
from docx.enum.text import WD_PARAGRAPH_ALIGNMENT
from docx.enum.section import WD_ORIENTATION

基本流程很简单,读入无填报记录的数据,按日期输出 word 文档。

def wu_to_word(filepath):
    df = pd.read_excel(filepath, sheet_name="无")
    date_list = list(df['日期'])
    for d in date_list:
        filename = wordname+str(d)+").docx"  # 输出的word文件名
        title = "("+str(d)[:4]+"."+str(d)[4:6]+"."+str(d)[6:8]+")"  # 副标题日期XXXX.XX.XX
        word = str(d)[:4]+"年"+str(d)[4:6]+"月"+str(d)[6:8]+"日"  # 开头、落款日期XXXX年XX月XX日
        wu_doc(title, word, filename)
        print(f"文件:{filename},{title},{word} 已保存")

每份文档都会用到的同样的内容也可以先设定好。

wordname = “XX公司业务数据表(日报”
all_title = ” XX公司业务报告”

生成 word 内容,不加表格的情况下还是比较容易实现的,注意调整好格式。

def wu_doc(title,word,filename):  # 传入副标题日期,文段开头及落款的日期,文件名
    doc = Document()  # 创建文档对象
    section = doc.sections[0]  # 获取页面节点
section.orientation = WD_ORIENTATION.LANDSCAPE  # 页面方向设为横版
new_width, new_height = section.page_height, section.page_width  # 将原始长宽互换,实现将竖版页面变为横版
    section.page_width = new_width
    section.page_height = new_height
    # 段落的全局设置
    doc.styles['Normal'].font.name = u'宋体'  # 字体
    doc.styles['Normal']._element.rPr.rFonts.set(qn('w:eastAsia'), u'宋体')  # 中文字体需再添加这个设置
    doc.styles['Normal'].font.size = Pt(14)  # 字号 四号对应14
    t1 = doc.add_paragraph()  # 添加一个段落
    t1.paragraph_format.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER  # 居中
    _t1 = t1.add_run(all_title)  # 添加段落内容(大标题)
    _t1.bold = True  # 加粗
    _t1.font.size = Pt(22)
    t2 = doc.add_paragraph()  # 再添加一个段落
    t2.paragraph_format.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER  # 居中
    _t2 = t2.add_run(title + "\n")  # 添加段落内容(副标题)
    _t2.bold = True
    doc.add_paragraph(word + "无记录。\n\n").paragraph_format.first_line_indent = Inches(0.35)  # 添加段落同时添加内容,并设置首行缩进
    doc.add_paragraph(word).paragraph_format.alignment = WD_PARAGRAPH_ALIGNMENT.RIGHT  # 落款日期右对齐
    doc.save(dir+filename)  # 按路径+文件名保存

执行!104 份无填报记录的日报就写好啦,干脆就这样交差吧,剩下的不想研究了哈哈哈。

(二)附表格文档

有报送记录的数据处理起来相对复杂一点,先看一下原始数据。

比如 X 年 X 月 X 日,有 N 个部门填报了数据,根据文档样例,文段描述部分需要整理成如下格式:

部门 A:“报送内容1” X条记录;“报送内容2” Y条记录;部门 B:……;部门 C:……;

而附件表格部分需整理成如下格式,可以预想把每一行需要的数据整理一个 list,按行写入表格:

一级指标 二级指标 三级指标 四级指标 各部门报送情况 备注
lalala hahaha balabala 若为空则沿用上级 部门A:报送内容1 有记录未上传,没报,系统崩了
aaa bbb ccc ddd 部门A:报送内容2 已上传,报的好
部门B:报送内容1

基本流程类似,读表后先按日期分组,每一组含一天中的一个或多个部门数据,再生成某一天的附件需要的表格,接着整理文段描述,最后按日期输出每一天的 word 文档。

def what_to_word(filepath):
    df = pd.read_excel(filepath, sheet_name="有")
    df.fillna('', inplace=True)  # 替换nan值为空字符
    dates = []  # 日期列表
    df_total = []  # 分日期存的所有df
    list_total = []  # 每一份word中需要的表数据合集
    for d in df.groupby('日期'):
        dates.append(d[0])
        df_total.append(d[1])
    for index,date in enumerate(dates):
        list_oneday = []  # 某一个word所需的表数据
        for row in range(len(df_total[index])):
            list_row = get_table_data(df_total, index, row)  # 其中一行数据
            list_oneday.append(list_row)
        list_total.append(list_oneday)
    for index, date in enumerate(dates):
        filename = wordname+str(date)+").docx"  # 输出的word文件名
        title = "("+str(date)[:4]+"."+str(date)[4:6]+"."+str(date)[6:8]+")"  # 副标题日期XXXX.XX.XX
        word = str(date)[:4]+"年"+str(date)[4:6]+"月"+str(date)[6:8]+"日"  # 开头、落款日期XXXX年XX月XX日
        sentence = get_sentence(df_total, index)  # 某一天的文段描述
        what_doc(title, word, sentence, list_total[index], filename)  #传入需要的内容后输出文档
        print(f"文件:{filename} 已保存")

下面让我们分别看看整理表格、整理文段、输出文档是如何实现的。

1、整理表格

获取 excel 表中的一行数据(说明df_total[df_index] 为一个 dataframe,其 values 为一个二维的 numpy 数组),整理各级指标、各部门报送情况和备注,返回一个列表。

def get_table_data(df_total, df_index, table_row):
    list1 = df_total[df_index].values[table_row]  # excel表中的一行
    list2 = list1[3:7]  # 一至四级指标
    for i in range(len(list2)):  # 当前指标为空则沿用上级指标
        if list2[i] == '空' and i != 0:
            list2[i] = list2[i - 1]
    content = list1[2] + ":\n" + list1[-4]  # 报送内容
    if '否' in list1[-2]:  # 备注
        remark = '有记录未上传,' + str(list1[-1])
    else:
        remark = '已上传'
    list3 = list2.tolist()  # 需填入word中的表数据,由numpy数组转为list列表
    list3.append(str(content))
    list3.append(str(remark))
    return list3

2、整理文段

对当日数据中的【填报部门】列中的唯一值计数,得知有 N 个部门填报了数据。对部门分组,获取其相关信息,组合成 [(报送内容,记录数,是否上报,备注)] 的格式,再整理出形如 “有N个部门报送了数据:部门X:“ 报送内容XXX ” X条记录;… …” 的描述串。

def get_sentence(df_total, df_index):
    df_oneday = df_total[df_index]
    num = df_oneday['填报部门'].nunique()  # 部门的数量
    group = []  # 部门名称
    detail = []  # 组合某个部门的数据,其中元素为元组格式(, , , )
    info = ''  # 报送情况描述
    for item in df_oneday.groupby('填报部门'):
        group.append(item[0])
        detail.append(
            list(
                zip(
                    list(item[1]['报送内容']),
                    list(item[1]['记录数']),
                    list(item[1]['是否上报']),
                    list(item[1]['备注'])
                )
            )
        )
    for index, g in enumerate(group):  # 整理每个部门的填报情况
        mes = str(g)+':'  # 部门开头
        for i in range(len(detail[index])):
            _mes = detail[index][i]
            if int(_mes[1])>0:
                mes = mes + f'“{_mes[0]}{_mes[1]}条记录;'
        info = info + mes
    info = info[:-1]+"。"  #将最后一个分号替换成句号
    sentence = f"有{num}个部门报送了数据:{info}"
    return sentence

3、输出文档

(耐心警告!)调整 word 中的文本和表格样式的操作比较繁琐,需一步一步设置,预设表头如下:

table_title = [‘一级指标’, ‘二级指标’, ‘三级指标’, ‘四级指标’, ‘各部门报送情况’, ‘备注’]

其他详见代码注释。

def what_doc(title, word, sentence, table, filename):  # 传入副标题日期,开头/落款日期,文段,表数据,文件名
    doc = Document()
    section = doc.sections[0]
    new_width, new_height = section.page_height, section.page_width
    section.orientation = WD_ORIENTATION.LANDSCAPE
    section.page_width = new_width
    section.page_height = new_height
    # 段落的全局设置
    doc.styles['Normal'].font.name = u'宋体'  # 字体
    doc.styles['Normal']._element.rPr.rFonts.set(qn('w:eastAsia'), u'宋体')  # 中文字体需再添加这个设置
    doc.styles['Normal'].font.size = Pt(14)  # 字号 四号对应14
    t1 = doc.add_paragraph()  # 大标题
    t1.paragraph_format.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER  # 居中
    _t1 = t1.add_run(all_title)
    _t1.bold = True
    _t1.font.size = Pt(22)
    t2 = doc.add_paragraph()  # 副标题
    t2.paragraph_format.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER  # 居中
    _t2 = t2.add_run(title + "\n")
    _t2.bold = True
    doc.add_paragraph(word + sentence +"\n\n").paragraph_format.first_line_indent = Inches(0.35)  # 首行缩进
    doc.add_paragraph(word).paragraph_format.alignment = WD_PARAGRAPH_ALIGNMENT.RIGHT  # 右对齐
    doc.add_paragraph("各部门具体报送情况见附件:")

    doc.add_page_break()  # 分页---------------------------------------------------------------
    fujian = doc.add_paragraph().add_run("\n附件")
    fujian.bold = True
    fujian.font.size = Pt(16)
    t3 = doc.add_paragraph()  # 附件大标题
    t3.paragraph_format.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER  # 居中
    _t3 = t3.add_run("XX公司业务数据表")
    _t3.bold = True
    _t3.font.size = Pt(22)

    rows = len(table)+1
    word_table = doc.add_table(rows=rows, cols=6, style='Table Grid')  # 创建rows行、6列的表格
    word_table.autofit=True  # 添加框线
    table = [table_title] + table  # 固定的表头+表数据
    for row in range(rows):  # 写入表格
        cells = word_table.rows[row].cells
        for col in range(6):
            cells[col].text = str(table[row][col])
    for i in range(len(word_table.rows)):    # 遍历行列,逐格修改样式
        for j in range(len(word_table.columns)):
            for par in word_table.cell(i, j).paragraphs:  # 修改字号
                for run in par.runs:
                    run.font.size = Pt(10.5)
            for par in word_table.cell(0, j).paragraphs:  # 第一行加粗
                for run in par.runs:
                    run.bold = True
    doc.save(dir+filename)

执行!74份有记录的日报也写好啦,一共178份。

一顿操作猛如虎,总算是批量生成了日报,盒饭该加个鸡腿子了吧… …

我们的文章到此就结束啦,如果你喜欢今天的 Python 教程,请持续关注Python实用宝典。

有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。

原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!

给作者打赏,选择打赏金额
¥1¥5¥10¥20¥50¥100¥200 自定义

​Python实用宝典 ( pythondict.com )
不只是一个宝典
欢迎关注公众号:Python实用宝典