# threads 抓圖
###### tags: `chrome`, `tampermonkey`, `javascript`
``` javascript
// ==UserScript==
// @name [ Threads ] 圖片與完整描述自動收集
// @description [ Threads ] 圖片與完整描述自動收集
// @namespace http://tampermonkey.net/
// @version 1.20240604
// @author icps
// @match https://www.threads.com/@*
// @grant none
// ==/UserScript==
(function() {
'use strict';
window.allImageData = [];
const btn = document.createElement('button');
btn.textContent = '開始收集';
btn.style.position = 'fixed';
btn.style.top = '20px';
btn.style.right = '20px';
btn.style.zIndex = 9999;
btn.style.padding = '10px 15px';
btn.style.backgroundColor = '#ff5722';
btn.style.color = '#fff';
btn.style.border = 'none';
btn.style.borderRadius = '5px';
btn.style.cursor = 'pointer';
btn.style.fontSize = '14px';
btn.style.boxShadow = '0 2px 5px rgba(0,0,0,0.3)';
document.body.appendChild(btn);
btn.addEventListener('click', async () => {
btn.disabled = true;
btn.textContent = '收集中...';
await autoScrollAndCollect();
console.log(`共收集 ${window.allImageData.length} 筆描述與圖片`);
downloadData(window.allImageData);
btn.disabled = false;
btn.textContent = '開始收集';
});
async function autoScrollAndCollect() {
const maxScrollTimes = 100;
const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
for (let scrollTimes = 0; scrollTimes < maxScrollTimes; scrollTimes++) {
document.querySelectorAll('div.x1xdureb.xkbb5z.x13vxnyz').forEach(post => {
const descEl = post.querySelector('div.x1a6qonq span');
const desc = descEl ? descEl.innerText.trim() : "";
const imgUrls = Array.from(post.querySelectorAll('img'))
.map(img => img.src)
.filter(src => src); // 避免空值
if (imgUrls.length === 0) return;
// 檢查是否已存在相同描述
const exists = window.allImageData.find(d => d.text === desc);
if (exists) {
// 已存在,補上新圖片(避免重複)
imgUrls.forEach(url => {
if (!exists.urls.includes(url)) {
exists.urls.push(url);
}
});
} else {
// 新增資料
window.allImageData.push({
text: desc,
urls: imgUrls
});
}
});
window.scrollBy(0, 1500);
await sleep(2000);
}
}
function downloadData(data) {
const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' });
const link = document.createElement('a');
link.href = URL.createObjectURL(blob);
// 取出使用者名稱
const matches = window.location.pathname.match(/^\/@([^\/]+)/);
const username = matches ? matches[1] : 'threads_data';
link.download = `${username}.json`;
link.click();
}
})();
```