杰瑞科技汇

Python Bottle如何处理PDF文件?

Of course! Using Python with the Bottle web framework to generate and serve PDFs is a common task. The best and most standard way to do this is by using the ReportLab library to create the PDF content dynamically.

Python Bottle如何处理PDF文件?-图1
(图片来源网络,侵删)

Here’s a complete guide covering:

  1. The Scenario: A simple web page with a button to generate a PDF report.
  2. Setup: Installing the necessary libraries.
  3. Backend (Bottle + ReportLab): The Python code to generate the PDF and send it to the browser.
  4. Frontend (HTML/JS): The user interface.
  5. Alternative: Serving a pre-existing PDF file.

The Scenario

We'll build a simple web application with one page:

  • : Displays a welcome message and a "Generate PDF Report" button.
  • /generate_pdf: A hidden URL that our button will call. This route will generate a PDF in memory and send it to the browser for download.

Setup

First, you need to install Bottle and ReportLab. You can do this using pip:

pip install bottle reportlab

Backend (Bottle + ReportLab)

This is the core of our application. We'll create a Python script that sets up the Bottle server and defines our routes.

Python Bottle如何处理PDF文件?-图2
(图片来源网络,侵删)

The key to this is using Python's io module to create the PDF in memory (a BytesIO object) instead of writing it to a file on the disk. This is much more efficient for web applications.

Create a file named app.py:

import bottle
from bottle import route, run, static_file, response
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import letter
from reportlab.lib.units import inch
from io import BytesIO
# --- Route for the main page ---
@route('/')
def index():
    """Serves the main HTML page."""
    return '''
    <h1>Welcome to the PDF Generator!</h1>
    <p>Click the button below to generate a PDF report.</p>
    <button onclick="generatePDF()">Generate PDF Report</button>
    '''
# --- Route to generate and serve the PDF ---
@route('/generate_pdf')
def generate_pdf():
    """
    Generates a PDF in memory and sends it to the browser for download.
    """
    # 1. Create a BytesIO buffer to hold the PDF in memory
    buffer = BytesIO()
    # 2. Create a canvas object to draw on the PDF
    p = canvas.Canvas(buffer, pagesize=letter)
    width, height = letter
    # 3. Draw content on the PDF
    # You can add text, images, tables, etc.
    p.setFont("Helvetica-Bold", 24)
    p.drawString(inch, height - inch, "Sales Report")
    p.setFont("Helvetica", 12)
    p.drawString(inch, height - 2 * inch, "This report was dynamically generated.")
    p.drawString(inch, height - 2.5 * inch, "Date: 2025-10-27")
    # Draw a simple line
    p.line(inch, height - 3 * inch, width - inch, height - 3 * inch)
    # Add some sample data
    data = [
        ("Product A", 150),
        ("Product B", 200),
        ("Product C", 75),
    ]
    y = height - 4 * inch
    p.drawString(inch, y, "Product")
    p.drawString(3 * inch, y, "Sales")
    y -= 0.5 * inch
    for product, sales in data:
        p.drawString(inch, y, product)
        p.drawString(3 * inch, y, f"${sales}")
        y -= 0.5 * inch
    # 4. Close the canvas and save the PDF to the buffer
    p.save()
    # 5. Get the value of the buffer and rewind it
    pdf_data = buffer.getvalue()
    buffer.close()
    # 6. Set the HTTP response headers
    # - Content-Type: 'application/pdf' tells the browser it's a PDF.
    # - Content-Disposition: 'attachment' prompts a "Save As" dialog.
    #   The 'filename=' parameter suggests a default name for the file.
    response.content_type = 'application/pdf'
    response.headers['Content-Disposition'] = 'attachment; filename="report.pdf"'
    # 7. Return the PDF data as the response body
    return pdf_data
# --- To run the application ---
if __name__ == '__main__':
    # Use reloader=True for development to restart the server on code changes
    run(host='localhost', port=8080, reloader=True)

Code Breakdown:

  1. BytesIO(): Creates an in-memory binary stream. It acts like a file, but it doesn't touch your disk.
  2. canvas.Canvas(buffer, ...): We tell ReportLab to draw our PDF onto our in-memory buffer.
  3. p.drawString(...), p.line(...): These are ReportLab functions for drawing content. You can get very creative here, adding tables, charts, images, etc.
  4. p.save(): Finalizes the PDF document and writes it to the buffer.
  5. buffer.getvalue(): Retrieves the raw bytes of the PDF from the buffer.
  6. response.content_type = 'application/pdf': This is a critical header. It tells the browser how to interpret the data it's receiving. Without it, the browser might try to display the raw PDF code as text.
  7. response.headers['Content-Disposition'] = 'attachment; ...': This header tells the browser to treat the response as a file to be downloaded, rather than a page to be displayed. The filename="report.pdf" part is what appears in the "Save As..." dialog.

Frontend (HTML/JS)

The frontend is very simple. We have a button that, when clicked, makes a GET request to our /generate_pdf route. The browser will then handle the response according to the headers we set.

Python Bottle如何处理PDF文件?-图3
(图片来源网络,侵删)

The app.py already includes the HTML for the main page, but here it is again for clarity. You could also save this as index.html and use Bottle's static_file route to serve it.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">PDF Generator App</title>
    <style>
        body { font-family: sans-serif; text-align: center; margin-top: 50px; }
        button { padding: 10px 20px; font-size: 16px; cursor: pointer; }
    </style>
</head>
<body>
    <h1>Welcome to the PDF Generator!</h1>
    <p>Click the button below to generate a PDF report.</p>
    <!-- This button calls our backend route -->
    <button onclick="window.location.href='/generate_pdf'">Generate PDF Report</button>
</body>
</html>

How to Run and Test

  1. Save the Python code as app.py.
  2. Open your terminal or command prompt.
  3. Navigate to the directory where you saved app.py.
  4. Run the script: python app.py
  5. You will see output like this: Bottle server starting up (using WSGIRefServer)... Listening on http://localhost:8080/
  6. Open your web browser and go to http://localhost:8080.
  7. You should see the welcome page. Click the "Generate PDF Report" button.
  8. Your browser should prompt you to download a file named report.pdf. Open it, and you'll see the dynamically generated content!

Alternative: Serving a Pre-existing PDF File

Sometimes, you don't need to generate the PDF on the fly; you just need to serve a file that already exists. For this, Bottle's static_file route is perfect.

Let's say you have a PDF file named my_document.pdf in a folder named static.

  1. Project Structure:

    /my_project
    |-- app.py
    |-- /static
        |-- my_document.pdf
  2. app.py Code:

    import bottle
    from bottle import route, run, static_file, response
    # Route for the main page
    @route('/')
    def index():
        return '''
        <h1>PDF File Server</h1>
        <p><a href="/download_pdf">Click here to download my_document.pdf</a></p>
        '''
    # Route to serve a static file
    @route('/download_pdf')
    def download_pdf():
        # The 'root' argument is the path to the directory containing the file.
        # The 'filename' is the name of the file to serve.
        # The 'download' argument prompts a "Save As" dialog.
        return static_file('my_document.pdf', root='static', download=True)
    if __name__ == '__main__':
        run(host='localhost', port=8080, reloader=True)

This approach is simpler and more efficient if the PDF content doesn't change. The download=True argument conveniently sets the Content-Disposition header for you.

分享:
扫描分享到社交APP
上一篇
下一篇