如何在pytest中mock HTML文件内链接的请求?
解决HTML转PDF时Mock外部链接请求无效的问题
requests_mock只拦截基于requests库发起的HTTP请求,但绝大多数HTML转PDF工具(比如pdfkit/wkhtmltopdf、WeasyPrint、Pyppeteer)都是用自身底层的网络模块处理请求,完全不依赖requests,所以你的mock代码根本拦截不到这些请求,自然无效。
根据你使用的PDF渲染工具,对应以下解决方案:
1. 使用pdfkit/wkhtmltopdf
wkhtmltopdf自带参数可以直接禁用或替换外部链接:
- 禁用所有外部请求(最简单,适合你不需要响应内容的场景):
import pdfkit options = { 'disable-external-links': None # wkhtmltopdf的无值参数用None表示 } pdfkit.from_file('your.html', 'output.pdf', options=options) - 替换指定链接的内容(如果需要自定义mock内容):
import pdfkit options = { 'replace': 'https://example.com=<div>Mocked Content</div>' } pdfkit.from_file('your.html', 'output.pdf', options=options)
2. 使用WeasyPrint
WeasyPrint支持自定义URL fetcher,直接替换请求逻辑:
from weasyprint import HTML def mock_url_fetcher(url): if url == 'https://example.com': # 返回自定义的mock响应 return { 'content': b'<html><body>Mocked Content</body></html>', 'mime_type': 'text/html', 'encoding': 'utf-8' } # 其他未mock的请求可以直接抛出异常或忽略 raise ValueError(f"Unmocked URL: {url}") # 传入自定义fetcher渲染PDF html = HTML(filename='your.html', url_fetcher=mock_url_fetcher) html.write_pdf('output.pdf')
3. 使用Pyppeteer/Playwright
这类基于浏览器的工具可以直接拦截页面网络请求:
Pyppeteer示例
import asyncio from pyppeteer import launch async def render_mocked_pdf(): browser = await launch() page = await browser.newPage() # 开启请求拦截 await page.setRequestInterception(True) async def intercept_request(req): if req.url == 'https://example.com': # 返回mock响应 await req.respond({ 'status': 200, 'contentType': 'text/html', 'body': '<div>Mocked Content</div>' }) else: # 其他请求正常处理 await req.continue_() page.on('request', intercept_request) # 加载本地HTML文件(需传入绝对路径) await page.goto('file:///absolute/path/to/your.html') await page.pdf(path='output.pdf') await browser.close() asyncio.run(render_mocked_pdf())
内容的提问来源于stack exchange,提问作者user13267766
相关产品推荐
相关产品推荐

