Python使用Reportlabs生成多页全页运输标签的代码优化方案咨询
问题描述
我是ReportLab的新手,想要生成如下样式的全页运输标签:
目前我已经写出了可以实现需求的代码,但写法不够简洁高效:
import datetime from reportlab.lib import colors from reportlab.lib.pagesizes import letter from reportlab.pdfgen import canvas year = datetime.date.today().year # IIRNumber = str(int(input("Month (digit): "))) + "-" + str(int(input("Shipment Number (include zero if before 10): "))) # VMBENumber = "VBME-" + str(year)[-2:] + "-" + str(int(input("Enter VBME Number (last four digits: "))) # PONUmber = input("Enter PO number or V for Various: ") IIRNumber = "08-09" VMBENumber = "VBME-21-1458" PONUmber = "9185555" ShipmentNumber = int(input("How many pieces in the shipment?: ")) print(VMBENumber) print(IIRNumber) print(ShipmentNumber) def textobject_demo(): my_canvas = canvas.Canvas("PDFGenerated.pdf", pagesize=letter) # Create text_object text_object = my_canvas.beginText() # Set text location (x, y) # Write a line of text + carriage return # Set font face and size text_object.setFont('Times-Roman', 12) text_object.setTextOrigin(150, 730) for i in range(1, ShipmentNumber + 1): # Write text to the canvas text_object.textLine(text="") text_object.textLine(text="") text_object.textLine(text="") text_object.textLine(text="") text_object.textLine(text='To: Voisey Bay Mine Site – EXPANSION PROJECT (VBME)') text_object.textLine(text="") text_object.textLine(text="") text_object.textLine(text="") text_object.textLine(text=" C/O Innu Mikun Hangar") text_object.textLine(text=" Happy Valley-Goose Bay, NL") text_object.textLine(text="") text_object.textLine(text="") text_object.textLine(text="") text_object.textLine(text="") text_object.textLine(text="") text_object.textLine(text=" CC0012- " + VMBENumber + " - " + IIRNumber) text_object.textLine(text=" Product Description:" + PONUmber) text_object.textLine(text="") text_object.textLine(text="") text_object.textLine(text="") text_object.textLine(text="") text_object.textLine(text=" Box " + str(i) + " of " + str(ShipmentNumber)) text_object.textLine(text=" Gross Weight: 14 lbs") text_object.textLine(text=" Net Weight: 14 lbs") text_object.textLine(text="") text_object.textLine(text="") text_object.textLine(text="") text_object.textLine(text="") text_object.textLine(text="") text_object.textLine(text=" Dimensions: 9 L x 9 W x 9” H") text_object.textLine(text="") text_object.textLine(text="") text_object.textLine(text="") text_object.textLine(text="") text_object.textLine(text=" Special Storage Instruction: NO") text_object.textLine(text="") text_object.textLine(text="") text_object.textLine(text="") text_object.textLine(text="") text_object.textLine(text=" Attn: IIR – REDPATH Canada Limited") text_object.textLine(text=" Underground Garage ATTN: Mark / Shawn") text_object.textLine(text="") my_canvas.drawText(text_object) my_canvas.showPage() my_canvas.save() if __name__ == '__main__': textobject_demo()
我希望优化现有实现逻辑,替代原先逐页复制粘贴信息的操作,实现批量生成运输标签的流程,请问有没有更优的实现方式?
优化方案
核心优化逻辑如下:
- 把所有可变参数(运单编号、PO号、重量尺寸等)抽离出来,后续修改或批量传参不需要改动模板逻辑
- 用模板字符串统一管理标签的全部内容,包括空行、缩进,替代原来手动写大量
textLine("")的操作,调整排版更方便 - 把字体、坐标、页尺寸这类样式参数统一设为全局常量,后续改样式不需要翻代码找对应位置
- 每页单独生成文本对象,避免多页循环时出现坐标偏移的问题
- 核心生成逻辑拆分为单页生成和批量生成两个函数,支持多批运单数据一次性生成全量标签
优化后代码如下:
import datetime from reportlab.lib.pagesizes import letter from reportlab.pdfgen import canvas # --------------- 全局样式常量 --------------- FONT_NAME = "Times-Roman" FONT_SIZE = 12 TEXT_ORIGIN_X = 150 TEXT_ORIGIN_Y = 730 PAGE_SIZE = letter OUTPUT_PATH = "运输标签.pdf" # --------------- 标签模板 --------------- LABEL_TEMPLATE = """ To: Voisey Bay Mine Site – EXPANSION PROJECT (VBME) C/O Innu Mikun Hangar Happy Valley-Goose Bay, NL CC0012- {vmbe_number} - {iir_number} Product Description: {po_number} Box {current_box} of {total_box} Gross Weight: {gross_weight} lbs Net Weight: {net_weight} lbs Dimensions: {dimensions} Special Storage Instruction: {storage_instruction} Attn: IIR – REDPATH Canada Limited Underground Garage ATTN: Mark / Shawn """ def generate_single_label(canvas, label_data): """生成单页运输标签""" text_obj = canvas.beginText() text_obj.setFont(FONT_NAME, FONT_SIZE) text_obj.setTextOrigin(TEXT_ORIGIN_X, TEXT_ORIGIN_Y) # 填充模板内容 label_content = LABEL_TEMPLATE.format(**label_data) # 按行写入 for line in label_content.split('\n'): text_obj.textLine(line) canvas.drawText(text_obj) canvas.showPage() def batch_generate_labels(label_data_list): """批量生成运输标签""" my_canvas = canvas.Canvas(OUTPUT_PATH, pagesize=PAGE_SIZE) for data in label_data_list: generate_single_label(my_canvas, data) my_canvas.save() if __name__ == '__main__': year = datetime.date.today().year # 示例输入,可替换为从Excel/表单批量读取数据 IIRNumber = "08-09" VMBENumber = "VBME-21-1458" PONUmber = "9185555" ShipmentNumber = int(input("请输入货物总件数: ")) # 组装单批运单的所有箱子标签数据 label_list = [] for i in range(1, ShipmentNumber+1): label_data = { "vmbe_number": VMBENumber, "iir_number": IIRNumber, "po_number": PONUmber, "current_box": i, "total_box": ShipmentNumber, "gross_weight": 14, "net_weight": 14, "dimensions": "9 L x 9 W x 9” H", "storage_instruction": "NO" } label_list.append(label_data) # 如果有多批运单,继续往label_list里加数据即可 batch_generate_labels(label_list)
使用说明
- 样式调整:如果需要改字体、字号、标签起始位置,直接修改顶部的全局常量即可
- 排版调整:如果需要改标签的文字内容、空行、缩进,直接修改
LABEL_TEMPLATE里的文本即可,和最终输出效果完全对应 - 批量生成:如果需要批量生成多批不同的运单标签,只需要把所有运单的数据按照指定格式组装成字典,加入
label_list即可,支持对接Excel、数据库等数据源批量导入 - 输入逻辑:原来的交互式输入可以保留,也可以替换成从数据源批量读取的逻辑,不需要改动生成标签的核心代码
内容的提问来源于stack exchange,提问作者littlejiver
相关产品推荐
相关产品推荐

