京东热卖商品下载

发表于 视频

// ==UserScript==
// @name         JD接口抓取SKU商品名图片-内容数分组版
// @namespace    jd-api-sku-img-content-group
// @version      3.0
// @match        *://*.jd.com/*
// @match        *://*.m.jd.com/*
// @grant        GM_download
// @run-at       document-start
// ==/UserScript==

(function () {
    'use strict';

    const downloaded = new Set();

    function safeName(str) {
        return String(str || "")
            .replace(/[\\/:*?"<>|]/g, "_")
            .replace(/\s+/g, " ")
            .trim()
            .slice(0, 120);
    }

    function cleanImg(url) {
        if (!url) return "";

        url = String(url).trim();

        if (url.startsWith("//")) {
            url = "https:" + url;
        }

        // 重点修复:
        // https://m.360buyimg.com/ceco/s500x0_jfs/...
        // 变成:
        // https://m.360buyimg.com/ceco/jfs/...
        url = url.replace(/\/s\d+x\d+_jfs\//g, "/jfs/");

        // 兜底去掉 s500x0_、s250x250_、s800x800_ 等
        url = url.replace(/s\d+x\d+_/g, "");

        return url;
    }

    function getContentNum(value) {
        if (value === undefined || value === null) return 0;

        let str = String(value).trim();

        // 例如:30+、5+、内容数3
        let match = str.match(/\d+/);

        if (!match) return 0;

        return parseInt(match[0], 10) || 0;
    }

    function getContentGroup(value) {
        const num = getContentNum(value);

        if (num <= 5) {
            return "01_内容数0-5";
        }

        if (num <= 10) {
            return "02_内容数5-10";
        }

        if (num <= 20) {
            return "03_内容数10-20";
        }

        if (num <= 50) {
            return "04_内容数21-50";
        }

        return "05_内容数50以上";
    }

    function downloadSku(item) {
        if (!item || !item.skuBasic) return;

        const sku = item.skuBasic.sku || "";
        const title = item.skuBasic.skuName || "";
        const img = cleanImg(item.skuBasic.img || "");

        const contentCount =
            item.skuStatistics?.contentCount
            || item.skuStatistics?.contentCountBlur
            || "0";

        if (!sku || !title || !img) return;

        const key = sku + "_" + img;
        if (downloaded.has(key)) return;
        downloaded.add(key);

        const groupName = getContentGroup(contentCount);
        const folderName = safeName(sku) + "----" + safeName(title);

        const savePath = groupName + "/" + folderName + "/0.jpg";

        console.log("准备下载:", {
            sku: sku,
            title: title,
            contentCount: contentCount,
            group: groupName,
            img: img,
            savePath: savePath
        });

        GM_download({
            url: img,
            name: savePath,
            saveAs: false,
            onload: function () {
                console.log("下载成功:", savePath);
            },
            onerror: function (e) {
                console.log("下载失败:", savePath, img, e);
            }
        });
    }

    function handleJson(json) {
        try {
            if (!json || json.code !== 0) return;

            const skus = json?.data?.skus;

            if (!Array.isArray(skus) || skus.length === 0) return;

            console.log("接口检测到SKU数量:", skus.length);

            skus.forEach(downloadSku);

        } catch (e) {
            console.log("解析SKU失败:", e);
        }
    }

    // 拦截 fetch
    const originalFetch = window.fetch;
    window.fetch = function () {
        return originalFetch.apply(this, arguments).then(function (response) {
            try {
                const url = response.url || "";

                if (url.includes("api.m.jd.com")) {
                    response.clone().json().then(function (json) {
                        handleJson(json);
                    }).catch(function () {});
                }
            } catch (e) {}

            return response;
        });
    };

    // 拦截 XMLHttpRequest
    const originalOpen = XMLHttpRequest.prototype.open;
    const originalSend = XMLHttpRequest.prototype.send;

    XMLHttpRequest.prototype.open = function (method, url) {
        this._jd_url = url;
        return originalOpen.apply(this, arguments);
    };

    XMLHttpRequest.prototype.send = function () {
        this.addEventListener("load", function () {
            try {
                const url = this._jd_url || "";

                if (!url.includes("api.m.jd.com")) return;

                const json = JSON.parse(this.responseText);
                handleJson(json);

            } catch (e) {}
        });

        return originalSend.apply(this, arguments);
    };

    function addButton() {
        if (document.getElementById("jdSkuContentGroupBtn")) return;

        const btn = document.createElement("button");

        btn.id = "jdSkuContentGroupBtn";
        btn.innerText = "监听SKU图片";
        btn.style.cssText = `
            position: fixed;
            right: 20px;
            top: 120px;
            z-index: 999999;
            padding: 10px 16px;
            background: #e1251b;
            color: #fff;
            border: none;
            border-radius: 6px;
            cursor: pointer;
            font-size: 14px;
            font-weight: bold;
            box-shadow: 0 4px 12px rgba(0,0,0,.2);
        `;

        btn.onclick = function () {
            alert("脚本正在监听 api.m.jd.com 接口,请刷新页面、翻页或滚动加载商品。");
        };

        document.body.appendChild(btn);
    }

    window.addEventListener("DOMContentLoaded", addButton);

})();


发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。