淘宝/天猫评论图集高清原图分组下载器
发表于 ・ 视频
高清原图下载:自动获取评论图的高清原图,无需手动另存。
自动分组文件夹:评论和图集按商品名+序号生成文件夹,整齐有序。
过滤小图:自动忽略小于 100×100 的无效图片,节省空间。
自动去重编号:同组内图片按 01、02、03 自动编号,避免重复。
支持评论分组 & 图集多选:自由选择需要下载的评论或单张图片。
安全易用:无需额外工具,一键下载,兼容淘宝/天猫各站点。

// ==UserScript==
// @name 淘宝/天猫评论图集高清原图分组下载器
// @namespace tb-comment-hd-gallery-downloader
// @version 3.5
// @description 淘宝/天猫评论图下载:商品文件夹、分组文件夹按商品名01/02命名、过滤100x100以下图片、高清原图、自动去重编号
// @match *://*.taobao.com/*
// @match *://*.tmall.com/*
// @match *://*.tmall.hk/*
// @match *://*.world.taobao.com/*
// @grant GM_download
// @connect gw.alicdn.com
// @connect img.alicdn.com
// @connect alicdn.com
// ==/UserScript==
(function () {
'use strict';
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
function fullUrl(url) {
if (!url) return '';
if (url.startsWith('//')) return 'https:' + url;
return url;
}
function cleanName(name, maxLen = 255) {
return (name || '未命名')
.replace(/[\\/:*?"<>|]/g, '')
.replace(/[\r\n\t]/g, '')
.replace(/\s+/g, ' ')
.trim()
.slice(0, maxLen);
}
function getRootFolderName() {
const input = document.querySelector('#tb-folder-name-input');
const value = input?.value?.trim() || '';
return cleanName(value || '淘宝评论原图', 255);
}
function makeGroupFolderName(rootFolder, indexOrId) {
const suffix = String(indexOrId).padStart(2, '0');
return cleanName(`${rootFolder} ${suffix}`, 255);
}
function getHDImage(url) {
if (!url) return '';
url = fullUrl(url).split('?')[0];
url = url.replace(/\/i\d+\//i, '/i0/');
const match = url.match(/.*?-(0|2)-(rate|tbbala)(?:_livephoto)?\.(jpg|jpeg|png)/i);
if (match) return match[0];
const match2 = url.match(/.*?!!\d+-(rate|tbbala)(?:_livephoto)?\.(jpg|jpeg|png)/i);
if (match2) return match2[0];
const imgMatch = url.match(/.*?\.(jpg|jpeg|png|webp)/i);
if (imgMatch) return imgMatch[0];
return url;
}
function getImageSrc(img) {
return img.getAttribute('data-src') ||
img.getAttribute('src') ||
img.currentSrc ||
img.src ||
'';
}
function isValidImageUrl(url) {
if (!url) return false;
if (url.includes('tps-145-145')) return false;
if (url.includes('tps-56-56')) return false;
if (url.includes('playerIcon')) return false;
if (url.includes('6000000002189-2-tps')) return false;
if (url.includes('6000000006294-2-tps')) return false;
return /\.(jpg|jpeg|png|webp)$/i.test(url);
}
function isImageSizeOk(img) {
const w = img.naturalWidth || img.width || 0;
const h = img.naturalHeight || img.height || 0;
return w >= 100 && h >= 100;
}
function getFileExt(url) {
const match = url.match(/\.(jpg|jpeg|png|webp)$/i);
return match ? match[1].toLowerCase() : 'jpg';
}
function getComments() {
return [...document.querySelectorAll(
'[class*="Comment--"], [class*="comment--"], [class*="comment"]'
)];
}
function getImages(comment) {
const imgs = [...comment.querySelectorAll('img')];
const urls = imgs
.filter(img => isImageSizeOk(img))
.map(img => getHDImage(getImageSrc(img)))
.filter(isValidImageUrl);
return [...new Set(urls)];
}
function getImageItems() {
return [...document.querySelectorAll(
'[class*="commentsImgItem"], [class*="photo--"], [class*="cover--"]'
)];
}
function injectStyle() {
if (document.querySelector('#tb-hd-style')) return;
const style = document.createElement('style');
style.id = 'tb-hd-style';
style.innerHTML = `
#tb-hd-download-panel {
position: fixed;
right: 24px;
top: 110px;
z-index: 999999999;
width: 520px;
padding: 14px 16px;
border-radius: 18px;
background: rgba(255,255,255,.95);
backdrop-filter: blur(16px);
box-shadow: 0 14px 40px rgba(0,0,0,.12), 0 6px 18px rgba(255,80,0,.18);
border: 1px solid rgba(255,80,0,.18);
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Arial, "Microsoft YaHei", sans-serif;
color: #222;
}
.tb-panel-top {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
margin-bottom: 10px;
}
.tb-panel-title {
display: flex;
align-items: center;
gap: 10px;
}
.tb-logo {
width: 34px;
height: 34px;
border-radius: 11px;
background: linear-gradient(135deg, #ff8a1c, #ff3d00);
color: #fff;
display: flex;
align-items: center;
justify-content: center;
font-weight: 900;
font-size: 18px;
box-shadow: 0 6px 14px rgba(255,80,0,.25);
}
.tb-title-main {
font-size: 16px;
font-weight: 800;
line-height: 1.2;
}
.tb-title-sub {
font-size: 12px;
color: #999;
margin-top: 2px;
}
.tb-folder-row {
display: flex;
gap: 8px;
align-items: center;
margin-bottom: 10px;
}
#tb-folder-name-input {
flex: 1;
height: 36px;
border-radius: 12px;
border: 1px solid rgba(255,80,0,.22);
background: #fff8f3;
padding: 0 12px;
font-size: 13px;
outline: none;
color: #333;
}
#tb-folder-name-input:focus {
border-color: #ff5000;
box-shadow: 0 0 0 3px rgba(255,80,0,.10);
background: #fff;
}
.tb-folder-preview {
width: 125px;
height: 36px;
line-height: 36px;
border-radius: 12px;
background: #fff3eb;
color: #ff5000;
font-size: 12px;
font-weight: 700;
text-align: center;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
border: 1px solid rgba(255,80,0,.16);
}
.tb-btn-row {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 8px;
}
.tb-btn {
height: 38px;
border: none;
outline: none;
border-radius: 12px;
font-size: 13px;
font-weight: 700;
cursor: pointer;
transition: all .18s ease;
}
.tb-btn:hover {
transform: translateY(-1px);
filter: brightness(1.04);
}
.tb-btn:active {
transform: scale(.98);
}
.tb-btn.primary {
color: #fff;
background: linear-gradient(135deg, #ff8a1c, #ff5000);
box-shadow: 0 6px 14px rgba(255,80,0,.24);
}
.tb-btn.success {
color: #fff;
background: linear-gradient(135deg, #24c6a0, #12b886);
box-shadow: 0 6px 14px rgba(18,184,134,.20);
}
.tb-btn.blue {
color: #fff;
background: linear-gradient(135deg, #4dabf7, #228be6);
box-shadow: 0 6px 14px rgba(34,139,230,.20);
}
.tb-btn.light {
color: #ff5000;
background: #fff4ed;
border: 1px solid rgba(255,80,0,.22);
}
.tb-download-label {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 7px 12px;
margin-bottom: 10px;
border-radius: 999px;
background: linear-gradient(135deg, #fff7f2, #fff);
color: #ff5000;
font-size: 13px;
font-weight: 700;
border: 1px solid rgba(255,80,0,.25);
box-shadow: 0 4px 12px rgba(255,80,0,.08);
cursor: pointer;
user-select: none;
}
.tb-download-label input {
accent-color: #ff5000;
width: 15px;
height: 15px;
}
.tb-img-select-wrap {
position: absolute !important;
right: 8px;
top: 8px;
z-index: 99999999;
width: 28px;
height: 28px;
border-radius: 50%;
background: rgba(0,0,0,.42);
backdrop-filter: blur(8px);
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
box-shadow: 0 4px 12px rgba(0,0,0,.18);
border: 1px solid rgba(255,255,255,.45);
}
.tb-img-select-wrap input {
width: 17px;
height: 17px;
margin: 0;
accent-color: #ff5000;
cursor: pointer;
}
.tb-img-selected {
outline: 3px solid #ff5000 !important;
outline-offset: -3px !important;
border-radius: 8px !important;
}
.tb-img-selected::after {
content: "已选";
position: absolute;
left: 8px;
top: 8px;
z-index: 99999998;
color: #fff;
background: linear-gradient(135deg, #ff8a1c, #ff5000);
font-size: 12px;
font-weight: 700;
padding: 4px 8px;
border-radius: 999px;
box-shadow: 0 4px 10px rgba(255,80,0,.25);
}
`;
document.head.appendChild(style);
}
function addPanel() {
if (document.querySelector('#tb-hd-download-panel')) return;
injectStyle();
const panel = document.createElement('div');
panel.id = 'tb-hd-download-panel';
panel.innerHTML = `
<div class="tb-panel-top">
<div class="tb-panel-title">
<span class="tb-logo">淘</span>
<div>
<div class="tb-title-main">评论原图下载</div>
<div class="tb-title-sub">商品文件夹 · 分组按商品名01/02 · 自动去重编号</div>
</div>
</div>
</div>
<div class="tb-folder-row">
<input id="tb-folder-name-input" placeholder="输入商品文件夹名,最长255字符">
<div class="tb-folder-preview" id="tb-folder-preview">淘宝评论原图</div>
</div>
<div class="tb-btn-row">
<button class="tb-btn primary" id="tb-scan-group-btn">评论分组</button>
<button class="tb-btn blue" id="tb-scan-img-btn">图集选择</button>
<button class="tb-btn success" id="tb-download-btn">下载选中</button>
<button class="tb-btn light" id="tb-select-all-btn">全选/反选</button>
</div>
`;
document.body.appendChild(panel);
const input = document.querySelector('#tb-folder-name-input');
const preview = document.querySelector('#tb-folder-preview');
input.addEventListener('input', () => {
preview.textContent = getRootFolderName();
});
document.querySelector('#tb-scan-group-btn').onclick = markComments;
document.querySelector('#tb-scan-img-btn').onclick = markImageItems;
document.querySelector('#tb-download-btn').onclick = downloadSelected;
document.querySelector('#tb-select-all-btn').onclick = toggleAll;
}
function markComments() {
const comments = getComments();
let validCount = 0;
comments.forEach((comment) => {
if (comment.querySelector('.tb-download-check')) return;
const imgs = getImages(comment);
if (!imgs.length) return;
validCount++;
const box = document.createElement('label');
box.className = 'tb-download-label';
box.innerHTML = `
<input type="checkbox" class="tb-download-check tb-group-check">
<span>本组 ${imgs.length} 张原图</span>
`;
comment.prepend(box);
});
alert(`评论分组扫描完成:找到 ${validCount} 个图片评论分组`);
}
function markImageItems() {
const items = getImageItems();
let validCount = 0;
const groupMap = new Map();
items.forEach((item) => {
if (item.querySelector('.tb-single-check')) return;
const img = item.querySelector('img');
if (!img) return;
if (!isImageSizeOk(img)) return;
const url = getHDImage(getImageSrc(img));
if (!isValidImageUrl(url)) return;
const hdUrl = getHDImage(url);
if (!groupMap.has(hdUrl)) {
groupMap.set(hdUrl, String(groupMap.size + 1).padStart(2, '0'));
}
const groupId = groupMap.get(hdUrl);
item.style.position = 'relative';
item.dataset.tbImageUrl = url;
item.dataset.tbGalleryGroupId = groupId;
const wrap = document.createElement('label');
wrap.className = 'tb-img-select-wrap';
wrap.title = `选中下载高清原图,分组:${groupId}`;
wrap.innerHTML = `<input type="checkbox" class="tb-single-check">`;
const checkbox = wrap.querySelector('input');
checkbox.addEventListener('change', () => {
item.classList.toggle('tb-img-selected', checkbox.checked);
});
wrap.addEventListener('click', e => {
e.stopPropagation();
});
item.appendChild(wrap);
validCount++;
});
alert(`图集扫描完成:找到 ${validCount} 张可选择图片`);
}
function toggleAll() {
const checks = [
...document.querySelectorAll('.tb-download-check'),
...document.querySelectorAll('.tb-single-check')
];
if (!checks.length) {
alert('请先点击“评论分组”或“图集选择”');
return;
}
const hasUnchecked = checks.some(c => !c.checked);
checks.forEach(c => {
c.checked = hasUnchecked;
const item = c.closest('[class*="commentsImgItem"], [class*="photo--"], [class*="cover--"]');
if (item) {
item.classList.toggle('tb-img-selected', c.checked);
}
});
}
function addTask(tasks, seen, groupCounters, rawUrl, folder) {
if (!rawUrl || !folder) return;
const hdUrl = getHDImage(rawUrl);
if (!isValidImageUrl(hdUrl)) return;
if (seen.has(hdUrl)) return;
seen.add(hdUrl);
if (!groupCounters[folder]) {
groupCounters[folder] = 0;
}
groupCounters[folder]++;
const ext = getFileExt(hdUrl);
const filename = `${folder}/${String(groupCounters[folder]).padStart(2, '0')}.${ext}`;
tasks.push({
url: hdUrl,
filename
});
}
async function downloadSelected() {
const rootFolder = getRootFolderName();
const tasks = [];
const seen = new Set();
const groupCounters = {};
const selectedGroups = [...document.querySelectorAll('.tb-group-check:checked')]
.map(input => input.closest('[class*="Comment--"], [class*="comment--"], [class*="comment"]'))
.filter(Boolean);
selectedGroups.forEach((comment, groupIndex) => {
const groupName = makeGroupFolderName(rootFolder, groupIndex + 1);
const folder = `${rootFolder}/评论分组/${groupName}`;
const imgs = getImages(comment);
imgs.forEach(url => {
addTask(tasks, seen, groupCounters, url, folder);
});
});
const selectedSingles = [...document.querySelectorAll('.tb-single-check:checked')]
.map(input => input.closest('[class*="commentsImgItem"], [class*="photo--"], [class*="cover--"]'))
.filter(Boolean);
selectedSingles.forEach(item => {
const rawUrl = item.dataset.tbImageUrl;
if (!rawUrl) return;
const hdUrl = getHDImage(rawUrl);
const groupId = item.dataset.tbGalleryGroupId || '01';
const groupName = makeGroupFolderName(rootFolder, groupId);
const folder = `${rootFolder}/图集分组/${groupName}`;
addTask(tasks, seen, groupCounters, hdUrl, folder);
});
if (!tasks.length) {
alert('请先勾选要下载的图片或评论分组');
return;
}
for (let i = 0; i < tasks.length; i++) {
const task = tasks[i];
console.log('下载高清原图:', task.url, task.filename);
GM_download({
url: task.url,
name: task.filename,
saveAs: false,
onload: () => console.log('下载完成:', task.filename),
onerror: err => console.warn('下载失败:', task.url, err)
});
await sleep(500);
}
alert(
`已开始下载 ${tasks.length} 张高清原图。\n\n` +
`主文件夹:${rootFolder}\n` +
`主文件夹最长255字符。\n` +
`已过滤低于100×100的图片。\n` +
`分组文件夹已按:商品文件夹名 01、商品文件夹名 02 命名。\n` +
`每个分组内图片仍按 01、02、03 自动编号。`
);
}
addPanel();
const observer = new MutationObserver(() => {
addPanel();
});
observer.observe(document.body, {
childList: true,
subtree: true
});
})();
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。