https://docs.reportlab.com/reportlab/userguide/
依赖
- reportlab
- pyrxp https://www.reportlab.com/ftp/
- preppy https://www.reportlab.com/ftp/
安装与使用
您想要用Python快速自动生成丰富、有吸引力且完全定制的PDF文件?
在工作中,你是否遇到过这样的工作场景:
- 自动化测试设备,将测试信息自动生成测试报告。
- 从XML一步生成PDF文件
- 生成包括表格、图片和文字的报告和论文等。
- 等等。
那我们今天要学习的Python第三方库ReportLab,就是为你量身打造的,这个库可以解决你在工作中自动生成报告的问题。我曾在某个时期大量使用这个库生成PDF文件。
这个Python库的功能强大,是一个用于生成PDF和图形的开源Python库。每个月使用ReportLab生成的文档超过500万份。
本文中的开发环境是Python 3.8,ReportLab的版本号是3.5.55。文中的代码全部经过验证,你可以直接使用,如果有什么问题,可以私信我。
ReportLab功能强大,但是限于篇幅,本文仅选取最常用的功能:段落、表格和图片。本文按照如下的顺序进行展开:
- 安装
- 功能概述
- PLATYPUS
- 段落
- 表格
- 图片
1.安装
用键盘按Win+R打开运行窗口,输入cmd命令。
C:\Users\Administrator>pip install reportlab
执行结果
Collecting reportlabUsing cached reportlab-3.5.55-cp38-cp38-win_amd64.whl (2.3 MB)Requirement already satisfied: pillow>=4.0.0 in d:\anaconda3\lib\site-packages (from reportlab) (7.2.0)Installing collected packages: reportlabSuccessfully installed reportlab-3.5.55
在命令行中输入python,进入python编译环境后,输入如下命令:
>>> import reportlab>>>
如果没有报错,则确认安装成功。
2.概述
在开始学习ReportLab之前,需要先回答下面几个问题:
- 什么是ReportLab?
- 我为什么要使用它?
- 怎么样才能够学会使用这个库?
什么是ReportLab?
简单来说,这个一个允许您使用Python编程语言直接创建PDF格式文件的软件库,它也可以创建各种表格、数据图和位图。
众所周知,PDF是一种电子文档的全球标准,它支持高质量打印,同时又能够很好的在不同的平台之间传播。然而,除了使用Word、专业版的Adobe PDF软件生成PDF文件,直接生成PDF比较困难。
今天要介绍的ReportLab可以通过图形命令行直接生成PDF,并且不需要其他辅助,ReportLab可以极快地生成报告。
ReportLab可以使用于下面的应用场景:
- 通过网页动态生成PDF文档
- 大量的报告和数据发布
- 用XML一步生成PDF
我们在官网上看ReportLab的案例。官网地址:
https://www.reportlab.com/casestudies/www.reportlab.com/casestudies/

我们选取其中的“Seychelles Travel Guides“作为例子,点击进去后,查看效果。
这个例子的链接是:
https://www.reportlab.com/casestudies/seychelles/www.reportlab.com/casestudies/seychelles/

这个例子真的是图文并茂,该有的要素一应俱全。
ReportLab功能这么强大。为了学会这个库,我们需要具备扎实的Python编程基础,同时按照我的教程,自己动手实践。
知识是一宝库,而实践就是开启宝库大门的钥匙。 — 富勒
ReportLab中包含的知识点非常多,为了方便大家快速掌握最常见的核心知识点,方便大家快速掌握最常用的核心知识点,我提炼出了最常用的80%的功能:Platypus、段落、表格和图片。
3.PLATYPUS
Platypus是“Page Layout and Typography Using Scripts”,是使用脚本的页面布局和印刷术的缩写,这是一个高层次页面布局库,它可以让你通过编程创造复杂的文档,并且毫不费力。
Platypus设计的目的是尽可能地将高层布局设计与文档内容分离,比如,段落使用段落格式构造,页面使用页面模板,这样做是有好处的,在仅仅修改几行代码的情况下,包含数百个页面的数百个文档就能够被构造成不同的风格。
Platypus从上到下,可以被看成具备多个层次。
DocTemplates:文档最外层的容器
PageTemplates:各种页面布局的规格
Frames:包含流动的文本和图形的文档区域规范
Flowables:能够被“流入文档”的文本、图形和段落等。

