You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

无需无头模式,求Selenium截取超长元素完整截图的JS方案

纯JavaScript实现超长元素截图方案

实现思路

通过浏览器原生Canvas API,逐段滚动目标元素并将可视区域内容绘制到画布,最终拼接成完整长图。无需依赖pyautogui、cv2或浏览器插件,可直接在undetectedChromeDriver中执行。

完整实现代码

结合undetectedChromeDriver的Python调用代码

from undetected_chromedriver import Chrome
import base64

def save_long_element_screenshot(driver, element_selector, save_path='long_screenshot.png'):
    # 执行内嵌的JavaScript截图逻辑
    screenshot_base64 = driver.execute_script("""
        async function captureLongElement(selector) {
            const el = document.querySelector(selector);
            if (!el) throw new Error('目标元素未找到');
            
            const fullW = el.scrollWidth;
            const fullH = el.scrollHeight;
            const viewportH = window.innerHeight;
            const elRect = el.getBoundingClientRect();
            
            // 创建对应尺寸的画布
            const canvas = document.createElement('canvas');
            canvas.width = fullW;
            canvas.height = fullH;
            const ctx = canvas.getContext('2d');
            
            // 保存原始滚动位置
            const origScrollTop = window.scrollY;
            const origScrollLeft = window.scrollX;
            
            try {
                let currentY = 0;
                while (currentY < fullH) {
                    // 计算需要滚动到的位置
                    const scrollToY = Math.min(currentY + viewportH, fullH) - viewportH;
                    window.scrollTo(origScrollLeft, scrollToY + elRect.top);
                    
                    // 等待滚动渲染完成
                    await new Promise(res => setTimeout(res, 150));
                    
                    // 创建临时画布截取当前视口内的元素片段
                    const tempCanvas = document.createElement('canvas');
                    tempCanvas.width = fullW;
                    tempCanvas.height = Math.min(viewportH, fullH - currentY);
                    const tempCtx = tempCanvas.getContext('2d');
                    
                    // 绘制当前视口内的元素部分
                    tempCtx.drawWindow(
                        window,
                        elRect.left,
                        scrollToY + elRect.top,
                        fullW,
                        Math.min(viewportH, fullH - currentY),
                        'white'
                    );
                    
                    // 将片段拼接到主画布
                    ctx.drawImage(tempCanvas, 0, currentY);
                    currentY += viewportH;
                }
                
                // 恢复原始滚动位置
                window.scrollTo(origScrollLeft, origScrollTop);
                return canvas.toDataURL('image/png');
            } catch (err) {
                window.scrollTo(origScrollLeft, origScrollTop);
                throw err;
            }
        }
        return captureLongElement(arguments[0]);
    """, element_selector)
    
    # 解码Base64并保存图片
    if screenshot_base64.startswith('data:image/png;base64,'):
        img_data = base64.b64decode(screenshot_base64.split(',')[1])
        with open(save_path, 'wb') as f:
            f.write(img_data)
        print(f"截图已保存到: {save_path}")
    else:
        print("截图失败,返回数据格式错误")

# 使用示例
if __name__ == '__main__':
    driver = Chrome()
    driver.get('你的目标网站URL')
    
    # 等待元素加载(根据实际情况调整等待策略)
    driver.implicitly_wait(10)
    
    # 传入目标元素的CSS选择器,如body、#target-id、.target-class
    save_long_element_screenshot(driver, 'body', 'full_page.png')
    
    driver.quit()

关键说明

  • 选择器替换:将element_selector替换为你需要截取的元素的CSS选择器,确保能准确定位目标元素。
  • 等待时间调整:如果页面滚动后元素渲染较慢,可延长setTimeout的时间(当前为150ms)。
  • 兼容性处理:部分网站可能限制drawWindowAPI,若遇到问题,可尝试改为直接绘制元素(需确保元素片段在视口内完全可见):
    // 替换drawWindow部分
    tempCtx.drawImage(el, 0, scrollToY, fullW, Math.min(viewportH, fullH - currentY), 0, 0, fullW, Math.min(viewportH, fullH - currentY));
    
  • 加载等待:建议使用显式等待(如WebDriverWait)替代隐式等待,确保目标元素完全加载后再执行截图。

内容的提问来源于stack exchange,提问作者Kerem

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 14:12:26