Tự động hóa báo cáo PDF với ReportLab: Giải pháp chuyên nghiệp cho Developer

Python tutorial - IT technology blog
Python tutorial - IT technology blog

Tại sao bạn nên ngừng làm báo cáo thủ công?

Copy dữ liệu từ Excel, dán vào Word, rồi hì hục căn chỉnh lề để xuất PDF là quy trình cực kỳ lãng phí thời gian. Mình từng mất cả buổi sáng chỉ để làm một bản báo cáo doanh số, và chỉ cần sai một con số là phải làm lại từ đầu.

Nếu bạn đã dùng Python để crawl dữ liệu hay chạy script automation, việc xuất báo cáo cũng nên được tự động hóa. ReportLab chính là chìa khóa giúp bạn giải quyết bài toán này một cách triệt để.

Khác với các thư viện convert HTML sang PDF thường bị lỗi định dạng, ReportLab cho phép bạn “vẽ” trực tiếp lên trang giấy. Bạn có quyền kiểm soát tuyệt đối từng pixel. Thư viện này cực kỳ phù hợp để tạo hóa đơn, chứng từ hoặc các báo cáo phân tích dữ liệu yêu cầu độ chính xác cao.

Cài đặt môi trường

Chỉ mất chưa đầy 10 giây để cài đặt ReportLab qua pip. Để hỗ trợ tốt nhất cho việc vẽ biểu đồ và xử lý hình ảnh, bạn nên cài đặt thêm thư viện Pillow đi kèm:

pip install reportlab pillow

Lưu ý quan trọng: ReportLab mặc định không hiểu tiếng Việt Unicode. Nếu không cấu hình font, các chữ có dấu sẽ hiển thị thành những ô vuông lỗi. Bạn cần chuẩn bị sẵn một file font .ttf (ví dụ: Arial hoặc Roboto) trong thư mục dự án để tích hợp vào code.

Cấu hình thành phần cốt lõi

ReportLab cung cấp hai cách tiếp cận: Canvas (vẽ thủ công theo tọa độ x, y) và Platypus (bộ khung layout cao cấp). Mình khuyên bạn nên dùng Platypus. Nó hoạt động giống như việc xếp các khối nội dung, tự động tính toán việc ngắt trang khi dữ liệu quá dài.

1. Xử lý Font tiếng Việt và Style

Bước đầu tiên là đăng ký font chữ để báo cáo hiển thị chuẩn xác. Đây là công đoạn giúp bạn tránh được 99% lỗi hiển thị phổ biến nhất.

from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_CENTER

# Đăng ký font để hiển thị tiếng Việt
try:
    pdfmetrics.registerFont(TTFont('Arial', 'arial.ttf'))
except:
    print("Lỗi: Không tìm thấy file arial.ttf. Hãy kiểm tra lại thư mục!")

styles = getSampleStyleSheet()
title_style = ParagraphStyle(
    'CustomTitle',
    parent=styles['Heading1'],
    fontName='Arial',
    fontSize=20,
    alignment=TA_CENTER,
    spaceAfter=30
)

2. Xây dựng bảng biểu (Tables) linh hoạt

Bảng biểu là phần quan trọng nhất của mọi báo cáo. Với TableStyle, bạn có thể định dạng màu sắc, kẻ khung và căn lề chuyên nghiệp không thua kém gì Excel.

from reportlab.platypus import Table, TableStyle
from reportlab.lib import colors

# Dữ liệu mẫu cho báo cáo
data = [
    ['STT', 'Sản phẩm', 'Số lượng', 'Doanh thu'],
    ['1', 'Phần mềm quản lý', '50', '5.000$'],
    ['2', 'Khóa học Python', '120', '12.000$'],
    ['3', 'Dịch vụ Cloud', '30', '3.000$'],
]

table = Table(data, colWidths=[40, 180, 80, 100])
table.setStyle(TableStyle([
    ('BACKGROUND', (0, 0), (-1, 0), colors.dodgerblue),
    ('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke),
    ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
    ('FONTNAME', (0, 0), (-1, -1), 'Arial'),
    ('GRID', (0, 0), (-1, -1), 0.5, colors.grey),
    ('BOTTOMPADDING', (0, 0), (-1, 0), 10),
]))

3. Vẽ biểu đồ Vector sắc nét

Thay vì chèn ảnh bitmap dễ bị vỡ hạt, hãy dùng module graphics của ReportLab. Biểu đồ sẽ được vẽ dưới dạng vector, dung lượng nhẹ và cực kỳ sắc nét khi in ấn.

from reportlab.graphics.shapes import Drawing
from reportlab.graphics.charts.barcharts import VerticalBarChart

def create_chart():
    drawing = Drawing(400, 200)
    bc = VerticalBarChart()
    bc.x = 50
    bc.y = 50
    bc.height = 125
    bc.width = 300
    bc.data = [(50, 120, 30)]
    bc.categoryAxis.categoryNames = ['Sản phẩm A', 'Sản phẩm B', 'Sản phẩm C']
    bc.valueAxis.valueMin = 0
    bc.valueAxis.valueMax = 150
    drawing.add(bc)
    return drawing

Hoàn thiện script xuất PDF

Bây giờ, chúng ta sẽ lắp ghép các mảnh ghép lại thành một quy trình hoàn chỉnh. Bạn có thể tái sử dụng template này cho nhiều dự án khác nhau.

from reportlab.lib.pagesizes import A4
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer

def export_pdf(filename):
    doc = SimpleDocTemplate(filename, pagesize=A4)
    elements = []

    # Thêm tiêu đề và nội dung
    elements.append(Paragraph("BÁO CÁO KẾT QUẢ KINH DOANH", title_style))
    elements.append(Spacer(1, 15))
    
    body_style = ParagraphStyle('Body', fontName='Arial', fontSize=12)
    elements.append(Paragraph("Dữ liệu tổng hợp tính đến cuối tháng:", body_style))
    elements.append(Spacer(1, 20))

    # Chèn bảng và biểu đồ đã tạo
    elements.append(table)
    elements.append(Spacer(1, 30))
    elements.append(create_chart())

    doc.build(elements)
    print(f"Thành công! File đã lưu tại: {filename}")

if __name__ == "__main__":
    export_pdf("Bao_Cao_Thang.pdf")

Kinh nghiệm thực tế khi triển khai

Để hệ thống chạy ổn định trong môi trường thực tế (production), bạn nên lưu ý 3 điểm sau:

  • Quản lý File: Luôn sử dụng try...except khi ghi file. Nếu file PDF đang mở bởi một ứng dụng khác, script sẽ bị crash ngay lập tức.
  • Tối ưu ảnh: Nếu báo cáo có chèn ảnh logo hay avatar, hãy resize về đúng kích thước cần hiển thị. Điều này giúp giảm dung lượng file từ vài MB xuống còn vài chục KB.
  • Tự động hóa hoàn toàn: Kết hợp script này với một công cụ lập lịch (như Cron job hoặc APScheduler). Hệ thống có thể tự động gửi báo cáo vào 8h sáng thứ Hai hàng tuần mà không cần bạn can thiệp.

Làm chủ ReportLab giúp bạn giải phóng bản thân khỏi những công việc lặp lại nhàm chán. Dù việc căn chỉnh ban đầu hơi mất thời gian, nhưng thành quả nhận được là một quy trình chuyên nghiệp, chính xác và tốc độ.

Share: