下载当前页面指定数据 (img, video, audio, ...)

调用 downloadDataInOrder(obtainDataNodes(document.querySelectorAll('数据节点'), 'file')) 方法,并传入数据节点,根据传入的数据节点,下载网页上的数据并保存到本地

当前为 2024-11-05 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         下载当前页面指定数据 (img, video, audio, ...)
// @namespace    http://tampermonkey.net/
// @version      1.0.4
// @description  调用 downloadDataInOrder(obtainDataNodes(document.querySelectorAll('数据节点'), 'file')) 方法,并传入数据节点,根据传入的数据节点,下载网页上的数据并保存到本地
// @author       slowFever
// @match        *://*/*
// @match        *
// @connect      *
// @grant        unsafeWindow
// @grant        GM_xmlhttpRequest
// @run-at       document-idle
// ==/UserScript==

(function() {
    'use strict';

    /**
     * @name 获取数据节点的函数
     * @param nodes 传入单个节点,或多个节点(img, video, audio, ...)
     * @returns Array[]
     */
    function obtainDataNodes(nodes) {
        let nodeDataList = [];
        nodes.forEach(node => {
            const src = node.getAttribute('src');
            if (src && !nodeDataList.includes(src)) {
                nodeDataList.push(src);
            }
        });
        console.log(`获取到${nodeDataList.length}条数据`)
        return nodeDataList;
    }

    /**
     * @name 下载数据的函数
     * @param url 下载地址
     * @param filename 文件名
     * @returns {Promise<void>}
     */
    function downloadFile(url, filename) {
        return new Promise((resolve, reject) => {
            GM_xmlhttpRequest({
                method: "GET",
                url: url,
                responseType: "blob", // 指定响应类型为 blob
                onload: function(response) {
                    if (response.status === 200) {
                        const blob = new Blob([response.response]); // 创建 Blob 对象
                        const link = document.createElement('a'); // 创建 <a> 标签
                        const objectURL = URL.createObjectURL(blob); // 创建 Blob URL
                        link.href = objectURL;
                        link.download = filename; // 设置下载的文件名
                        document.body.appendChild(link); // 添加到文档中
                        link.click(); // 模拟点击下载
                        document.body.removeChild(link); // 下载完成后移除 <a> 标签
                        URL.revokeObjectURL(objectURL); // 释放 Blob URL
                        console.log(`成功下载数据:${filename}`);
                        resolve(); // 下载完成,调用 resolve
                    } else {
                        console.error('下载失败,状态码:', response.status);
                        reject(`下载失败,状态码: ${response.status}`);
                    }
                },
                onerror: function(error) {
                    console.error('下载出错:', error);
                    reject(error); // 出错时调用 reject
                }
            });
        });
    }

    /**
     * @name 分批按顺序下载数据的函数
     * @param nodesData 数据节点
     * @param prefix 文件名前缀
     * @param batchSize 每次下载的最大文件数量
     */
    async function downloadDataInOrder(nodesData, prefix = 'file', batchSize = 10) {
        for (let i = 0; i < nodesData.length; i += batchSize) {
            const batch = nodesData.slice(i, i + batchSize); // 获取当前批次的数据
            await Promise.all(batch.map((url, index) => {
                const fileName = `${prefix}-${i + index + 1}.${url.split('.').pop().split('?')[0]}`;
                return downloadFile(url, fileName);
            }));
            console.log(`完成批次 ${Math.floor(i / batchSize) + 1} 的下载`);
        }
    }

    // 将函数暴露到全局,以便在控制台调用
    unsafeWindow.downloadDataInOrder = downloadDataInOrder;
    unsafeWindow.obtainDataNodes = obtainDataNodes;

    // 提示用户可以通过控制台调用函数
    (async () => {
        console.log("下载指定数据脚本加载完成,当前版本:", GM_info.script.version);
        await new Promise(resolve => setTimeout(resolve, 1000)); // 延时1秒
        console.log("%c使用脚本方法:↓ ↓ ↓", "color:#ec2c64");
        await new Promise(resolve => setTimeout(resolve, 1000)); // 再延时1秒
        console.log("%cdownloadDataInOrder(obtainDataNodes(document.querySelectorAll('数据节点'), 'file'))",  "color:#0f59a4; background:#eef7f2; font-size:1.5rem; padding:0.15rem 0.35rem; margin: 1rem auto; font-family: Rockwell; border: 2px solid #0f59a4; border-radius: 4px;font-weight: bold; text-shadow: 1px 1px 1px #0f59a4;");
    })();
})();