您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
记录已经打开的笔记对应的视频数据和链接,可以随时复制或下载csv
当前为
// ==UserScript== // @name xiaohongshu_link // @namespace http://tampermonkey.net/ // @version 0.1.1 // @description 记录已经打开的笔记对应的视频数据和链接,可以随时复制或下载csv // @author xxmdmst // @match https://www.xiaohongshu.com/* // @icon https://www.xiaohongshu.com/favicon.ico // @grant none // @license MIT // ==/UserScript== (function () { 'use strict'; let table; function initGbkTable() { // https://en.wikipedia.org/wiki/GBK_(character_encoding)#Encoding const ranges = [ [0xA1, 0xA9, 0xA1, 0xFE], [0xB0, 0xF7, 0xA1, 0xFE], [0x81, 0xA0, 0x40, 0xFE], [0xAA, 0xFE, 0x40, 0xA0], [0xA8, 0xA9, 0x40, 0xA0], [0xAA, 0xAF, 0xA1, 0xFE], [0xF8, 0xFE, 0xA1, 0xFE], [0xA1, 0xA7, 0x40, 0xA0], ]; const codes = new Uint16Array(23940); let i = 0; for (const [b1Begin, b1End, b2Begin, b2End] of ranges) { for (let b2 = b2Begin; b2 <= b2End; b2++) { if (b2 !== 0x7F) { for (let b1 = b1Begin; b1 <= b1End; b1++) { codes[i++] = b2 << 8 | b1 } } } } table = new Uint16Array(65536); table.fill(0xFFFF); const str = new TextDecoder('gbk').decode(codes); for (let i = 0; i < str.length; i++) { table[str.charCodeAt(i)] = codes[i] } } function str2gbk(str, opt = {}) { if (!table) { initGbkTable() } const NodeJsBufAlloc = typeof Buffer === 'function' && Buffer.allocUnsafe; const defaultOnAlloc = NodeJsBufAlloc ? (len) => NodeJsBufAlloc(len) : (len) => new Uint8Array(len); const defaultOnError = () => 63; const onAlloc = opt.onAlloc || defaultOnAlloc; const onError = opt.onError || defaultOnError; const buf = onAlloc(str.length * 2); let n = 0; for (let i = 0; i < str.length; i++) { const code = str.charCodeAt(i); if (code < 0x80) { buf[n++] = code; continue } const gbk = table[code]; if (gbk !== 0xFFFF) { buf[n++] = gbk; buf[n++] = gbk >> 8 } else if (code === 8364) { buf[n++] = 0x80 } else { const ret = onError(i, str); if (ret === -1) { break } if (ret > 0xFF) { buf[n++] = ret; buf[n++] = ret >> 8 } else { buf[n++] = ret } } } return buf.subarray(0, n) } function copyToClipboard(text) { try { const textarea = document.createElement("textarea"); textarea.setAttribute('readonly', 'readonly'); textarea.value = text; document.body.appendChild(textarea); textarea.select(); let flag = document.execCommand("copy"); document.body.removeChild(textarea); return flag; } catch (e) { console.log(e); return false; } } let title2urls = new Map(); function interceptResponse() { const originalSend = XMLHttpRequest.prototype.send; XMLHttpRequest.prototype.send = function () { originalSend.apply(this, arguments); const self = this; let func = this.onreadystatechange; this.onreadystatechange = (e) => { if (func) { func.apply(self, e); } if (self.readyState !== 4 || self.responseURL.indexOf("/api/sns/web/v1/feed") === -1) return; let json = JSON.parse(self.response); if (!json.success) return; for (let item of json.data.items) { let noteCard = item.note_card; if (noteCard.type !== "video") { continue; } let interactInfo = noteCard.interact_info; let backup_urls = noteCard.video.media.stream.h264[0].backup_urls; for (let video_url of backup_urls) { if (video_url.indexOf("?") > -1) { window.video_url = video_url; title2urls.set(item.id, [ noteCard.title, interactInfo.liked_count, interactInfo.collected_count, interactInfo.comment_count, interactInfo.share_count, new Date(noteCard.time).toLocaleString(), video_url ]); // console.log(Array.from(title2urls.keys())); // console.log(Array.from(title2urls.values())); break; } } } } }; } interceptResponse(); function createButton(title, top) { top = top === undefined ? "60px" : top; const button = document.createElement('button'); button.textContent = title; button.style.position = 'fixed'; button.style.right = '5px'; button.style.top = top; button.style.zIndex = '90000'; document.body.appendChild(button); return button } function txt2file(txt, filename) { const blob = new Blob([txt], {type: 'text/plain'}); const url = URL.createObjectURL(blob); const link = document.createElement('a'); link.href = url; link.download = filename.replace(/[\/:*?"<>|]/g, ""); document.body.appendChild(link); link.click(); document.body.removeChild(link); URL.revokeObjectURL(url); } function downloadData(encoding) { let text = "标题,点赞数,收藏数,评论数,分享数,发布时间,下载链接\n"; Array.from(title2urls.values()).forEach(item => { text += '"' + item[0] + '",' + item.slice(1).join(",") + "\n" }); if (encoding === "gbk") text = str2gbk(text); txt2file(text, document.title + ".csv"); } let b1 = createButton("复制已加载链接", "60px"); let b2 = createButton("下载已加载数据", "81px"); let b3 = createButton("复制链接", "102px"); function copyUrl() { let urls = Array.from(title2urls.values()).map(item => item[item.length - 1]).join("\n"); if (copyToClipboard(urls)) b1.textContent = "复制成功"; else b1.textContent = "复制失败"; setTimeout(() => { b1.textContent = '复制已加载链接'; }, 2000); } function copyUrl2() { if (copyToClipboard(window.video_url)) b3.textContent = "复制成功"; else b3.textContent = "复制失败"; setTimeout(() => { b3.textContent = '复制链接'; }, 2000); } window.onload = () => { b1.addEventListener('click', copyUrl); b2.addEventListener('click', (e) => downloadData("gbk")); b3.addEventListener('click', copyUrl2); }; })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址