您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Greasy Fork is available in English.
在抖音、小红书、B站的作者主页采集当前作者所有视频的访问链接
// ==UserScript== // @name 抖音小红书B站视频链接采集器 // @namespace http://tampermonkey.net/ // @version 0.4 // @description 在抖音、小红书、B站的作者主页采集当前作者所有视频的访问链接 // @author Ksr Cursor // @match *://*.douyin.com/user/* // @match *://*.xiaohongshu.com/user/profile/* // @match *://space.bilibili.com/*/upload/video // @grant GM_setClipboard // @run-at document-end // @license GPL-3.0-or-later // ==/UserScript== (function() { 'use strict'; // 添加样式 const style = document.createElement('style'); style.textContent = ` .ksr-collect-btn { padding: 8px 16px; background-color: #FF2B2B; color: white; font-size: 14px; font-weight: bold; border: none; border-radius: 4px; cursor: pointer; transition: all 0.3s; margin-left: 10px; } .ksr-collect-btn:hover { background-color: #FF0000; } .ksr-toast { position: fixed; top: 80px; right: 20px; padding: 10px 20px; background-color: rgba(0, 0, 0, 0.7); color: white; border-radius: 4px; z-index: 1000000; opacity: 0; transition: opacity 0.3s; font-weight: bold; font-size: 16px; } .ksr-toast.show { opacity: 1; } .ksr-float-btn { position: fixed; top: 20px; right: 20px; padding: 10px 15px; background-color: #FF2B2B; color: white; font-size: 14px; font-weight: bold; border: 2px solid white; border-radius: 4px; cursor: pointer; z-index: 9999999; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2); } `; document.head.appendChild(style); // 创建提示气泡 const toast = document.createElement('div'); toast.className = 'ksr-toast'; toast.textContent = '已复制'; document.body.appendChild(toast); // 显示气泡提示 function showToast() { toast.classList.add('show'); setTimeout(() => { toast.classList.remove('show'); }, 2000); } // 复制到剪贴板 function copyToClipboard(text) { GM_setClipboard(text); showToast(); } // 获取当前域名 const currentHost = window.location.host; // 创建按钮 function createCollectButton() { // 检查按钮是否已存在 const existingBtn = document.querySelector('.ksr-collect-btn'); if (existingBtn) return existingBtn; const collectBtn = document.createElement('button'); collectBtn.className = 'ksr-collect-btn'; collectBtn.textContent = '采集链接'; collectBtn.title = '点击采集链接 (快捷键: Alt+1)'; // 添加点击事件 collectBtn.addEventListener('click', collectLinks); return collectBtn; } // 创建悬浮按钮(备用方案) function createFloatButton() { // 检查是否已存在 if (document.querySelector('.ksr-float-btn')) return; const floatBtn = document.createElement('button'); floatBtn.className = 'ksr-float-btn'; floatBtn.textContent = '采集链接'; floatBtn.title = '点击采集链接 (快捷键: Alt+1)'; floatBtn.addEventListener('click', collectLinks); document.body.appendChild(floatBtn); } // 按平台插入按钮 function insertButton() { if (currentHost.includes('douyin.com')) { insertDouyinButton(); } else if (currentHost.includes('xiaohongshu.com')) { insertXiaohongshuButton(); } else if (currentHost.includes('bilibili.com')) { insertBilibiliButton(); } } // 为抖音寻找按钮容器的辅助函数 function findDouyinButtonContainer() { const possibleContainers = [ // 1. 尝试通过关注按钮查找 Array.from(document.querySelectorAll('button')).filter(btn => btn.textContent && ( btn.textContent.includes('关注') || btn.textContent.includes('已关注') || btn.textContent.includes('私信') || btn.textContent.includes('分享') ) ), // 2. 尝试通过按钮容器类查找 document.querySelectorAll('[class*="action"], [class*="button-container"], [class*="profile-header"], [class*="tool"]'), // 3. 尝试抖音常用UI组件 document.querySelectorAll('[class*="user-info"], [class*="header-right"], [class*="operation"]') ]; // 扁平化并过滤掉空结果 const containers = possibleContainers .flat() .filter(el => el && el.parentNode); if (containers.length > 0) { // 优先考虑已有多个按钮的容器 for (const container of containers) { const buttons = container.querySelectorAll('button'); if (buttons.length >= 2) return container; } // 如果没有多按钮容器,返回第一个容器 return containers[0]; } return null; } // 插入抖音按钮 function insertDouyinButton() { let buttonContainer = null; // 1. 先尝试通过XPath查找 const selectors = [ // 原始XPath '//*[@id="user_detail_element"]/div/div[2]/div[3]/div', // 备选1: 更通用的CSS选择器路径 '//*[contains(@class, "user-info")]//*[contains(@class, "action")]', // 备选2: 查找按钮容器 '//*[contains(@class, "profile-header")]//*[contains(@class, "button") or contains(@class, "operation")]', // 备选3: 关注按钮旁 '//div[contains(@class, "following-button")]/parent::*', // 备选4: 按钮组合处 '//button[contains(text(),"关注") or contains(text(),"私信") or contains(text(),"分享")]/parent::*' ]; // 尝试每个XPath选择器 for (const selector of selectors) { try { const result = document.evaluate( selector, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null ); if (result && result.singleNodeValue) { buttonContainer = result.singleNodeValue; break; } } catch (err) { /* 忽略错误 */ } } // 2. 如果XPath查找失败,尝试通过DOM查找 if (!buttonContainer) { buttonContainer = findDouyinButtonContainer(); } // 3. 如果找到容器,添加按钮 if (buttonContainer) { buttonContainer.appendChild(createCollectButton()); return true; } return false; } // 插入小红书按钮 function insertXiaohongshuButton() { // 尝试多种选择器 const selectors = [ // 原始XPath '//*[@id="global"]/div[1]/header/div[2]/div/div[1]', // 主页操作区域 '//header//button[contains(text(), "关注") or contains(text(), "私信") or contains(@class, "follow")]/parent::*', // 用户资料头部区域 '//header//div[contains(@class, "user-action")]' ]; let buttonContainer = null; // 尝试每个选择器 for (const selector of selectors) { try { const result = document.evaluate( selector, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null ); if (result.singleNodeValue) { buttonContainer = result.singleNodeValue; break; } } catch (err) { /* 忽略错误 */ } } if (buttonContainer) { buttonContainer.appendChild(createCollectButton()); return true; } else { setTimeout(insertXiaohongshuButton, 2000); return false; } } // 插入B站按钮 function insertBilibiliButton() { // 检查是否已存在按钮 if (document.querySelector('.ksr-collect-btn')) { return true; } const buttonContainer = document.evaluate( '//*[@id="app"]/main/div[1]/div[2]/div/div[1]/div[1]', document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null ).singleNodeValue; if (buttonContainer) { buttonContainer.appendChild(createCollectButton()); return true; } else { setTimeout(insertBilibiliButton, 2000); return false; } } // 链接采集主函数 function collectLinks() { if (currentHost.includes('douyin.com')) { collectDouyinLinks(); } else if (currentHost.includes('xiaohongshu.com')) { collectXiaohongshuLinks(); } else if (currentHost.includes('bilibili.com')) { collectBilibiliLinks(); } } // 添加键盘快捷键 Alt+1 document.addEventListener('keydown', function(e) { if (e.altKey && e.key === '1') { e.preventDefault(); collectLinks(); } }); // 抖音视频链接采集 function collectDouyinLinks() { const videos = []; try { // 主要方法 const xpath = '//*[@id="user_detail_element"]/div//ul/li/div/a/@href'; const result = document.evaluate(xpath, document, null, XPathResult.ANY_TYPE, null); let href; while (href = result.iterateNext()) { const link = href.value; // 排除非视频链接 if (link.includes('/note/')) continue; // 完整化链接 if (link.startsWith('/video/')) { videos.push('https://www.douyin.com' + link); } } // 如果没有找到视频,尝试备用方法 if (videos.length === 0) { // 通过视频卡片元素定位 const videoCards = document.querySelectorAll('a[href*="/video/"]'); videoCards.forEach(card => { let href = card.getAttribute('href'); if (href && href.startsWith('/video/')) { videos.push('https://www.douyin.com' + href); } }); } } catch (err) { /* 忽略错误 */ } if (videos.length > 0) { copyToClipboard(videos.join('\n')); } else { alert('未找到视频链接'); } } // 小红书视频链接采集 function collectXiaohongshuLinks() { let videos = []; try { // 方法1: 通过视频区块查找 const videoSections = document.evaluate( "//section[.//span[contains(@class, 'play-icon')]]", document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null ); // 从每个视频区块中提取链接 for (let i = 0; i < videoSections.snapshotLength; i++) { const section = videoSections.snapshotItem(i); const linkNode = section.querySelector('a[href]'); if (linkNode) { let link = linkNode.getAttribute('href'); // 完整化链接 if (link.startsWith('/')) { link = 'https://www.xiaohongshu.com' + link; } videos.push(link); } } // 方法2: 如果没有找到视频,尝试备用方法 if (videos.length === 0) { const cards = document.querySelectorAll('a[href^="/explore/"]'); cards.forEach(card => { // 检查是否有视频标记 const isVideo = card.querySelector('.play-icon, .play, [class*="video"]'); if (isVideo) { const link = 'https://www.xiaohongshu.com' + card.getAttribute('href'); videos.push(link); } }); } } catch (err) { /* 忽略错误 */ } if (videos.length > 0) { copyToClipboard(videos.join('\n')); } else { alert('未找到视频链接'); } } // B站视频链接采集 function collectBilibiliLinks() { const videos = []; try { const xpath = '//*[@id="app"]/main/div[1]/div[2]/div/div[2]/div/div/div/div/div/div/div[2]/div[1]/a/@href'; const result = document.evaluate(xpath, document, null, XPathResult.ANY_TYPE, null); let href; while (href = result.iterateNext()) { let link = href.value; // 完整化链接 if (link.startsWith('//')) { link = 'https:' + link; } // 裁切链接 - 移除查询参数 const cleanLink = link.split('?')[0]; videos.push(cleanLink); } } catch (err) { /* 忽略错误 */ } if (videos.length > 0) { copyToClipboard(videos.join('\n')); } else { alert('未找到视频链接'); } } // 抖音特殊处理:尝试强制重试 let douyinRetryCount = 0; const MAX_DOUYIN_RETRIES = 10; function douyinFallbackCheck() { // 如果当前不是抖音,跳过此步骤 if (!currentHost.includes('douyin.com')) return; // 检查是否已经有按钮 if (document.querySelector('.ksr-collect-btn')) return; // 尝试再次插入 if (douyinRetryCount < MAX_DOUYIN_RETRIES) { const success = insertDouyinButton(); // 如果成功,不再尝试 if (success) return; // 增加重试次数,下次再尝试 douyinRetryCount++; setTimeout(douyinFallbackCheck, 2000); } else { // 超过重试次数,启用备用悬浮按钮 createFloatButton(); } } // 初始化 function initScript() { // 清除可能存在的旧按钮 const oldBtn = document.querySelector('.ksr-collect-btn'); if (oldBtn) oldBtn.remove(); // 删除可能存在的旧浮动按钮 const oldFloatBtn = document.querySelector('.ksr-float-btn'); if (oldFloatBtn) oldFloatBtn.remove(); // 插入按钮 setTimeout(insertButton, 1000); // 专门为抖音增加延迟检测 if (currentHost.includes('douyin.com')) { setTimeout(douyinFallbackCheck, 3000); } } // 监听DOM变化 function observeDOMChanges() { const observer = new MutationObserver(() => { // 每次DOM变化后检查是否需要重新插入按钮 if (!document.querySelector('.ksr-collect-btn') && !document.querySelector('.ksr-float-btn')) { clearTimeout(window.insertBtnTimer); window.insertBtnTimer = setTimeout(insertButton, 1000); // 为抖音特别处理 if (currentHost.includes('douyin.com')) { setTimeout(douyinFallbackCheck, 1500); } } }); // 开始观察整个document observer.observe(document.body, { childList: true, subtree: true }); } // 脚本初始化 if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initScript); } else { initScript(); } // 添加DOM变化观察 setTimeout(observeDOMChanges, 2000); })();