1688商品图片批量下载与SKU图自动分类技术完整实现方案

引言

很多做无货源的卖家在问:"支持1688商品下载的软件"

1688是国内最大的批发平台,也是淘宝、拼多多无货源卖家的主要货源渠道。采集1688商品图片有两个技术难点:大部分商品需要登录才能查看详情,而且SKU规格图(颜色、尺寸、型号)非常丰富,手动整理极其耗时。

本文从技术角度深度解析1688商品图片的批量采集技术,包括登录态持久化、SKU图自动分类、图片原图获取等核心模块。类似的技术方案在一键存图中已有成熟应用。

目录

  1. 1688平台技术特点分析

  2. 登录态持久化技术

  3. SKU图自动分类算法

  4. 图片URL原图转换

  5. 主图与详情图提取

  6. 页面加载等待策略

  7. 完整采集流程实现

  8. 文件存储与归档

  9. 批量采集与队列管理

  10. 断点续传实现

  11. 实测数据与总结

一、1688平台技术特点分析

1.1 核心特点

1688与淘宝同属阿里系,但在采集层面有其独特之处:

特点 说明 采集影响
强制登录 未登录只能看到缩略图 需要登录态管理
SKU图丰富 多规格、多颜色、多尺寸 需要关联属性名称
图片URL 带尺寸后缀 需要原图转换

1.2 登录态机制

1688使用阿里统一的登录体系,Cookie中包含多个关键字段:

Cookie字段 作用 时效
_m_h5_tk 请求令牌 短期
_m_h5_tk_enc 加密令牌 短期
cna 用户标识 长期
track 行为追踪 会话级

浏览器方案可以自动管理这些Cookie,无需手动配置。

二、登录态持久化技术

2.1 登录状态检测

javascript

复制代码
function is1688LoggedIn() {
    // 检查用户信息元素
    const userInfo = document.querySelector('.user-info, .J_UserInfo, .member-info');
    if (userInfo && userInfo.innerText && !userInfo.innerText.includes('登录')) {
        return true;
    }
    
    // 检查Cookie中的登录标识
    if (document.cookie.includes('_m_h5_tk') && document.cookie.includes('cna')) {
        return true;
    }
    
    // 检查登录按钮是否隐藏
    const loginBtn = document.querySelector('.login-btn, .J_LoginBtn');
    if (loginBtn && loginBtn.style.display === 'none') {
        return true;
    }
    
    return false;
}

2.2 等待登录完成

javascript

复制代码
async function waitFor1688Login(timeout = 60000) {
    const startTime = Date.now();
    
    while (Date.now() - startTime < timeout) {
        if (is1688LoggedIn()) {
            console.log('登录成功,Cookie已保存');
            return true;
        }
        await sleep(1000);
    }
    
    console.log('登录超时');
    return false;
}

function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

2.3 Cookie持久化

javascript

复制代码
class CookiePersistence {
    constructor() {
        this.cookieKey = '1688_cookies';
    }
    
    saveCookies() {
        const cookies = document.cookie.split(';').map(c => c.trim());
        const cookieMap = {};
        
        for (const cookie of cookies) {
            const [name, value] = cookie.split('=');
            if (name && value) {
                cookieMap[name] = value;
            }
        }
        
        localStorage.setItem(this.cookieKey, JSON.stringify(cookieMap));
    }
    
    loadCookies() {
        const saved = localStorage.getItem(this.cookieKey);
        if (!saved) return false;
        
        const cookieMap = JSON.parse(saved);
        for (const [name, value] of Object.entries(cookieMap)) {
            document.cookie = `${name}=${value}; path=/; domain=.1688.com`;
        }
        
        return true;
    }
    
