您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
自動瀏覽 Threads 文章,模擬真實使用行為。工具欄新增【開始 🚀】與【暫停 ⛔】按鈕,並在狀態欄顯示當前狀態、倒計時與完整循環次數(每完成一次目標頁與首頁瀏覽算一輪)。請用於刷文章觀看。
// ==UserScript== // @name Threads V1.21 // @namespace http://tampermonkey.net/ // @version 1.3 // @description 自動瀏覽 Threads 文章,模擬真實使用行為。工具欄新增【開始 🚀】與【暫停 ⛔】按鈕,並在狀態欄顯示當前狀態、倒計時與完整循環次數(每完成一次目標頁與首頁瀏覽算一輪)。請用於刷文章觀看。 // @author ChatGPT // @match https://www.threads.net/* // @grant none // @license MIT // ==/UserScript== (function() { 'use strict'; // ========= 初始設定 ========= // 讀取或設定目標文章與首頁 URL(若 localStorage 中無則採用預設值) let targetUrl = localStorage.getItem("THREADS_TARGET_URL") || "https://www.threads.net/posts/xxxxxx"; // 請替換預設目標文章 URL(請注意目標文章 URL 應包含 "/post/" 或 "/posts/") let homeUrl = localStorage.getItem("HOME_URL") || "https://www.threads.net"; // 預設首頁 URL localStorage.setItem("THREADS_TARGET_URL", targetUrl); localStorage.setItem("HOME_URL", homeUrl); // 使用 localStorage 儲存自動運行旗標與循環次數(每次進入目標文章頁視為完成一輪循環) const AUTO_FLAG = "THREADS_AUTOMATION_RUNNING"; const LOOP_COUNT_KEY = "LOOP_COUNT"; // ========= 時間參數(毫秒) ========= const STAY_TIME = [30000, 60000]; // 目標文章頁瀏覽:30~60秒 const BROWSE_TIME = [120000, 240000]; // 首頁瀏覽:2~4分鐘,原3~5分鐘 const SCROLL_INTERVAL = [2000, 5000]; // 滾動間隔:2~5秒 // ========= 工具函式 ========= function randomDelay(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; } async function wait(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } // 倒計時等待,每秒更新,並顯示當前階段描述 async function countdown(ms, description) { let seconds = Math.ceil(ms / 1000); while (seconds > 0 && localStorage.getItem(AUTO_FLAG) === "true") { countdownDisplay.textContent = `${description} 倒數:${seconds}秒`; await wait(1000); seconds--; } } // 更新狀態顯示 function updateStatus(text) { statusDisplay.textContent = "狀態:" + text; } // 寫入日誌 function logMessage(msg) { const div = document.createElement('div'); div.textContent = msg; logArea.appendChild(div); logArea.scrollTop = logArea.scrollHeight; } // 隨機滾動一次,增加隨機上下滾動效果(模擬真實使用) async function scrollPage() { logMessage("👉 開始滾動頁面..."); const scrollStep = window.innerHeight * (Math.random() * 0.5 + 0.5); // 70% 機率向下滾,30% 機率向上滾 const direction = Math.random() < 0.7 ? 1 : -1; window.scrollBy({ top: scrollStep * direction, behavior: 'smooth' }); await wait(randomDelay(...SCROLL_INTERVAL)); logMessage("✅ 完成滾動"); } // ========= 模擬流程 ========= // 模擬目標文章頁瀏覽(包含隨機滾動與倒計時等待,完成後等待一段時間再跳轉至首頁) async function simulateTargetPage() { // 判斷條件修改為:只要 URL 包含 "/post/" 或 "/posts/" 就認為是目標文章頁 if (!(window.location.href.includes("/post/") || window.location.href.includes("/posts/"))) return; // 累計循環次數,每進入目標文章頁即累加 let count = parseInt(localStorage.getItem(LOOP_COUNT_KEY) || "0") + 1; localStorage.setItem(LOOP_COUNT_KEY, count.toString()); cycleCountDisplay.textContent = "已循環:" + count + " 次"; updateStatus("瀏覽目標文章中 📄"); logMessage("🔔 開始在目標文章頁模擬瀏覽..."); let duration = randomDelay(...STAY_TIME); let startTime = Date.now(); while (Date.now() - startTime < duration && localStorage.getItem(AUTO_FLAG) === "true") { await scrollPage(); let remaining = Math.ceil((duration - (Date.now() - startTime)) / 1000); countdownDisplay.textContent = "目標頁倒數:" + remaining + "秒"; } if (localStorage.getItem(AUTO_FLAG) === "true") { updateStatus("結束目標文章瀏覽,準備返回首頁 🏠"); let waitTime = randomDelay(10000, 20000); await countdown(waitTime, "返回首頁等待"); window.location.href = homeUrl; } } // 模擬首頁瀏覽(包含隨機滾動、倒計時等待,以及隨機點擊文章內部模擬瀏覽,再返回首頁) async function simulateHomePage() { if (window.location.href.includes("/post/") || window.location.href.includes("/posts/")) return; updateStatus("瀏覽首頁中 🌐"); logMessage("🔔 開始在首頁模擬瀏覽..."); const startTime = Date.now(); const browseDuration = randomDelay(...BROWSE_TIME); let clickCount = 0; // 控制隨機點擊文章次數(最多 2 次) while (Date.now() - startTime < browseDuration && localStorage.getItem(AUTO_FLAG) === "true") { await scrollPage(); let remaining = Math.ceil((browseDuration - (Date.now() - startTime)) / 1000); countdownDisplay.textContent = "首頁倒數:" + remaining + "秒"; // 隨機觸發文章點擊(模擬使用者點進文章閱讀),機率 30% if (Math.random() < 0.3 && clickCount < 5) { logMessage("隨機點擊一篇文章..."); let posts = document.querySelectorAll('.x1xdureb.xkbb5z.x13vxnyz'); if (posts.length > 0) { const randomPost = posts[Math.floor(Math.random() * posts.length)]; randomPost.click(); logMessage("點擊了文章,等待模擬瀏覽..."); // 模擬在文章內瀏覽,停留 5~15秒 let articleDuration = randomDelay(5000, 15000); let articleStart = Date.now(); while (Date.now() - articleStart < articleDuration && localStorage.getItem(AUTO_FLAG) === "true") { await scrollPage(); } // 返回首頁(使用瀏覽器的 history.back() 模擬返回) window.history.back(); logMessage("返回首頁..."); await wait(randomDelay(2000, 5000)); // 停留 2~5秒 clickCount++; } } } if (localStorage.getItem(AUTO_FLAG) === "true") { updateStatus("結束首頁瀏覽,準備返回目標文章 📄"); let waitTime = randomDelay(5000, 10000); await countdown(waitTime, "返回目標等待"); window.location.href = targetUrl; } } // 自動恢復流程:根據當前 URL 執行對應的模擬過程 function autoContinue() { if (localStorage.getItem(AUTO_FLAG) === "true") { if (window.location.href.includes("/post/") || window.location.href.includes("/posts/")) { simulateTargetPage(); } else { simulateHomePage(); } } else { updateStatus("待命"); } } // ========= 建立工具欄 ========= // 加入 Emoji 使介面更活潑 const controlPanelDiv = document.createElement('div'); controlPanelDiv.style.position = 'fixed'; controlPanelDiv.style.top = '10px'; controlPanelDiv.style.right = '10px'; controlPanelDiv.style.backgroundColor = '#f1f1f1'; controlPanelDiv.style.padding = '10px'; controlPanelDiv.style.border = '1px solid #ccc'; controlPanelDiv.style.zIndex = '9999'; controlPanelDiv.style.fontSize = '14px'; controlPanelDiv.style.maxWidth = '300px'; // 【更新目標文章 ✏️】按鈕 const updateTargetBtn = document.createElement('button'); updateTargetBtn.textContent = "更新目標文章 ✏️"; updateTargetBtn.style.display = 'block'; updateTargetBtn.style.marginBottom = '5px'; updateTargetBtn.onclick = function() { const newPostUrl = prompt("請輸入新的目標文章 URL:"); if (newPostUrl) { targetUrl = newPostUrl; localStorage.setItem("THREADS_TARGET_URL", targetUrl); logMessage("🔄 目標文章連結已更新:" + targetUrl); updateStatus("目標文章更新完畢"); } }; // 【更新首頁 URL 🌐】按鈕 const updateHomeBtn = document.createElement('button'); updateHomeBtn.textContent = "更新首頁 URL 🌐"; updateHomeBtn.style.display = 'block'; updateHomeBtn.style.marginBottom = '5px'; updateHomeBtn.onclick = function() { const newHomeUrl = prompt("請輸入新的首頁 URL:"); if (newHomeUrl) { homeUrl = newHomeUrl; localStorage.setItem("HOME_URL", homeUrl); logMessage("🔄 首頁連結已更新:" + homeUrl); updateStatus("首頁更新完畢"); } }; // 開始與暫停按鈕 const startBtn = document.createElement('button'); startBtn.textContent = "開始 🚀"; startBtn.style.marginRight = '10px'; const pauseBtn = document.createElement('button'); pauseBtn.textContent = "暫停 ⛔"; // 將開始與暫停按鈕放在同一行 const btnContainer = document.createElement('div'); btnContainer.appendChild(startBtn); btnContainer.appendChild(pauseBtn); // 狀態顯示區 const statusDisplay = document.createElement('div'); statusDisplay.style.backgroundColor = '#fff'; statusDisplay.style.border = '1px solid #ccc'; statusDisplay.style.padding = '4px'; statusDisplay.style.margin = '4px 0'; statusDisplay.textContent = "狀態:待命"; // 倒計時顯示區 const countdownDisplay = document.createElement('div'); countdownDisplay.style.backgroundColor = '#fff'; countdownDisplay.style.border = '1px solid #ccc'; countdownDisplay.style.padding = '4px'; countdownDisplay.style.margin = '4px 0'; countdownDisplay.textContent = "倒計時:"; // 循環次數顯示區 const cycleCountDisplay = document.createElement('div'); cycleCountDisplay.style.backgroundColor = '#fff'; cycleCountDisplay.style.border = '1px solid #ccc'; cycleCountDisplay.style.padding = '4px'; cycleCountDisplay.style.margin = '4px 0'; cycleCountDisplay.textContent = "已循環:0 次"; // 日誌顯示區 const logArea = document.createElement('div'); logArea.style.height = '200px'; logArea.style.overflowY = 'auto'; logArea.style.backgroundColor = '#fff'; logArea.style.border = '1px solid #ccc'; logArea.style.padding = '5px'; // 組裝控制面板 controlPanelDiv.appendChild(updateTargetBtn); controlPanelDiv.appendChild(updateHomeBtn); controlPanelDiv.appendChild(btnContainer); controlPanelDiv.appendChild(statusDisplay); controlPanelDiv.appendChild(countdownDisplay); controlPanelDiv.appendChild(cycleCountDisplay); controlPanelDiv.appendChild(logArea); document.body.appendChild(controlPanelDiv); // -------------------- // 開始按鈕事件:設置 AUTO_FLAG 為 "true",重置循環計數,然後開始流程 // -------------------- startBtn.addEventListener('click', function() { localStorage.setItem(AUTO_FLAG, "true"); localStorage.setItem(LOOP_COUNT_KEY, "0"); cycleCountDisplay.textContent = "已循環:0 次"; logMessage("🚀 開始模擬..."); updateStatus("開始模擬"); // 若當前頁面不在目標文章頁(判斷條件:同時支援 "/post/" 或 "/posts/"),則跳轉 if (!(window.location.href.includes("/post/") || window.location.href.includes("/posts/"))) { window.location.href = targetUrl; } else { simulateTargetPage(); } }); // 暫停按鈕事件:將 AUTO_FLAG 設為 "false",重置循環計數 pauseBtn.addEventListener('click', function() { localStorage.setItem(AUTO_FLAG, "false"); logMessage("⛔ 模擬已暫停"); updateStatus("已暫停"); cycleCountDisplay.textContent = "已循環:0 次"; }); // -------------------- // 當頁面載入時,自動檢查是否需要恢復模擬 // -------------------- window.addEventListener('load', function() { if (localStorage.getItem(AUTO_FLAG) === "true") { logMessage("🔄 自動啟動檢測:恢復模擬"); let cnt = localStorage.getItem(LOOP_COUNT_KEY) || "0"; cycleCountDisplay.textContent = "已循環:" + cnt + " 次"; if (window.location.href.includes("/post/") || window.location.href.includes("/posts/")) { simulateTargetPage(); } else { simulateHomePage(); } } else { updateStatus("待命"); logMessage("頁面載入完成,請更新目標文章與首頁 URL,再點【開始 🚀】按鈕"); } }); // -------------------- // 自動恢復:根據當前 URL 執行對應模擬流程 // -------------------- function autoContinue() { if (localStorage.getItem(AUTO_FLAG) === "true") { if (window.location.href.includes("/post/") || window.location.href.includes("/posts/")) { simulateTargetPage(); } else { simulateHomePage(); } } else { updateStatus("待命"); } } // 若頁面是因跳轉而重載,延遲 3 秒執行 autoContinue setTimeout(autoContinue, 3000); })();