我们常常用DocTemplate、PageTemplates和Flowables来构建文档。
先看一个简单的例子,来见识下ReportLab的威力。
from reportlab.platypus import SimpleDocTemplate, Paragraphfrom reportlab.lib.styles import getSampleStyleSheet# 调用模板,创建指定名称的PDF文档doc = SimpleDocTemplate("Hello.pdf")# 获得模板表格styles = getSampleStyleSheet()# 指定模板style = styles['Normal']# 初始化内容story =[]# 将段落添加到内容中story.append(Paragraph("This is the first Document!",style))# 将内容输出到PDF中doc.build(story)
在这个Python文件的同目录下,生成一个文件名为”Hello.pdf“的文件,我们打开看看,执行结果如下:

4. 段落
段落是一种重要的Flowables,它可以格式化任意的文本。
段落中主要包括两种信息:文本和格式。
下面的语句可以用来创建一个段落的实例。
Paragraph(text, style)
text参数提供了段落的文本,末尾和换行处的空白都会被删除。
style参数用于设置段落的格式,这里段落的格式是指参数的集合,包括字体大小、行间距、首行缩进等参数。我们可以调用如下语句来获得默认段落格式。
from reportlab.lib.styles import ParagraphStyle
那ParagraphStyle中究竟包含哪些参数呢?
class ParagraphStyle(PropertySet):defaults = {'fontName':_baseFontName,'fontSize':10,'leading':12,'leftIndent':0,'rightIndent':0,'firstLineIndent':0,'alignment':TA_LEFT,'spaceBefore':0,'spaceAfter':0,'bulletFontName':_baseFontName,'bulletFontSize':10,'bulletIndent':0,#'bulletColor':black,'textColor': black,'backColor':None,'wordWrap':None, #None means do nothing special#CJK use Chinese Line breaking#LTR RTL use left to right / right to left#with support from pyfribi2 if available'borderWidth': 0,'borderPadding': 0,'borderColor': None,'borderRadius': None,'allowWidows': 1,'allowOrphans': 0,'textTransform':None, #uppercase lowercase (captitalize not yet) or None or absent'endDots':None, #dots on the last line of left/right justified paras#string or object with text and optional fontName, fontSize, textColor & backColor#dy'splitLongWords':1, #make best efforts to split long words'underlineWidth': _baseUnderlineWidth, #underline width'bulletAnchor': 'start', #where the bullet is anchored ie start, middle, end or numeric'justifyLastLine': 0, #n allow justification on the last line for more than n words 0 means don't bother'justifyBreaks': 0, #justify lines broken with <br/>'spaceShrinkage': _spaceShrinkage, #allow shrinkage of percentage of space to fit on line'strikeWidth': _baseStrikeWidth, #stroke width'underlineOffset': _baseUnderlineOffset, #fraction of fontsize to offset underlines'underlineGap': _baseUnderlineGap, #gap for double/triple underline'strikeOffset': _baseStrikeOffset, #fraction of fontsize to offset strikethrough'strikeGap': _baseStrikeGap, #gap for double/triple strike'linkUnderline': _platypus_link_underline,#'underlineColor': None,#'strikeColor': None,'hyphenationLang': _hyphenationLang,#'hyphenationMinWordLength': _hyphenationMinWordLength,'embeddedHyphenation': _embeddedHyphenation,'uriWasteReduce': _uriWasteReduce,}
我们选取几个重要的参数进行说明:
- fontName:字体名称
- fontSize:字体大小
- leading:行间距
- leftIndent:左缩进
- rightIndent:右缩进
- firstLineIndent:首行缩进
- alignment:对齐方式
- spaceBefore:段前间隙
- spaceAfter:段后间隙
- bulletFontName:列表名称
- bulletFontSize:列表字体大小
- bulletIndent:列表缩进
- textColor:字体颜色
- backColor:背景色
- borderWidth:边框粗细
- borderPadding:边框间距
- borderColor:边框颜色
ParagraphStyle是段落的默认格式,也就是在调用Paragraph(text, style)语句时,如果不传入style参数,默认的段落格式。
我们还有其他方式获得ReportLab提供的段落格式。
from reportlab.lib.styles import getSampleStyleSheetstylesheet=getSampleStyleSheet()normalStyle = stylesheet['Normal']
这里就是获得系统提供的Normal格式,其实Normal格式与ParagraphStyle是一模一样的,除了Normal格式,还可以获得其他的格式。
- Normal
- BodyText
- Italic
- Heading1
- Title
- Heading2
- Heading3
- Heading4
- Heading5
- Heading6
- Bullet
- Definition
- Code
- UnorderedList
- OrderedList
假如想要获得Title格式,我们只需要按照如下格式调用即可
from reportlab.lib.styles import getSampleStyleSheetstylesheet=getSampleStyleSheet()titleStyle = stylesheet['Title']
那这些格式究竟是效果?可以用两种方法验证,一是直接使用看效果,二是查看源代码。
比如Title的源代码:
stylesheet.add(ParagraphStyle(name='Title',parent=stylesheet['Normal'],fontName = _baseFontNameB,fontSize=18,leading=22,alignment=TA_CENTER,spaceAfter=6),alias='title')
可以看到,Title的效果是:字体18号;行间距22;对齐方式:居中;段落后间距:6。
5.表格
表格是Flowable的派生类,是一种简单文本表格机制。表格可以保存所有能被转换为字符串或Flowerable是所有事物。
如果我们不提供行高,它们可以根据数据自动计算出行高。
如果需要,它们可以跨页分割,你可以指定跨页分割后,需要重复的行数。
表格风格和表格数据是分离的,因此你可以声明一系列的风格,然后将它们用于一大堆报告。
表格使用如下代码进行创建:
Table(data, colWidths=None, rowHeights=None, style=None, splitByRow=1,repeatRows=0, repeatCols=0, rowSplitRange=None, spaceBefore=None,spaceAfter=None)
这里挑选几个关键参数进行讲解。
- data:数据参数是一系列的表格值,每个表格值能够被转换为字符串或者Flowable实例。data值的第一行是data[0],第i行j列表格值是data[i] [j]。
- colWidths:是一系列值,这些值代表每列的宽度。如果传递的是None,则对应列宽需要被自动计算。
- rowHeights:是一系列值,这些值代表每行的高度。如果传递的是None,则对应的行高需要被自动计算。
- style:表格被创建时的初始样式值。
- splitByRow:布尔值,当指定值为1时,允许跨页分割表格,当指定指为0时,不允许跨页分割表格。
- repeatRows:指定跨页分行时,需要重复的行数。
- repeatCols:暂时没用。
- spaceBefore:指定表格前的行数。
- spaceAfter:指定表格后的行数。
先来看个例子。
from reportlab.platypus import SimpleDocTemplate, Tablefrom reportlab.lib.styles import getSampleStyleSheet# 调用模板,创建指定名称的PDF文档doc = SimpleDocTemplate("Hello.pdf")# 获得模板表格styles = getSampleStyleSheet()# 指定模板style = styles['Normal']# 初始化内容story =[]# 初始化表格内容data= [['00', '01', '02', '03', '04'],['10', '11', '12', '13', '14'],['20', '21', '22', '23', '24'],['30', '31', '32', '33', '34']]# 根据内容创建表格t = Table(data)# 将表格添加到内容中story.append(t)# 将内容输出到PDF中doc.build(story)
执行结果是:

打开“Hello.pdf”,看到是一个无边框的表格。如果我们需要指定表格的显示方式呢?细看下一节的表格格式。
表格格式
指定表格格式有两种方式,一种是在调用创建表格接口时,传入style参数,一种是在创建完表格后,调用如下接口:
Table.setStyle(tblStyle)
直接传入style参数
from reportlab.platypus import SimpleDocTemplate, Tablefrom reportlab.lib import colorsfrom reportlab.lib.styles import getSampleStyleSheetdoc = SimpleDocTemplate("Hello.pdf")styles = getSampleStyleSheet()style = styles['Normal']story =[]data= [['00', '01', '02', '03', '04'],['10', '11', '12', '13', '14'],['20', '21', '22', '23', '24'],['30', '31', '32', '33', '34']]t=Table(data,style=[('GRID',(0,0),(-1,-1),1,colors.grey),('GRID',(1,1),(-2,-2),1,colors.green),('BOX',(0,0),(1,-1),2,colors.red),('BACKGROUND', (0, 0), (0, 1), colors.pink),('BACKGROUND', (1, 1), (1, 2), colors.lavender),('BACKGROUND', (2, 2), (2, 3), colors.orange),])story.append(t)doc.build(story)
查看执行结果:

调用setStyle
from reportlab.platypus import SimpleDocTemplate, Table, TableStylefrom reportlab.lib import colorsfrom reportlab.lib.styles import getSampleStyleSheetdoc = SimpleDocTemplate("Hello.pdf")styles = getSampleStyleSheet()style = styles['Normal']story =[]data= [['00', '01', '02', '03', '04'],['10', '11', '12', '13', '14'],['20', '21', '22', '23', '24'],['30', '31', '32', '33', '34']]t=Table(data)t.setStyle(TableStyle([('INNERGRID', (0,0), (-1,-1), 0.25, colors.black),('BOX', (0,0), (-1,-1), 2, colors.black),('LINEBELOW', (0,0), (-1,0), 2, colors.yellow),('LINEAFTER', (0,0), (0,-1), 2, colors.blue),('ALIGN', (1,1), (-1,-1), 'RIGHT')]))story.append(t)doc.build(story)
查看执行结果:

看到这里,小伙伴们可能一头雾水,这里需要补充基础知识。
表格的位置索引方式与列表的索引方式一致,即左上角第一个是data[0] [0],第二行第一个是data[1] [0],最后一行第一个位置是data[-1] [0],依次类推。
上面的例子中,列举了不少的表格格式化命令,这里将我知道的命令都列举完毕,方便大家学习掌握。
- FONTNAME:字体名称
- FONTSIZE:字体大小
- LEADING:行间距
- TEXTCOLOR:字体颜色
- ALIGNMENT:水平对齐方式(可选值:”LEFT”,”RIGHT“,”CENTER“)
- LEFTPADDING:左边填充
- RIGHTPADDING:右边填充
- BOTTOMPADDING:底部填充
- TOPPADDING:顶部填充
- BACKGROUND:背景色
- VALIGN:垂直对齐方式(可选值:”TOP”,“MIDDLE”,“BOTTOM”)
- GRID:表格颜色,被指定的行列中的所有子行和子列都被设置成相应颜色
- INNERGRID:表格颜色,仅仅修改指定的子行和子列的相应颜色(不包括边框)
- BOX:边框颜色,被指定的边框的颜色
- LINEBELOW:指定块底部的行颜色
- LINEAFTER:指定块右边的行颜色。
6.图片
图片的调用接口比较简单,在调用该接口时,支持默认的jpeg格式。接口如下:
Image(filename, width=None, height=None)
- filename:指定文件名
- width:指定图片的宽度
- height:指定图片的高度
如果宽度和高度有一个没有被指定,则参考原来的图片像素。
先举一个例子:
from reportlab.platypus import SimpleDocTemplate, Imagefrom reportlab.lib.styles import getSampleStyleSheetdoc = SimpleDocTemplate("Hello.pdf")styles = getSampleStyleSheet()style = styles['Normal']story =[]t = Image("C:\\Users\\Administrator\\Desktop\\timg.jpg")story.append(t)doc.build(story)
打开指定的PDF文件,查看效果如下:

后记:本文介绍了ReportLab中最常用的4个功能:Platypus、段落、表格和图片。
在使用过程中,还会遇到很多问题,比如在使用中文时,需要首先注册字体等问题,需要大家自己摸索,当然也可以留言一起讨论哦。
中文问题
https://www.jianshu.com/p/41284e4e25f5
用reportlab生成pdf文件,碰到中文就会变成黑色的小方块,如下图。
解决方法
1.下载中文字体SimSun.ttf
2.把下载下来的字体放到/Library/Python/2.7/site-packages/reportlab/fonts文件夹下。(文件夹根据自己安装的reportlab的路径来)
3.注册字体并使用
from reportlab.platypus import SimpleDocTemplate, Image, Paragraphfrom reportlab.lib.styles import getSampleStyleSheet, ParagraphStylefrom reportlab.pdfbase import pdfmetricsfrom reportlab.pdfbase.ttfonts import TTFontpdfmetrics.registerFont(TTFont('SimSun', 'SimSun.ttf')) #注册字体styles = getSampleStyleSheet()styles.add(ParagraphStyle(fontName='SimSun', name='Song', leading=20, fontSize=12)) #自己增加新注册的字体Paragraph(describe, styles['Song']), #使用新字体
还有文字换行问题,暂时用了下面的方式
Paragraph(u'<br/>%s<br/>' % describe, styles['Song'])
参考
https://zhaobugs.com/2018/07/09/%E4%BD%BF%E7%94%A8Python%E7%94%9F%E6%88%90PDF-reportlab%E7%AF%87/