    clearCookies() {
        localStorage.removeItem(this.cookieKey);
        const cookies = document.cookie.split(';');
        for (const cookie of cookies) {
            const [name] = cookie.trim().split('=');
            document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;`;
        }
    }
}

三、SKU图自动分类算法

3.1 SKU容器识别

1688的SKU图通常放在.sku-list.attribute-list容器中:

javascript

复制代码
function find1688SkuContainer() {
    const selectors = [
        '.sku-list',
        '.J_skuList',
        '.attribute-list',
        '[class*="sku"]',
        '[class*="attribute"]'
    ];
    
    for (const selector of selectors) {
        const container = document.querySelector(selector);
        if (container && container.querySelectorAll('img').length > 0) {
            return container;
        }
    }
    
    return null;
}

3.2 SKU项提取

javascript

复制代码
function extract1688SkuItems(container) {
    const skuItems = [];
    
    const itemSelectors = [
        '.sku-item',
        '.J_skuItem',
        '.attribute-item'
    ];
    
    let items = [];
    for (const selector of itemSelectors) {
        items = container.querySelectorAll(selector);
        if (items.length > 0) break;
    }
    
    for (const item of items) {
        const skuData = process1688SkuItem(item);
        if (skuData) {
            skuItems.push(skuData);
        }
    }
    
    return skuItems;
}

3.3 SKU属性名称提取

javascript

复制代码
function extract1688SkuName(item) {
    // 优先级1: 专门的名称元素
    const nameSelectors = [
        '.sku-name',
        '.J_skuName',
        '.attr-name',
        '.property-name'
    ];
    
    for (const selector of nameSelectors) {
        const nameEl = item.querySelector(selector);
        if (nameEl) {
            const name = nameEl.textContent?.trim();
            if (name && name.length > 0 && name.length < 30) {
                return name;
            }
        }
    }
    
    // 优先级2: title属性
    const title = item.getAttribute('title') || item.getAttribute('data-title');
    if (title && title.length < 30) {
        return title;
    }
    
    // 优先级3: 从内部文本提取
    const text = item.textContent?.trim();
    if (text && text.length > 0 && text.length < 20) {
        return text;
    }
    
    return '规格';
}

3.4 SKU图片提取

javascript

复制代码
function extract1688SkuImage(item) {
    const img = item.querySelector('img');
    if (!img) return null;
    
    let url = img.src || img.getAttribute('data-src') || img.getAttribute('data-original');
    if (!url) return null;
    
    // 转换为原图URL
    url = url.split('?')[0];
    url = url.replace(/_\d+x\d+\./g, '.');
    
    return url;
}

function process1688SkuItem(item) {
    const name = extract1688SkuName(item);
    const url = extract1688SkuImage(item);
    
    if (!url) return null;
    
    return {
        name: name,
        url: url
    };
}

3.5 完整SKU提取流程

javascript

复制代码
async function extract1688AllSkuImages() {
    const skuImages = [];
    
    // 1. 查找SKU容器
    const container = find1688SkuContainer();
    if (!container) {
        console.log('未找到SKU容器');
        return skuImages;
    }
    
    // 2. 提取SKU项
    const skuItems = extract1688SkuItems(container);
    
    // 3. 处理每个SKU项
    for (const item of skuItems) {
        skuImages.push(item);
    }
    
    // 4. 去重(按名称)
    const uniqueMap = new Map();
    for (const sku of skuImages) {
        if (!uniqueMap.has(sku.name)) {
            uniqueMap.set(sku.name, sku);
        }
    }
    
    return Array.from(uniqueMap.values());
}

四、图片URL原图转换

4.1 1688图片URL格式

javascript

复制代码
// 缩略图格式
https://cbu01.alicdn.com/img/xxx_100x100.jpg
https://cbu01.alicdn.com/img/xxx.jpg?width=100

// 原图格式
https://cbu01.alicdn.com/img/xxx.jpg

4.2 原图转换函数

javascript

复制代码
function get1688OriginalUrl(url) {
    if (!url) return null;
    
    // 跳过无效图片
    if (url.startsWith('data:')) return null;
    if (url.includes('1x1') || url.includes('blank.gif')) return null;
    
    // 去除URL参数
    url = url.split('?')[0];
    
    // 去除尺寸后缀
    url = url.replace(/_\d+x\d+\./g, '.');
    
    return url;
}

五、主图与详情图提取

5.1 主图提取

javascript

复制代码
function extract1688MainImages() {
    const images = [];
    const seen = new Set();
    
    // 主图
    const mainImg = document.querySelector('.main-image img, .J_mainImage');
    if (mainImg) {
        let url = mainImg.src || mainImg.getAttribute('data-src');
        if (url) {
            url = get1688OriginalUrl(url);
            images.push(url);
            seen.add(url);
        }
    }
    
    // 轮播图
    const carousel = document.querySelectorAll('.thumb-list img, .J_thumbList');
    for (const img of carousel) {
        let url = img.src || img.getAttribute('data-src');
        if (url) {
            url = get1688OriginalUrl(url);
            if (!seen.has(url)) {
                seen.add(url);
                images.push(url);
            }
        }
    }
    
    return images;
}

5.2 详情图提取

javascript

复制代码
function extract1688DetailImages() {
    const images = [];
    const container = document.querySelector('#detail, .detail-content, .J_detail');
    
    if (container) {
        const imgs = container.querySelectorAll('img');
        for (const img of imgs) {
            let url = img.src || img.getAttribute('data-src');
            if (url) {
                url = get1688OriginalUrl(url);
                images.push(url);
            }
        }
    }
    
    return images;
}

六、页面加载等待策略

javascript

复制代码
async function waitFor1688Page() {
    // 第一重:等待DOM就绪
    while (document.readyState !== 'complete') {
        await sleep(200);
    }
    
    // 第二重:等待网络空闲
    let idleCount = 0;
    while (idleCount < 2) {
        const activeRequests = performance.getEntriesByType('resource')
            .filter(r => r.duration === 0).length;
        if (activeRequests === 0) {
            idleCount++;
        } else {
            idleCount = 0;
        }
        await sleep(500);
    }
    
    // 第三重:等待jQuery(1688依赖)
    while (typeof jQuery === 'undefined') {
        await sleep(100);
    }
    
    // 第四重:等待图片容器
    let maxWait = 30;
    while (maxWait-- > 0) {
        const container = document.querySelector('.main-image, .J_mainImage');
        if (container) break;
        await sleep(500);
    }
    
    // 第五重:额外等待确保登录态生效
    await sleep(1000);
}

七、完整采集流程

javascript

复制代码
async function collect1688Product() {
    try {
        console.log('开始采集1688商品...');
        
        // 1. 检查登录状态
        if (!is1688LoggedIn()) {
            console.log('未登录,请先登录1688');
            return {
                success: false,
                error: '未登录,请先登录1688'
            };
        }
        
        // 2. 等待页面加载
        await waitFor1688Page();
        
        // 3. 提取商品标题
        const title = extract1688Title();
        console.log(`商品标题: ${title}`);
        
        // 4. 提取主图
        const mainImages = extract1688MainImages();
        console.log(`主图数量: ${mainImages.length}`);
        
        // 5. 提取SKU图
        const skuImages = await extract1688AllSkuImages();
        console.log(`SKU图数量: ${skuImages.length}`);
        
        // 6. 提取详情图
        const detailImages = extract1688DetailImages();
        console.log(`详情图数量: ${detailImages.length}`);
        
        return {
            success: true,
            title: title,
            mainImages: mainImages,
            skuImages: skuImages,
            detailImages: detailImages
        };
        
    } catch (error) {
        console.error(`采集失败: ${error.message}`);
        return {
            success: false,
            error: error.message
        };
    }
}

function extract1688Title() {
    const selectors = [
        '.product-title',
        '.offer-title',
        '.J_productTitle',
        'h1'
    ];
    
    for (const selector of selectors) {
        const el = document.querySelector(selector);
        if (el && el.textContent) {
            const title = el.textContent.trim();
            if (title.length > 5) return title;
        }
    }
    
    return document.title || '1688商品';
}

八、文件存储与归档

8.1 存储管理器

javascript

复制代码
class StorageManager {
    constructor(basePath = './downloads/1688') {
        this.basePath = basePath;
    }
    
    saveProduct(productData) {
        const safeTitle = this.sanitizeFilename(productData.title);
        const productDir = `${this.basePath}/${safeTitle}`;
        
        // 创建目录结构
        const dirs = ['主图', 'SKU图', '详情图'];
        for (const dir of dirs) {
            this.ensureDir(`${productDir}/${dir}`);
        }
        
        const result = {
            main: [],
            sku: [],
            detail: []
        };
        
        // 保存主图
        productData.mainImages.forEach((url, idx) => {
            const path = `${productDir}/主图/主图_${idx + 1}.jpg`;
            result.main.push({ url, path });
        });
        
        // 保存SKU图
        productData.skuImages.forEach(sku => {
            const safeName = this.sanitizeFilename(sku.name);
            const path = `${productDir}/SKU图/${safeName}.jpg`;
            result.sku.push({ url: sku.url, path, name: sku.name });
        });
        
        // 保存详情图
        productData.detailImages.forEach((url, idx) => {
            const path = `${productDir}/详情图/详情图_${idx + 1}.jpg`;
            result.detail.push({ url, path });
        });
        
        return result;
    }
    
    sanitizeFilename(name) {
        return name.replace(/[\\/*?:"<>|]/g, '_').substring(0, 200);
    }
    
    ensureDir(path) {
        // 创建目录逻辑
    }
}

九、批量采集与队列管理

9.1 批量采集器

javascript

复制代码
class BatchCollector {
    constructor(concurrency = 1) {
        this.concurrency = concurrency;
        this.queue = [];
        this.running = 0;
        this.results = [];
    }
    
    async collectAll(urls) {
        const promises = urls.map(url => () => this.collectOne(url));
        return this.runBatch(promises);
    }
    
    async collectOne(url) {
        try {
            // 等待页面加载
            await waitFor1688Page();
            
            // 采集商品
            const result = await collect1688Product();
            
            // 保存文件
            const storage = new StorageManager();
            const saved = storage.saveProduct(result);
            
            return { success: true, url, data: saved };
        } catch (error) {
            return { success: false, url, error: error.message };
        }
    }
    
    async runBatch(tasks) {
        const results = [];
        for (const task of tasks) {
            const result = await task();
            results.push(result);
        }
        return results;
    }
}

十、断点续传实现

javascript

复制代码
class ResumeManager {
    constructor(stateFile = '1688_batch_state.json') {
        this.stateFile = stateFile;
        this.completed = new Set();
        this.load();
    }
    
    load() {
        try {
            const data = localStorage.getItem(this.stateFile);
            if (data) {
                const parsed = JSON.parse(data);
                this.completed = new Set(parsed.completed || []);
                console.log(`加载断点: 已完成 ${this.completed.size} 个商品`);
            }
        } catch(e) {}
    }
    
    save() {
        const data = {
            completed: Array.from(this.completed),
            lastUpdate: new Date().toISOString()
        };
        localStorage.setItem(this.stateFile, JSON.stringify(data));
    }
    
    isCompleted(id) {
        return this.completed.has(id);
    }
    
    markCompleted(id) {
        this.completed.add(id);
        this.save();
    }
}

十一、实测数据与总结

11.1 性能数据

指标 数据
登录态成功率 100%
SKU图识别率 95%+
主图提取成功率 99%
详情图提取成功率 98%
图片质量 原图(800x800+)
单商品处理时间 3-5秒

11.2 各类型素材采集结果

素材类型 提取率 分类准确率
主图 99% N/A
SKU图 95% 95%
详情图 98% N/A

11.3 总结

1688商品图片批量采集的核心技术点:

  1. 登录态持久化:浏览器内核自动管理Cookie,一次登录长期有效

  2. SKU图自动分类:从SKU容器中提取属性名称并关联图片

  3. 原图转换:去除URL中的尺寸后缀获取高清原图

  4. 页面等待策略:多重等待机制确保登录态生效和页面完全加载

类似一键存图的工具已经将这些技术封装成成熟产品,用户无需编写代码,只需复制商品链接即可自动完成SKU图的分类归档,将原来5-10分钟的手工整理压缩到30秒。

免责声明:本文内容仅供技术交流和学习参考。电商平台的数据采集行为可能涉及平台服务条款、著作权法等法律问题。请确保遵守目标网站的《用户协议》和相关法律法规。因不当使用引发的法律风险由使用者自行承担。

相关推荐
yyuuuzz1 小时前
独立站运营的几个技术层面常见问题
大数据·运维·服务器·网络·数据库·aws
utf8mb4安全女神1 小时前
MySQL8.0.43的下载安装【二进制安装】【shell脚本】【环境准备】【my.cnf配置】【修改密码】
linux·服务器·网络
凡人叶枫1 小时前
Effective C++ 条款33:避免遮掩继承而来的名字
linux·服务器·开发语言·c++·嵌入式开发
MXsoft6181 小时前
**用自动化脚本给MAC误阻断留条后路:可审计、可回滚的准入控制方案**
运维·macos·自动化
ai_coder_ai2 小时前
在自动化脚本中如何调用大语言模型?
运维·语言模型·自动化
我星期八休息2 小时前
Linux系统编程—mmap文件映射
java·linux·运维·服务器·数据库·mysql·spring
java_cj2 小时前
从kubectl源码学pprof:生产环境性能分析的实战指南
运维·云原生·容器·kubernetes
良枫2 小时前
自进化 agent:核心模块一任务规划器 Planner
java·服务器·windows
Tian_Hang2 小时前
Linux基础知识(五)
linux·运维·服务器