# 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(); } })(); ```