前端代码渲染截图方案

1、pip安装依赖

bash 复制代码
pip install playwright
playwright install chromium

2、apt安装其他依赖

bash 复制代码
sudo apt update && sudo apt install -y libgbm1  libgbm1 libasound2 libxkbcommon0 libcups2 libdrm2 libxdamage1 libpango-1.0-0

3、支持中文字体

bash 复制代码
sudo apt install fonts-wqy-microhei fonts-wqy-zenhei fonts-noto-cjk

注意:和html的字体并不是完全一样,可以进一步优化

4、完整代码

bash 复制代码
from playwright.sync_api import sync_playwright

def html_to_image_sync(html_file_path, output_image_path):
    """同步版本的HTML转图片"""
    with sync_playwright() as p:
        browser = p.chromium.launch(headless=True)
        page = browser.new_page()
        
        # 设置更长的超时时间
        page.set_default_timeout(60000)  # 60秒超时
        
        page.set_viewport_size({"width": 375, "height": 600})

        with open(html_file_path, 'r', encoding='utf-8') as file:
            html_content = file.read()

        try:
            # 使用domcontentloaded而不是默认的load,加载更快
            page.set_content(html_content, wait_until="domcontentloaded", timeout=60000)
            
            # 可选:等待特定元素加载完成
            # page.wait_for_selector('.fund-card', timeout=2000)
            
            page.screenshot(path=output_image_path, full_page=True)
            print(f"截图成功: {output_image_path}")
            
        except Exception as e:
            print(f"截图失败: {e}")
        
        finally:
            browser.close()

# 使用同步版本
html_to_image_sync("0010-gemini3.html", "0010-gemini3.png")

建议:可以将图片宽度放大为375的倍数,不然看起来分辨率太小,不清晰

截图效果(+-图片没有加载出来):

html效果:

5、优化代码(图标需要转base64)

bash 复制代码
from playwright.sync_api import sync_playwright
import base64

def html_to_image_sync(html_file_path, output_image_path):
    """优化版本的HTML转图片"""
    with sync_playwright() as p:
        # 启动浏览器,添加网络优化参数
        browser = p.chromium.launch(
            headless=True,
            args=[
                '--disable-web-security',
                '--disable-features=VizDisplayCompositor',
                '--disable-background-timer-throttling',
                '--disable-renderer-backgrounding',
                '--aggressive-cache-discard',
                '--max_old_space_size=4096'
            ]
        )
        
        # 创建页面上下文,设置网络超时
        context = browser.new_context(
            viewport={"width": 375, "height": 600},
            ignore_https_errors=True
        )
        
        page = context.new_page()
        page.set_default_timeout(45000)  # 45秒超时
        page.set_default_navigation_timeout(45000)

        try:
            with open(html_file_path, 'r', encoding='utf-8') as file:
                html_content = file.read()
            
            print("读取HTML文件成功,开始处理外部资源...")
            
            # 方案1: 替换外部图片为base64内联图片
            html_content = replace_external_images_with_base64(html_content)
            
            # 方案2: 或者使用本地SVG图标替换
            # html_content = replace_with_svg_icons(html_content)
            
            print("设置页面内容...")
            # 使用commit而不是domcontentloaded,更快
            page.set_content(html_content, wait_until="commit", timeout=30000)
            
            # 等待字体和样式加载完成
            print("等待页面渲染...")
            page.wait_for_timeout(2000)  # 等待2秒确保CSS应用
            
            # 检查关键元素是否渲染
            try:
                page.wait_for_selector('.fund-card', timeout=5000)
                print("关键元素加载成功")
            except:
                print("关键元素加载超时,继续截图...")
            
            page.screenshot(path=output_image_path, full_page=True, timeout=15000)
            
        except Exception as e:
            print(f"主流程失败: {e}")
        
        finally:
            browser.close()

