October DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsClean PCRecommendedOne scan can reveal what keeps slowing WindowsLook for cleanup and repair opportunities.Run ScanOctober DealsAmazon USDeal season is back - check today's better picksAmazon US: current deals, useful picks and tech finds.See Picks×
Skip to content
HTML

Convert an HTML File to PDF with Python (WeasyPrint Guide)

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Use WeasyPrint to convert a local HTML file to a PDF in Python. Install it in the environment that will run your script, then pass the file to HTML and call write_pdf:

from weasyprint import HTML

HTML(filename="input.html").write_pdf("output.pdf")

This creates output.pdf beside your script (unless you provide another path). The rest of this guide covers installation, relative assets, print CSS, security, batch conversion, troubleshooting, and an API alternative when you do not want to manage a browser or rendering environment.

1. Install WeasyPrint in the right Python environment

Install the package with the interpreter that will execute your conversion code:

python -m pip install weasyprint

The current WeasyPrint 70.0 documentation lists Python 3.10 or newer, Pango 1.44 or newer, and additional Python and native dependencies. On Linux, the distribution package can be the simplest route. If pip installation fails, check the operating-system installation instructions and confirm that the required native libraries are available.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Verify the environment before converting:

python --version
weasyprint --info

Run these commands inside the same virtual environment, container, or deployment image used by your application. Dependency requirements can change, so consult the current WeasyPrint installation documentation for your operating system and record the versions you deploy.

2. Convert one local HTML file

Minimal script

from weasyprint import HTML

HTML(filename="input.html").write_pdf("output.pdf")

The filename can also be supplied positionally, as in HTML("input.html"). Using filename= makes the source explicit and is easier to extend when you later add options.

Use absolute paths when the working directory is uncertain

from pathlib import Path
from weasyprint import HTML

source = Path("/srv/reports/input.html").resolve()
target = Path("/srv/reports/output.pdf").resolve()
HTML(filename=str(source)).write_pdf(str(target))
print(f"Wrote {target}")

Resolve paths deliberately in web workers, scheduled jobs, and containers: a process’s current directory may not be the directory containing your Python file.

3. Make CSS, images, and fonts resolve correctly

An HTML document often references styles.css, images, or fonts with relative URLs. Keep the source file and its asset tree together, use correct relative references, and inspect the PDF rather than assuming that a browser-like environment will find every resource.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
<link rel="stylesheet" href="css/print.css">
<img src="images/logo.png" alt="Company logo">

For a document at /app/report/input.html, the paths above point to /app/report/css/print.css and /app/report/images/logo.png. If assets are generated, write them before calling write_pdf. For remote resources, ensure the rendering environment can reach them and that authentication, certificates, and firewall rules permit access. The official documentation confirms filename input, but does not guarantee every possible relative-resource arrangement; test your actual layout.

Use print-specific CSS

@media print {
  .screen-only { display: none; }
  a { color: black; text-decoration: none; }
}

@page {
  size: A4;
  margin: 18mm 16mm;
}

h1, h2 { break-after: avoid; }

Print CSS controls pagination and removes controls that make sense only on screen. Test long tables, headings near page bottoms, images, fonts, and page breaks with representative documents.

4. Convert HTML held in a string

When your application generates markup instead of reading a file, pass the string to HTML(string=...) and provide a base_url that lets relative assets resolve:

from pathlib import Path
from weasyprint import HTML

html = """
<!doctype html>
<html><head>
  <link rel="stylesheet" href="css/print.css">
</head><body>
  <h1>Monthly report</h1>
  <p>Generated by Python.</p>
</body></html>
"""

HTML(string=html, base_url=str(Path("/srv/reports").resolve())).write_pdf(
    "/srv/reports/monthly-report.pdf"
)

Without a suitable base URL, a relative stylesheet or image may not be found. Sanitize or template generated HTML according to your application’s trust model.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

5. What WeasyPrint supports—and where it stops

WeasyPrint is an HTML/CSS-to-PDF renderer, not a promise that every arbitrary web page will look exactly like it does in Chrome or Firefox. Its documentation states that generated-document validity is not guaranteed for every combination of HTML, CSS, and PDF features; the features you use must fit the specifications and the implementation’s limits. Validate a representative output before committing to a layout.

The API reference lists hyperlinks, bookmarks, attachments, forms, text, raster graphics, and vector graphics among content that PDFs can contain. That is a capability description, not a guarantee that every source document transfers perfectly. JavaScript-driven pages may need to be rendered to static HTML first, because this workflow does not establish browser-level execution of arbitrary client-side code.

6. Security for untrusted HTML and CSS

The WeasyPrint first-steps documentation warns: “Using WeasyPrint with untrusted HTML or untrusted CSS may lead to various security problems.” Treat user-submitted markup as hostile. Run conversion in an isolated worker or container, restrict network access and filesystem visibility, limit document size and conversion time, and control which URLs or resource types can be fetched. Do not expose a conversion endpoint that can freely read local files or reach internal services.

