引言
很多做无货源的卖家在问:“支持1688商品下载的软件”
1688是国内最大的批发平台,也是淘宝、拼多多无货源卖家的主要货源渠道。采集1688商品图片有两个技术难点:大部分商品需要登录才能查看详情,而且SKU规格图(颜色、尺寸、型号)非常丰富,手动整理极其耗时。
本文从技术角度深度解析1688商品图片的批量采集技术,包括登录态持久化、SKU图自动分类、图片原图获取等核心模块。类似的技术方案在一键存图中已有成熟应用。
目录
1688平台技术特点分析
登录态持久化技术
SKU图自动分类算法
图片URL原图转换
主图与详情图提取
页面加载等待策略
完整采集流程实现
文件存储与归档
批量采集与队列管理
断点续传实现
实测数据与总结
一、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商品图片批量采集的核心技术点:
登录态持久化:浏览器内核自动管理Cookie,一次登录长期有效
SKU图自动分类:从SKU容器中提取属性名称并关联图片
原图转换:去除URL中的尺寸后缀获取高清原图
页面等待策略:多重等待机制确保登录态生效和页面完全加载
类似一键存图的工具已经将这些技术封装成成熟产品,用户无需编写代码,只需复制商品链接即可自动完成SKU图的分类归档,将原来5-10分钟的手工整理压缩到30秒。
免责声明:本文内容仅供技术交流和学习参考。电商平台的数据采集行为可能涉及平台服务条款、著作权法等法律问题。请确保遵守目标网站的《用户协议》和相关法律法规。因不当使用引发的法律风险由使用者自行承担。