使用Python在AWS Lambda中将含图片表格的HTML转为PDF并上传S3
我之前也遇到过类似的问题,在Lambda里折腾FPDF、pdfKit确实容易踩坑——要么依赖的系统库缺失,要么对复杂HTML(比如带表格、图片)的支持不够。给你几个亲测有效的方案,既能搞定HTML转PDF,又能直接上传到S3:
方案1:WeasyPrint + Lambda层(轻量且稳定)
WeasyPrint对HTML/CSS的支持很完善,能很好处理表格和图片,而且体积比Chrome小很多。核心是要把它的依赖打包成Lambda层,解决环境缺失的问题。
步骤:
制作Lambda层:
- 用和Lambda同架构的环境(比如Amazon Linux 2 EC2实例,或者本地用Docker模拟
amazonlinux:2镜像),安装WeasyPrint及其系统依赖:yum install -y gcc python3-devel cairo-devel pango-devel gdk-pixbuf2-devel pip3 install weasyprint -t python/lib/python3.9/site-packages/ - 把
python目录打包成zip,上传到Lambda作为层。
- 用和Lambda同架构的环境(比如Amazon Linux 2 EC2实例,或者本地用Docker模拟
Lambda函数代码:
import weasyprint import boto3 from io import BytesIO import os def lambda_handler(event, context): # 从event获取HTML内容,或者从S3读取HTML文件 html_content = event.get("html_content", "") # 生成PDF到内存缓冲区 pdf_buffer = BytesIO() # 如果HTML里有本地图片,可以转成base64嵌入,或者确保Lambda能访问图片URL weasyprint.HTML(string=html_content).write_pdf(pdf_buffer) pdf_buffer.seek(0) # 上传到S3 s3_client = boto3.client("s3") s3_client.put_object( Bucket=os.environ["S3_BUCKET_NAME"], Key=f"generated_pdfs/{context.aws_request_id}.pdf", Body=pdf_buffer, ContentType="application/pdf" ) return { "statusCode": 200, "body": f"PDF已上传至S3:s3://{os.environ['S3_BUCKET_NAME']}/generated_pdfs/{context.aws_request_id}.pdf" }
方案2:Headless Chrome(pyppeteer) + Lambda层(完美还原网页样式)
如果你的HTML有复杂的JS交互或者CSS动画,pyppeteer(Python版Puppeteer)会更合适,它模拟真实Chrome渲染,生成的PDF和网页几乎一致。
步骤:
添加Chrome Lambda层:
可以直接使用社区维护的Chrome层(包含Chrome二进制文件和依赖),或者自己打包适配Lambda环境的Chrome资源。Lambda函数代码:
import asyncio import pyppeteer import boto3 from io import BytesIO import os async def render_html_to_pdf(html_content): # 启动无头Chrome browser = await pyppeteer.launch( headless=True, args=["--no-sandbox", "--disable-dev-shm-usage", "--single-process"] ) page = await browser.newPage() # 设置页面内容,支持加载外部图片、CSS await page.setContent(html_content, waitUntil="networkidle0") # 生成PDF,printBackground=True确保背景图/颜色正常显示 pdf_bytes = await page.pdf(format="A4", printBackground=True) await browser.close() return pdf_bytes def lambda_handler(event, context): html_content = event.get("html_content", "") # 运行异步生成PDF的逻辑 loop = asyncio.get_event_loop() pdf_bytes = loop.run_until_complete(render_html_to_pdf(html_content)) # 上传到S3 s3_client = boto3.client("s3") s3_client.put_object( Bucket=os.environ["S3_BUCKET_NAME"], Key=f"generated_pdfs/{context.aws_request_id}.pdf", Body=BytesIO(pdf_bytes), ContentType="application/pdf" ) return { "statusCode": 200, "body": f"PDF已上传至S3:s3://{os.environ['S3_BUCKET_NAME']}/generated_pdfs/{context.aws_request_id}.pdf" }
关键注意事项
- 图片资源处理:如果HTML里的图片是本地文件,建议转成base64嵌入HTML;如果是远程URL,要确保Lambda有访问该URL的权限(比如配置VPC互联网访问、添加对应权限)。
- Lambda配置调整:生成PDF需要一定资源,建议把Lambda内存调到1024MB以上,超时时间设置为30秒(根据PDF大小灵活调整)。
- 权限设置:给Lambda的IAM角色添加S3上传权限,确保能读写目标S3存储桶。
内容的提问来源于stack exchange,提问作者yasir kk
相关产品推荐
相关产品推荐

