您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
基于真实文章链接选择器,自动滚动+关键词筛选+导出txt
// ==UserScript== // @name LOFTER合集一键导出txt文档 // @namespace http://tampermonkey.net/ // @version 1.0 // @description 基于真实文章链接选择器,自动滚动+关键词筛选+导出txt // @match *://*.lofter.com/view* // @grant none // @license MIT // @require https://code.jquery.com/jquery-3.6.0.min.js // ==/UserScript== (async function() { 'use strict'; const $ = window.jQuery; const delay = ms => new Promise(r => setTimeout(r, ms)); // 自动滚动到底部,等待文章加载,检测文章数稳定 async function autoScroll(maxAttempts = 40, interval = 1500) { let lastCount = 0, stableCount = 0; for(let i = 0; i < maxAttempts; i++) { window.scrollTo(0, document.body.scrollHeight); await delay(interval); const count = $("a[href*='/post/']").length; if(count === lastCount) { stableCount++; if(stableCount >= 3) break; } else { stableCount = 0; lastCount = count; } } return lastCount; } // 提取文章列表,去重 function extractArticles() { const articles = []; $("a[href*='/post/']").each(function(){ const url = $(this).attr("href"); let title = $(this).text().replace(/\s+/g, " ").trim(); if(url && title) { articles.push({url, title}); } }); // 去重 return [...new Map(articles.map(a => [a.url, a])).values()]; } // 根据文章页面尝试抓正文,尝试多个常用选择器 async function fetchContent(url) { try { const html = await $.get(url); const doc = new DOMParser().parseFromString(html, "text/html"); const selectors = [".post-text", ".text", ".post-content", ".article-desc", ".article-content"]; let content = ""; for(const sel of selectors) { const elems = doc.querySelectorAll(sel); if(elems.length) { content = Array.from(elems).map(e => e.textContent.trim()).join("\n\n"); if(content.length > 30) break; // 找到长度合理的正文就用 } } return content || ""; } catch(e) { console.warn("抓取正文失败:", url, e); return ""; } } // 导出文本 function exportTxt(data,keyword) { data.sort((a,b) => 0); // 若需时间排序,可加时间字段再排序 data.reverse(); let text = ""; data.forEach(item => { text += item.content.trim() + "\n\n---------------------------------\n\n"; }); const blob = new Blob([text], {type:"text/plain;charset=utf-8"}); const link = document.createElement("a"); link.href = URL.createObjectURL(blob); link.download = keyword ? `lofter_${keyword}.txt` : "lofter_文章导出.txt"; link.click(); URL.revokeObjectURL(link.href); } // 插入按钮UI function injectButton() { const btn = $('<button style="position:fixed;top:15px;right:15px;z-index:999999;padding:10px;background:#1e90ff;color:#fff;border:none;border-radius:6px;cursor:pointer;">输入文章标题并导出</button>'); $("body").append(btn); btn.on("click", async () => { const keyword = prompt("请输入关键词(留空导出全部):") || ""; btn.text("自动滚动加载中..."); const totalCount = await autoScroll(); btn.text(`加载到${totalCount}篇文章,开始抓正文...`); const articles = extractArticles(); const results = []; for(let i=0; i<articles.length; i++) { btn.text(`抓取正文 ${i+1}/${articles.length} ...`); const content = await fetchContent(articles[i].url); if(keyword === "" || content.includes(keyword) || articles[i].title.includes(keyword)) { results.push({...articles[i], content}); } await delay(800); } btn.text(`完成,匹配${results.length}篇,导出中...`); exportTxt(results,keyword); btn.text("输入文章标题并导出"); alert(`导出完成,共导出${results.length}篇文章`); }); } $(window).on("load", () => setTimeout(injectButton, 2000)); })();