您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Extracts texts, emojis, and hashtags in sequence, grouped by div, with a start button, real-time board, copy, and save functions.
// ==UserScript== // @name Full-Feature Sequential Text Extraction // @namespace http://tampermonkey.net/ // @version 1.3.1 // @description Extracts texts, emojis, and hashtags in sequence, grouped by div, with a start button, real-time board, copy, and save functions. // @match https://x.com/* // @grant MIT // ==/UserScript== (function () { 'use strict'; // Initialize an array to store extracted data grouped by div const extractedData = JSON.parse(localStorage.getItem('extractedData')) || []; let isExtractionActive = false; // To track if extraction is active // Create floating controls (board, start button, and other UI) const controls = document.createElement('div'); controls.style.position = 'fixed'; controls.style.bottom = '10px'; controls.style.right = '10px'; controls.style.backgroundColor = 'rgba(0, 0, 0, 0.8)'; controls.style.color = 'white'; controls.style.padding = '10px'; controls.style.fontSize = '14px'; controls.style.zIndex = '9999'; document.body.appendChild(controls); const startButton = document.createElement('button'); startButton.textContent = 'Start'; startButton.style.backgroundColor = 'seagreen'; startButton.style.color = 'white'; startButton.style.fontWeight = "700"; // Bold weight startButton.style.padding = '6px'; startButton.style.marginBottom = '10px'; controls.appendChild(startButton); const clearButton = document.createElement('button'); clearButton.textContent = 'Clear'; clearButton.style.backgroundColor = 'maroon'; clearButton.style.color = 'white'; clearButton.style.fontWeight = "700"; // Bold weight clearButton.style.padding = '6px'; clearButton.style.marginBottom = '10px'; clearButton.style.marginLeft = '8px'; controls.appendChild(clearButton); const display = document.createElement('div'); display.style.maxHeight = '200px'; display.style.overflowY = 'auto'; display.style.border = '1px solid white'; display.style.padding = '5px'; display.style.marginTop = '10px'; display.innerHTML = '<strong>Extracted Data:</strong><br>'; controls.appendChild(display); const copyButton = document.createElement('button'); copyButton.textContent = 'Copy to Clipboard'; copyButton.style.marginTop = '10px'; copyButton.style.backgroundColor = '#007BFF'; copyButton.style.color = 'white'; copyButton.style.fontWeight = "700"; // Bold weight copyButton.style.padding = '5px'; controls.appendChild(copyButton); const saveButton = document.createElement('button'); saveButton.textContent = 'Save as JSON'; saveButton.style.marginTop = '10px'; saveButton.style.backgroundColor = '#FF8C00'; saveButton.style.color = 'white'; saveButton.style.fontWeight = "700"; // Bold weight saveButton.style.padding = '5px'; controls.appendChild(saveButton); // Function to update the display board function updateDisplay() { display.innerHTML = '<strong>Extracted Data:</strong><br>' + extractedData.map((item, index) => `<div><strong>Div ${index + 1}:</strong> ${item}</div>`).join(''); localStorage.setItem('extractedData', JSON.stringify(extractedData)); } // Function to extract data from a single div, preserving sequence function extractFromDiv(div) { let result = ''; // Initialize as a string to build the output directly const children = div.childNodes; children.forEach((child) => { if (child.nodeType === Node.TEXT_NODE) { const text = child.textContent.trim(); if (text) { // Append text directly if (result && !result.endsWith(' ')) { result += ' '; } result += text; } } else if (child.nodeType === Node.ELEMENT_NODE) { if (child.tagName === 'SPAN') { const text = child.innerText.trim(); if (text) { if (result && !result.endsWith(' ')) { result += ' '; } result += text; } } else if (child.tagName === 'IMG') { const alt = child.getAttribute('alt'); if (alt) { result += alt; // Append emoji directly, no space needed } } else if (child.tagName === 'A' && child.getAttribute('role') === 'link') { const hashtag = child.innerText.trim(); if (hashtag) { if (!result.endsWith(' ')) { result += ' '; } result += hashtag; } } } }); return result.trim(); // Return the final formatted string, trimmed for safety } // Function to extract from all divs function extractAll() { const targetDivs = document.querySelectorAll('div[data-testid="tweetText"]'); targetDivs.forEach((div) => { const divData = extractFromDiv(div); // Add data if it's a new div if (divData && !extractedData.includes(divData)) { extractedData.push(divData); updateDisplay(); } }); } // Add functionality to the "Start Logging" button startButton.onclick = () => { if (!isExtractionActive) { isExtractionActive = true; startButton.textContent = 'Running...'; extractAll(); } }; // Add functionality to the "Clear Data" button clearButton.onclick = () => { extractedData.length = 0; // Clear the array updateDisplay(); }; // Save as JSON saveButton.onclick = () => { const blob = new Blob([JSON.stringify(extractedData, null, 2)], { type: 'application/json' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = 'extracted_data.json'; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); }; // Copy to Clipboard copyButton.onclick = () => { navigator.clipboard.writeText(JSON.stringify(extractedData, null, 2)); }; // MutationObserver to monitor new content on the page const observer = new MutationObserver(() => { if (isExtractionActive) { extractAll(); } }); observer.observe(document.body, { childList: true, subtree: true }); })();