SSkilltecabyclaudinhocode
Enviar skill
← Voltar para o catálogo

html-to-pdf

Documentos

将远程HTML网页转换为本地PDF文件,支持身份验证、自定义请求头、JavaScript渲染和CSS样式。支持单页转换和完整文档转换(自动爬取侧边栏所有子页面)。当用户需要下载网页为PDF、转换HTML到PDF、保存网页内容为文档、或提到完整文档/所有章节时使用。

1estrelas
Ver no GitHub ↗Autor: jamesxjzLicença: MIT

HTML转PDF转换

将远程HTML网页转换为本地PDF文件,完全控制渲染选项。支持两种模式:

转换模式选择

重要:首先判断用户需要哪种模式:

  1. 单页模式 - 用户只提到"转换这个网页"、"单个页面"
  2. 完整文档模式 - 用户提到"所有章节"、"完整文档"、"包含所有页面"、"侧边栏所有链接"

快速开始

单页转换流程

  1. 判断HTML源的复杂度(静态页面 vs JavaScript重度页面)
  2. 选择合适的库
  3. 如需要,处理身份验证/请求头
  4. 配置PDF输出选项
  5. 保存到本地文件

完整文档转换流程

  1. 访问文档首页
  2. 真实爬取侧边栏所有链接(不要猜测URL!)
  3. 等待JavaScript加载完成(至少10-15秒)
  4. 提取所有文档链接
  5. 逐个转换每个页面
  6. 合并成单个PDF文件

库选择指南

根据页面需求选择:

最适合核心特性
Playwright现代Web应用、单页应用、JavaScript重度页面完整浏览器自动化、JS执行、截图
WeasyPrint静态HTML、CSS样式页面纯Python、优秀的CSS支持、无外部依赖
pdfkit通用场景、混合内容wkhtmltopdf封装、良好兼容性

默认推荐:优先使用Playwright,可靠性和功能完整性最好。

基础转换

使用 Playwright(推荐)

from playwright.sync_api import sync_playwright

def html转pdf(网址, 输出路径, **选项):
    with sync_playwright() as p:
        浏览器 = p.chromium.launch()
        页面 = 浏览器.new_page()
        页面.goto(网址)
        页面.pdf(path=输出路径, **选项)
        浏览器.close()

# 示例
html转pdf("https://example.com", "输出.pdf")

使用 WeasyPrint(静态HTML)

from weasyprint import HTML

def html转pdf(网址, 输出路径):
    HTML(网址).write_pdf(输出路径)

# 示例
html转pdf("https://example.com", "输出.pdf")

高级功能

身份验证与请求头

# Playwright带自定义请求头
def html转pdf带认证(网址, 输出路径, 请求头=None):
    with sync_playwright() as p:
        浏览器 = p.chromium.launch()
        上下文 = 浏览器.new_context(extra_http_headers=请求头 or {})
        页面 = 上下文.new_page()
        页面.goto(网址)
        页面.pdf(path=输出路径)
        浏览器.close()

# 带身份验证的示例
请求头 = {
    "Authorization": "Bearer 你的令牌",
    "User-Agent": "自定义User Agent"
}
html转pdf带认证("https://example.com", "输出.pdf", 请求头)

等待JavaScript渲染

# 等待特定内容加载
def html转pdf带等待(网址, 输出路径, 选择器=None, 超时时间=30000):
    with sync_playwright() as p:
        浏览器 = p.chromium.launch()
        页面 = 浏览器.new_page()
        页面.goto(网址, wait_until="networkidle")
        
        if 选择器:
            页面.wait_for_selector(选择器, timeout=超时时间)
        
        页面.pdf(path=输出路径)
        浏览器.close()

# 等待特定元素
html转pdf带等待("https://example.com", "输出.pdf", 选择器="#content")

PDF格式化选项

# 完全控制PDF输出
def html转pdf格式化(网址, 输出路径):
    with sync_playwright() as p:
        浏览器 = p.chromium.launch()
        页面 = 浏览器.new_page()
        页面.goto(网址)
        页面.pdf(
            path=输出路径,
            format="A4",                    # 纸张大小
            print_background=True,          # 包含背景图形
            margin={                        # 页边距
                "top": "20mm",
                "right": "20mm",
                "bottom": "20mm",
                "left": "20mm"
            },
            display_header_footer=True,     # 显示页眉/页脚
            header_template="<div style='font-size:10px; text-align:center; width:100%;'>我的页眉</div>",
            footer_template="<div style='font-size:10px; text-align:center; width:100%;'>第 <span class='pageNumber'></span> 页,共 <span class='totalPages'></span> 页</div>",
            prefer_css_page_size=False,     # 使用format而非CSS
            landscape=False                 # 纵向方向
        )
        浏览器.close()

常见工作流

单页转换

from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    浏览器 = p.chromium.launch()
    页面 = 浏览器.new_page()
    页面.goto("https://example.com")
    页面.pdf(path="输出.pdf", format="A4", print_background=True)
    浏览器.close()

批量转换

def 批量html转pdf(网址列表, 输出目录):
    with sync_playwright() as p:
        浏览器 = p.chromium.launch()
        for i, 网址 in enumerate(网址列表):
            页面 = 浏览器.new_page()
            页面.goto(网址)
            输出路径 = f"{输出目录}/页面_{i+1}.pdf"
            页面.pdf(path=输出路径)
            页面.close()
        浏览器.close()

# 转换多个页面
网址列表 = ["https://example.com/page1", "https://example.com/page2"]
批量html转pdf(网址列表, "./pdfs")

使用自定义CSS转换