For trusted, internally generated reports, still validate URLs and resource paths. Log failures without including secrets embedded in URLs or headers.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

7. Convert many files efficiently

For repeated conversions, keep a long-lived Python process instead of starting a fresh interpreter for every document. The WeasyPrint documentation identifies this as a way to avoid paying startup costs on each conversion; it does not establish a quantified speed improvement.

from pathlib import Path
from weasyprint import HTML

input_dir = Path("reports/html")
output_dir = Path("reports/pdf")
output_dir.mkdir(parents=True, exist_ok=True)

for source in input_dir.glob("*.html"):
    destination = output_dir / f"{source.stem}.pdf"
    HTML(filename=str(source)).write_pdf(str(destination))
    print(f"{source.name} -> {destination.name}")

For production queues, add bounded concurrency, per-document timeouts at the worker layer, retries only for transient resource failures, and output checks such as file existence and a nonzero size. Do not run unlimited conversions in one process without monitoring memory and disk use.

8. Troubleshooting common failures

ModuleNotFoundError: No module named 'weasyprint'

Your script is using a different interpreter from the one where you installed the package. Run python -m pip install weasyprint with that interpreter, activate the intended virtual environment, and check python -c "import weasyprint; print(weasyprint.__version__)".

Native-library or Pango errors

Install the operating-system dependencies listed for your platform in the current WeasyPrint installation guide. Confirm Pango is at least the version required by the documentation, then rerun weasyprint --info.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Missing images, CSS, or fonts

Check the spelling and case of every path, the process working directory, and the document’s base URL. Prefer absolute, known-good paths while diagnosing. Confirm that the worker can read local files and reach approved remote resources.

Blank or incomplete pages

Open the generated PDF and inspect the HTML independently. Look for invalid markup, CSS that hides content in print, external resources that time out, and oversized elements that cannot fit the page. Reduce the document to a small reproduction, then add styles and assets back incrementally.

Layout differs from the browser

Check print media rules and unsupported CSS features. Replace fragile screen-only layout with print-oriented styles, explicit page sizes and margins, and tested page-break rules. Do not claim pixel-perfect browser parity without validating the exact documents you produce.

Conversion is slow or consumes too much memory

Reduce unnecessary remote assets, resize very large images, split exceptionally large documents, and reuse a long-lived worker. Measure your own workload; the available documentation supplies no universal timing or memory figure.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

9. A hosted option when you do not want browser setup

Or skip the browser setup:

If your real input is a publicly reachable web page rather than a local file, ScreenshotNeo can return a screenshot or PDF through one request. It accepts cookie and consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed. Its MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. Every response identifies the page verdict and billing status with X-Page-Verdict and X-Billed headers.

See the complete parameter list in the ScreenshotNeo documentation. The same endpoint supports full-page capture with lazy images, CSS-selector elements, dark mode, device presets or custom viewports, retina scale, PDF paper size, margins, landscape mode and page ranges, custom CSS and JavaScript, clicks, waits, blocking rules, headers, cookies, user agents, authorization, timezone, geolocation, transparent backgrounds, resizing, chosen cache TTLs, signed links, asynchronous webhooks, bulk capture of up to 100 URLs per call, usage reporting, and an OpenAPI specification.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

The Free plan includes 1,000 shots per month with no card. Paid plans start at $5 for 3,000 shots; yearly billing provides two months free, and every feature is included on every plan. Sign up free for ScreenshotNeo.

10. Practical validation checklist

  • Install and verify WeasyPrint in the deployment environment.
  • Convert a representative HTML file and open the PDF.
  • Check page size, margins, page breaks, fonts, images, links, and bookmarks where relevant.
  • Test missing or slow resources and decide how your worker handles them.
  • Isolate untrusted HTML/CSS and restrict filesystem and network access.
  • For batch jobs, reuse a long-lived process and monitor resource consumption.

Frequently Asked Questions

Can I convert an HTML file without installing a browser?

Yes. WeasyPrint renders HTML/CSS directly from Python and its documented minimal call is HTML(filename="input.html").write_pdf("output.pdf"). You still need WeasyPrint’s Python and native dependencies.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Why does my PDF not match Chrome exactly?

WeasyPrint has its own HTML/CSS implementation and documented limits. Use print CSS and validate the exact layouts, fonts, assets, and page breaks your application generates.

Is WeasyPrint safe for user-uploaded HTML?

Not by default. The project warns that untrusted HTML or CSS can create security problems. Isolate conversion, restrict resources, and enforce size and time limits.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Leave a Reply

Your email address will not be published. Required fields are marked *

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Read next

Recommended PC Tool
Recommended PC Tool
Outdated Drivers Are Slowing You DownFree scan - exact matches
Windows Errors? Fix Them Before They SpreadFree repair scan

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.