Export all X (Twitter) followings to a .txt file
// ==UserScript==
// @name X Followings Exporter
// @namespace http://tampermonkey.net/
// @version 0.2
// @description Export all X (Twitter) followings to a .txt file
// @author okiseji
// @match https://x.com/*/following
// @grant none
// ==/UserScript==
(function () {
'use strict';
const button = document.createElement('button');
button.textContent = 'EXPORT';
button.style.position = 'fixed';
button.style.top = '10px';
button.style.right = '10px';
button.style.zIndex = '1000';
button.style.padding = '10px';
button.style.backgroundColor = '#1DA1F2';
button.style.color = '#FFFFFF';
button.style.border = 'none';
button.style.borderRadius = '5px';
button.style.cursor = 'pointer';
document.body.appendChild(button);
button.addEventListener('click', async () => {
const followings = new Set();
let hasMore = true;
while (hasMore) {
const elements = document.querySelectorAll('a[href^="/"]');
elements.forEach(element => {
const href = element.getAttribute('href');
if (href) {
if (!href.match(/\/[^/]+\/[^/]+/) && !href.startsWith('/search?q=')) {
followings.add(`https://x.com${href}`); // 在每个 URL 前面加上 https://x.com
}
}
});
window.scrollTo(0, document.body.scrollHeight);
await new Promise(resolve => setTimeout(resolve, 3000));
const newElements = document.querySelectorAll('a[href^="/"]');
if (newElements.length === elements.length) {
hasMore = false;
}
}
const content = Array.from(followings).join('\n');
const blob = new Blob([content], { type: 'text/plain' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'followings.txt';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
alert(`Exported ${followings.size} followings to followings.txt!`);
});
})();