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

Tampermonkey脚本下载Canvas图片文件损坏 手动运行正常如何解决

问题根因

你遇到的核心差异来自运行时机:你手动在控制台运行脚本时,页面的Canvas绘制逻辑已经完全执行完毕,而Tampermonkey的document-idle、jQuery的ready事件都只代表DOM树加载完成,画廊页面的图片资源加载、Canvas异步绘制逻辑往往在这之后才执行,你提前调用toDataURL拿到的就是未完成绘制的Canvas内容,自然会出现图片损坏的情况。固定时长等待无法适配不同网络环境下的加载速度,自然不稳定。

可靠的检测方案

不要依赖固定延时,改用Canvas内容稳定性检测逻辑:定期采样Canvas的像素特征,连续多次采样结果一致时,就代表绘制已经完成,可以执行下载。

另外你现有代码里的eval解析页码逻辑风险极高,且完全没必要,可以用正则直接匹配页码,更稳定可靠。

修改后的完整脚本

// ==UserScript==
// @name           somesite 画廊批量下载
// @description    自动下载Canvas画廊的完整图片
// @namespace      somesite
// @version        2.0
// @match          https://somesite.com/somegallery/*
// @license        tttt
// @copyright      tttt
// @grant          none
// @run-at         document-idle
// ==/UserScript==

(function() {
    // 等待Canvas绘制完成的函数
    function waitForCanvasReady(canvas, callback) {
        let lastData = null;
        let stableCount = 0;
        // 每500ms采样一次Canvas的像素特征
        const checkTimer = setInterval(() => {
            // 取Canvas左上角100x100区域的像素数据做特征,全图采样太耗性能
            const ctx = canvas.getContext('2d');
            const imgData = ctx.getImageData(0, 0, Math.min(100, canvas.width), Math.min(100, canvas.height)).data.toString();
            if (imgData === lastData) {
                stableCount++;
                // 连续3次采样结果一致,认为绘制完成
                if (stableCount >= 3) {
                    clearInterval(checkTimer);
                    callback();
                }
            } else {
                lastData = imgData;
                stableCount = 0;
            }
        }, 500);
    }

    // 执行下载逻辑
    function downloadImage() {
        const canvas = document.getElementById("the-canvas");
        const pageText = document.querySelector("#main > h1").textContent;
        // 用正则匹配页码,比字符串切割+eval安全可靠
        const pageMatch = pageText.match(/Page (\d+) of (\d+)/);
        if (!pageMatch) return;
        const currentPage = pageMatch[1], totalPage = pageMatch[2];

        const image = canvas.toDataURL("image/png");
        const link = document.createElement("a");
        link.download = `Page ${currentPage} of ${totalPage}.png`;
        link.href = image;
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);

        // 不是最后一页就翻页
        if (parseInt(currentPage) !== parseInt(totalPage)) {
            setTimeout(() => {
                document.getElementsByClassName("btn btn-primary float-right")[1].click();
            }, Math.floor(Math.random() * 2000) + 1000);
        }
    }

    // 先检测Canvas元素是否存在,存在就等绘制完成再下载
    const checkCanvasTimer = setInterval(() => {
        const canvas = document.getElementById("the-canvas");
        if (canvas) {
            clearInterval(checkCanvasTimer);
            waitForCanvasReady(canvas, downloadImage);
        }
    }, 300);
})();

额外优化说明

  • 去掉了对页面jQuery的依赖,全部用原生JS实现,避免页面未加载jQuery导致的逻辑异常
  • 增加了Canvas元素存在性检测,避免页面DOM还没渲染完就执行逻辑报错
  • 采样仅取Canvas左上角小区域做特征对比,不会影响页面性能
  • 下载完成后自动移除创建的a标签,避免页面残留冗余元素

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 17:24:01