def html转pdf带css(网址, 输出路径, 自定义css=None):
    with sync_playwright() as p:
        浏览器 = p.chromium.launch()
        页面 = 浏览器.new_page()
        页面.goto(网址)
        
        # 注入自定义CSS
        if 自定义css:
            页面.add_style_tag(content=自定义css)
        
        页面.pdf(path=输出路径)
        浏览器.close()

# 转换前隐藏元素
自定义css = """
    .advertisement { display: none !important; }
    .navigation { display: none !important; }
"""
html转pdf带css("https://example.com", "输出.pdf", 自定义css)

错误处理

始终处理常见错误:

def 安全html转pdf(网址, 输出路径):
    try:
        with sync_playwright() as p:
            浏览器 = p.chromium.launch()
            页面 = 浏览器.new_page()
            
            # 设置超时和错误处理
            页面.set_default_timeout(30000)
            响应 = 页面.goto(网址)
            
            if 响应.status != 200:
                raise Exception(f"HTTP {响应.status}: 加载页面失败")
            
            页面.pdf(path=输出路径)
            浏览器.close()
            return True
            
    except Exception as e:
        print(f"转换错误 {网址}: {str(e)}")
        return False

安装要求

向用户说明所需的包:

Playwright(推荐,单页和完整文档都需要)

pip install playwright
playwright install chromium

PyPDF2(仅完整文档模式需要,用于合并PDF)

pip install PyPDF2

WeasyPrint(可选,静态HTML单页转换)

pip install weasyprint

pdfkit(可选,备选方案)

pip install pdfkit
# 还需要在系统上安装wkhtmltopdf

决策树

根据用户需求选择转换模式:

第1步:判断转换模式

用户说了什么?

  • "转换这个网页" / "把这个URL转成PDF" / "单个页面" → 使用单页模式

  • "所有章节" / "完整文档" / "包含侧边栏所有页面" / "包含所有子页面" → 使用完整文档模式

第2步:选择库(单页模式)

  1. 是否需要执行JavaScript?

    • 是 → 使用Playwright
    • 否 → 继续步骤2
  2. 页面是否需要身份验证或自定义请求头?

    • 是 → 使用Playwright
    • 否 → 继续步骤3
  3. 是否为带CSS样式的静态HTML?

    • 是 → 使用WeasyPrint(更快、更轻)
    • 否 → 使用Playwright(最安全的默认选择)

第3步:完整文档模式的关键点

必须遵守的规则

  1. ⚠️ 绝对不要猜测URL路径!

    • ❌ 错误:假设路径是 /docs/agent/pane
    • ✅ 正确:从页面上真实提取链接
  2. ⚠️ 必须等待JavaScript加载!

    • ❌ 错误:立即提取(只能找到2-3个链接)
    • ✅ 正确:等待10-15秒后提取(能找到50+个链接)
  3. ⚠️ 使用 page.evaluate() 提取链接!

    • ✅ 在浏览器上下文中运行JavaScript
    • ✅ 能获取动态渲染的内容
  4. ⚠️ 需要安装 PyPDF2 来合并!

    • 如果未安装:pip install PyPDF2

完整文档模式的详细实现

import time

# 步骤1:真实提取导航链接
def 提取所有文档链接(页面, 首页url):
    """
    关键:真实爬取,不猜测!
    """
    页面.goto(首页url, timeout=60000)
    
    # 重要!等待足够长的时间
    time.sleep(15)
    
    # 使用JavaScript提取所有链接
    链接数据 = 页面.evaluate("""
        () => {
            const links = Array.from(document.querySelectorAll('a'));
            return links.map(a => ({
                text: a.textContent.trim(),
                href: a.href
            })).filter(l => l.text && l.href.includes('/docs/'));
        }
    """)
    
    # 去重
    唯一链接 = {}
    for 项 in 链接数据:
        url = 项['href']
        if url not in 唯一链接:
            唯一链接[url] = 项['text']
    
    return [(标题, url) for url, 标题 in 唯一链接.items()]

# 步骤2:批量转换
def 批量转换并合并(文档列表, 输出文件):
    """
    转换所有页面并合并
    """
    from PyPDF2 import PdfMerger
    import tempfile
    
    临时目录 = tempfile.mkdtemp()
    pdf文件列表 = []
    
    with sync_playwright() as p:
        浏览器 = p.chromium.launch()
        页面 = 浏览器.new_page()
        
        for i, (标题, url) in enumerate(文档列表, 1):
            try:
                页面.goto(url, wait_until="domcontentloaded", timeout=30000)
                time.sleep(1)
                
                # 隐藏导航
                页面.add_style_tag(content="nav, header, .sidebar { display: none !important; }")
                
                pdf路径 = os.path.join(临时目录, f"{i:03d}.pdf")
                页面.pdf(path=pdf路径, format="A4", print_background=True)
                pdf文件列表.append(pdf路径)
                
            except:
                pass
        
        浏览器.close()
    
    # 合并
    merger = PdfMerger()
    for pdf in pdf文件列表:
        merger.append(pdf)
    merger.write(输出文件)
    merger.close()
    
    # 清理
    import shutil
    shutil.rmtree(临时目录)

常见问题与解决方案

单页转换问题

问题:PDF为空白或不完整

  • 解决方案:添加 wait_until="networkidle" 或等待特定选择器

问题:需要身份验证

  • 解决方案:使用 extra_http_headers 或带cookies的浏览器上下文

问题:背景图形缺失

  • 解决方案:在PDF选项中设置 print_background=True

问题:页面布局错乱

  • 解决方案:设置合适的 `format

Como adicionar

/plugin marketplace add jamesxjz/html-to-pdf-agent-skill

O comando exato pode variar conforme o repositório. Confira o README no GitHub.

Comentários · Nenhum comentário

Entre para comentar. Entrar

  • Ainda não há comentários. Seja o primeiro.