def replace_external_images_with_base64(html_content):
    """将外部图片替换为base64编码的内联图片"""
    # 简单的加号SVG(灰色)
    plus_svg = '''<svg width="24" height="24" xmlns="http://www.w3.org/2000/svg">
        <path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z" fill="#cccccc"/>
    </svg>'''
    
    # 简单的减号SVG(灰色)
    minus_svg = '''<svg width="24" height="24" xmlns="http://www.w3.org/2000/svg">
        <path d="M19 13H5v-2h14v2z" fill="#cccccc"/>
    </svg>'''
    
    # 刷新图标SVG
    refresh_svg = '''<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg">
        <path d="M12.8 5.2A6 6 0 0 0 8 2a6 6 0 1 0 4.8 9.6" stroke="#999" stroke-width="1.5" fill="none"/>
        <path d="M12 4l2.8-2.8v4" stroke="#999" stroke-width="1.5" fill="none" stroke-linecap="round"/>
    </svg>'''
    
    # 将SVG转换为base64
    def svg_to_base64(svg_content):
        return "data:image/svg+xml;base64," + base64.b64encode(svg_content.encode('utf-8')).decode('utf-8')
    
    # 替换图片URL
    replacements = {
        'https://img.icons8.com/material-rounded/24/cccccc/plus-math.png': svg_to_base64(plus_svg),
        'https://img.icons8.com/material-rounded/24/cccccc/minus-math.png': svg_to_base64(minus_svg),
        'https://img.icons8.com/ios/50/999999/refresh--v1.png': svg_to_base64(refresh_svg)
    }
    
    for old_url, new_data in replacements.items():
        html_content = html_content.replace(old_url, new_data)
    
    return html_content

def replace_with_svg_icons(html_content):
    """直接使用内联SVG替换img标签"""
    # 加号SVG
    plus_svg = '''<svg width="12" height="12" viewBox="0 0 24 24" fill="#cccccc">
        <path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
    </svg>'''
    
    # 减号SVG  
    minus_svg = '''<svg width="12" height="12" viewBox="0 0 24 24" fill="#cccccc">
        <path d="M19 13H5v-2h14v2z"/>
    </svg>'''
    
    # 刷新SVG
    refresh_svg = '''<svg width="16" height="16" viewBox="0 0 50 50" fill="#999999">
        <path d="M25 10c-8.3 0-15 6.7-15 15s6.7 15 15 15 15-6.7 15-15-6.7-15-15-15zm0 28c-7.2 0-13-5.8-13-13s5.8-13 13-13 13 5.8 13 13-5.8 13-13 13z"/>
        <path d="M25 16l-5 5 5 5 5-5-5-5z"/>
    </svg>'''
    
    # 直接替换整个img标签
    html_content = html_content.replace(
        '',
        refresh_svg
    )
    
    html_content = html_content.replace(
        '',
        plus_svg
    )
    
    html_content = html_content.replace(
        '', 
        minus_svg
    )
    
    return html_content

# 使用优化版本
html_to_image_sync("0010-gemini3.html", "0010-gemini3.png")

截图效果:

图标并不是完全一样。这里是自行生成的。需要解决

相关推荐
xkxnq2 小时前
第二阶段:Vue 组件化开发(第 21天)
前端·javascript·vue.js
阿珊和她的猫2 小时前
深入理解 React 中的 Render Props 模式
前端·react.js·状态模式
IT_陈寒3 小时前
SpringBoot 3.0实战:10个高效开发技巧让你的启动时间减少50%
前端·人工智能·后端
im_AMBER3 小时前
前端 + agent 开发学习路线
前端·学习·agent
亿坊电商3 小时前
利于SEO优化的CMS系统都有哪些特点?
前端·数据库
juejin_cn3 小时前
使用 Codex SDK 轻松实现文字控制电脑
前端
CUYG3 小时前
Moment.js常用
前端
用户81274828151203 小时前
漏学Input知识系列之“偷”走了其他窗口的事件pilferPointers
前端
用户81274828151203 小时前
安卓14自由窗口圆角处理之绘制圆角轮廓线
前端