Windows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallCrashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteWith WeasyPrint, load a remote stylesheet by creating CSS(url="https://…") and passing that object in the stylesheets list to HTML.write_pdf(). If your HTML is a string, also provide base_url so relative images, fonts, and other resources resolve correctly.
The basic WeasyPrint pattern
WeasyPrint documents two separate inputs: the HTML document and one or more stylesheet objects. A stylesheet can be constructed from a URL, and the resulting object is supplied to write_pdf.
from weasyprint import HTML, CSS
html = HTML(
string="""
<html>
<body>
<h1>Invoice</h1>
<p>Thank you for your order.</p>
</body>
</html>
""",
base_url="https://example.com/",
)
css = CSS(url="https://example.com/static/pdf.css")
html.write_pdf("output.pdf", stylesheets=[css])
The call to CSS(url=...) tells WeasyPrint to fetch the stylesheet through its URL fetcher. Passing the object in stylesheets makes it part of the PDF render. Replace both example URLs with endpoints that are reachable from the machine running Python.
Choose the input form that matches your document
HTML already hosted at a URL
If the page itself is remote and already contains a normal linked stylesheet, use the page URL directly:
Free tools Windows power users keep installed
One-click scans. No signup required.
#1 Best Overall
from weasyprint import HTML, CSS
HTML(url="https://example.com/invoice/42").write_pdf(
"invoice.pdf",
stylesheets=[CSS(url="https://example.com/static/pdf-overrides.css")],
)
The page’s own linked CSS is discovered as part of loading the document. The additional stylesheet is useful for print-specific overrides or for rules that should apply only to this export.
HTML assembled in Python
Use HTML(string=...) when a template, database record, or generated markup supplies the document. In this form, there is no natural document location, so set base_url whenever the HTML contains relative URLs.
Command-line conversion
The WeasyPrint command-line interface accepts a stylesheet URL or filename with -s or --stylesheet. Use -u or --base-url to establish the base for relative references. The CLI also exposes controls for timeout, allowed protocols, redirect behavior, and whether HTTP errors should fail the command; check the options installed with your version before relying on a version-specific flag.
weasyprint
--stylesheet https://example.com/static/pdf.css
--base-url https://example.com/
input.html output.pdf
Make relative URLs resolve predictably
There are two URL-resolution contexts to account for:
Rank #2
- URLs in the HTML: images, fonts, links, and other relative references resolve against the document’s base URL. For string input, provide
base_urlor rewrite those references as absolute URLs. - URLs in the CSS: declarations such as
background-image: url("../images/pattern.png")resolve relative to the stylesheet’s own location. Supplying an absolute URL toCSS(url=...)gives that stylesheet a meaningful origin.
For example, if pdf.css is at https://example.com/static/pdf.css, a relative font URL in that file is resolved from the /static/ directory. Setting base_url on the HTML does not change the CSS file’s own base.
from weasyprint import HTML, CSS
html = HTML(
string="""
<html>
<head><title>Statement</title></head>
<body>
<img src="images/logo.svg" alt="Company logo">
<h1>Statement</h1>
</body>
</html>
""",
base_url="https://example.com/account/",
)
css = CSS(url="https://cdn.example.com/pdf/pdf.css")
html.write_pdf("statement.pdf", stylesheets=[css])
Here, the logo is resolved below https://example.com/account/, while any relative asset referenced by pdf.css is resolved below https://cdn.example.com/pdf/.
When the stylesheet needs cookies or authentication
WeasyPrint’s default fetcher can open file and HTTP URLs, but its HTTP client does not provide advanced features such as cookies or authentication. If the CSS endpoint is protected, pass a custom URL fetcher to HTML or CSS.
A custom fetcher is a function that receives a URL, adds the credentials or headers required by your service, downloads the resource, and returns the resource data in the structure expected by WeasyPrint. For URLs that do not need special treatment, delegate to the default fetcher. Keep credentials in environment variables rather than embedding them in HTML or source code.
Recommended Free Tools
import os
import requests
from weasyprint import HTML, CSS, default_url_fetcher
TOKEN = os.environ["PDF_CSS_TOKEN"]
def fetch_url(url):
if url == "https://private.example.com/pdf.css":
response = requests.get(
url,
headers={"Authorization": f"Bearer {TOKEN}"},
timeout=20,
)
response.raise_for_status()
return {
"string": response.content,
"mime_type": "text/css",
"redirected_url": response.url,
}
return default_url_fetcher(url)
html = HTML(
string="<html><body><h1>Private report</h1></body></html>",
base_url="https://example.com/",
url_fetcher=fetch_url,
)
css = CSS(
url="https://private.example.com/pdf.css",
url_fetcher=fetch_url,
)
html.write_pdf("private-report.pdf", stylesheets=[css])
Check the API reference for the exact fetcher return fields and exception classes in your installed release. The important design is to use the custom fetcher for the protected URL and the default fetcher everywhere else. Also account for authentication on assets referenced by the stylesheet; a public CSS file can still point at private fonts or images.
Decide whether a failed CSS fetch should stop the job
By default, fetch errors are caught and reported as warnings, so a PDF may be produced without a missing stylesheet. That behavior is convenient for best-effort documents but dangerous when the CSS controls page size, branding, or legal formatting.
For a mandatory stylesheet, make the custom fetcher detect its failure and raise WeasyPrint’s fatal URL-fetching error rather than returning an incomplete resource. This converts a silent visual defect into an explicit failed job that your application can retry or report. Apply the same policy to other required assets if a partially rendered PDF is unacceptable.
Network and security checks
Verify access from the renderer
- Confirm DNS resolution and outbound HTTP(S) access from the worker or container, not only from your laptop.
- Check TLS certificates, redirects, and the final URL returned by the server.
- Make sure the stylesheet response is actually CSS and is not a login page, bot challenge, or error document.
- Set a finite fetch timeout so a stalled origin cannot hold a PDF worker indefinitely.
Restrict untrusted documents
Rendering untrusted HTML and CSS in a web application is security-sensitive. User-controlled markup can reference unexpected network locations or local files. Restrict reachable protocols and hosts, isolate the renderer where appropriate, and apply the allowed-protocol and related controls exposed by your installed WeasyPrint release. Do not allow arbitrary user input to choose internal URLs.
Quick wins for a faster PC:
Scan for outdated or missing drivers - takes under a minuteDriver Scan →Clear out junk files and repair common Windows errorsFree Scan →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Common failures and fixes
| Symptom | Likely cause | Fix |
|---|---|---|
| The PDF has no CSS styling | The CSS object was created but not passed to stylesheets, or the URL returned an error. |
Pass stylesheets=[CSS(url="...")], inspect warnings, and request the URL from the rendering host. |
| Images or fonts disappear | Relative URLs have no base, or assets are blocked by authentication or network policy. | Set base_url for string HTML, use absolute asset URLs where practical, and add a custom fetcher for protected resources. |
| Rendering hangs | A remote server, redirect, or asset is taking too long to respond. | Configure a fetch timeout, limit redirects as appropriate, and test each remote dependency independently. |
| Only some pages fail | The stylesheet or one of its imports is intermittently unavailable. | Log the requested URL and response status, retry transient failures, and make critical CSS failures fatal. |
| CSS works in a browser but not in the PDF | The browser supplied cookies, headers, or capabilities that the default fetcher does not. | Use a custom URL fetcher, simplify the resource chain, and verify that the CSS and its assets are reachable without browser-only state. |
| A local file is unexpectedly readable | An untrusted document can reach local resources through a permissive protocol policy. | Restrict allowed protocols and resource hosts, and isolate the rendering process. |
Performance and repeatability
Each uncached remote stylesheet and asset adds network latency to a render. Keep the CSS dependency graph small, serve assets from reliable origins, and avoid making a PDF depend on resources that change during a single job. If you generate many documents, reuse stable templates and measure fetch time separately from layout time so a slow origin is visible in your job metrics.
For deterministic output, pin the stylesheet URL to a versioned resource or deploy a controlled copy. A mutable URL can produce different PDFs from identical HTML. If you must use a live URL, record the resolved URL and response metadata with the job so a later reproduction can identify which CSS was used.
Input-shape comparison
| Situation | Recommended form | Important setting |
|---|---|---|
| Remote page already links its CSS | HTML(url="...") |
Add stylesheets only for extra overrides. |
| Generated HTML plus public remote CSS | HTML(string=...) and CSS(url=...) |
Set base_url for relative HTML resources. |
| Protected CSS or assets | HTML/CSS with a custom URL fetcher | Supply headers, cookies, or authorization in the fetcher. |
| Shell-based conversion | WeasyPrint CLI | Use --stylesheet and --base-url; verify flags for your installed version. |
Or skip the browser setup
If your actual requirement is to capture a rendered website or produce a PDF of a public page rather than assemble a Python document, ScreenshotNeo provides a single HTTP request. It accepts consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each step can be disabled. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and the response identifies the result with X-Page-Verdict and X-Billed headers. It can return PNG, JPEG, WebP, or PDF.
For Python PDF generation, WeasyPrint remains the direct solution above. ScreenshotNeo is the shortcut when a URL is the source and you do not want to operate a browser-rendering setup. Its MCP server also exposes take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients.
The Tool Desk
Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
Python:
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)
Node.js:
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
See the ScreenshotNeo API documentation for options including full-page lazy-image loading, CSS-selector element capture, dark mode, device presets, arbitrary viewports, retina scale, PDF paper size and margins, custom CSS or JavaScript, clicks, hidden selectors, selector or network-idle waits, request blocking, headers, cookies, user agents, authorization, timezone, geolocation, transparent backgrounds, resizing, TTL caching, signed image links, asynchronous webhooks, bulk capture of up to 100 URLs per call, usage reporting, and the OpenAPI specification. Parameter names used by other screenshot APIs also work for easier migration.
Best Value
| Plan | Included screenshots | Price |
|---|---|---|
| Free | 1,000 per month | $0, no card |
| Starter | 3,000 | $5 |
| Growth | 15,000 | $15 |
| Pro | 60,000 | $39 |
| Scale | 250,000 | $99 |
| Business | 1,000,000 | $249 |
Every feature is included on every plan, and yearly billing provides two months free. Create a free ScreenshotNeo account to use 1,000 screenshots a month with no card; paid plans start at $5 for 3,000.
Frequently Asked Questions
Does this technique apply to every Python PDF library?
No. The CSS(url=...) and stylesheets pattern is the documented WeasyPrint API; another library may require a different renderer or resource-loading configuration.
Can I pass more than one remote stylesheet?
Yes. Create a CSS object for each URL and pass the objects in the desired order in the stylesheets list. Later rules can override earlier rules when normal CSS specificity and cascade rules permit.
Why does a missing stylesheet sometimes produce a PDF instead of an exception?
WeasyPrint normally catches URL-fetching failures and emits warnings. If the stylesheet is mandatory, use a custom fetcher that raises a fatal URL-fetching error for that resource.
Quick Recap
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.

