// ==UserScript== // @name 小红书广告数据查询与展示 // @namespace http://tampermonkey.net/ // @version 1.4 // @description 在当前页面插入悬浮元素,点击展开窗口并发送请求,将结果展示在表格中并提供Excel下载按钮 // @author You // @match https://ad.xiaohongshu.com/aurora* // @grant GM_xmlhttpRequest // @connect ad.xiaohongshu.com // @license MIT // @downloadURL https://update.greasyfork.icu/scripts/527362/%E5%B0%8F%E7%BA%A2%E4%B9%A6%E5%B9%BF%E5%91%8A%E6%95%B0%E6%8D%AE%E6%9F%A5%E8%AF%A2%E4%B8%8E%E5%B1%95%E7%A4%BA.user.js // @updateURL https://update.greasyfork.icu/scripts/527362/%E5%B0%8F%E7%BA%A2%E4%B9%A6%E5%B9%BF%E5%91%8A%E6%95%B0%E6%8D%AE%E6%9F%A5%E8%AF%A2%E4%B8%8E%E5%B1%95%E7%A4%BA.meta.js // ==/UserScript== (function () { "use strict"; // // // 进度条类定义 class ChainProgress { constructor() { this.totalSteps = 0; this.currentStep = 0; this.initDOM(); } // 初始化DOM结构(参考材料1†、3†) initDOM() { this.progressContainer = document.createElement('div'); this.progressBar = document.createElement('div'); this.stepDots = document.createElement('div'); Object.assign(this.progressContainer.style, { position: 'fixed', bottom: '0', left: '0', width: '100%', height: '8px', backgroundColor: '#eee', "z-index":2147483647 }); Object.assign(this.progressBar.style, { width: '0%', height: '100%', backgroundColor: '#4CAF50', transition: 'width 0.3s ease' // 添加平滑过渡(材料5†) }); Object.assign(this.stepDots.style, { position: 'absolute', top: '-20px', display: 'flex', justifyContent: 'space-between', width: '100%' }); this.progressContainer.appendChild(this.progressBar); this.progressContainer.appendChild(this.stepDots); document.body.appendChild(this.progressContainer); } // 设置总步数(材料6†) setTotal(steps) { this.totalSteps = steps; this.currentStep = 0; this.stepDots.innerHTML = Array(steps) .fill('
') .join(''); } // 推进进度(材料4†) next() { if(++this.currentStep > this.totalSteps) return; // 更新进度条(材料2†) const progress = (this.currentStep / this.totalSteps) * 100; this.progressBar.style.width = `${progress}%`; // 更新步骤点(链式效果) const dots = this.stepDots.children; if(dots[this.currentStep-1]) { dots[this.currentStep-1].style.background = '#4CAF50'; } // 完成处理(材料5†) if(this.currentStep === this.totalSteps) { setTimeout(() => { this.progressBar.style.width = '0%'; this.stepDots.innerHTML = ''; }, 2000); } } } /* -------------------- 使用示例 -------------------- */ // const progress = new ChainProgress(); // // 初始化设置总步数 // progress.setTotal(5); // // 每次事件成功调用 // document.querySelector('.btn').addEventListener('click', () => { // progress.next(); // }); // // □ // 创建日志系统核心类 class XinliuLogger { constructor() { this.maxEntries = 200; // 最大存储200条 this.entries = []; this.initUI(); } // 初始化界面 initUI() { GM_addStyle(` #xinliu-logger { position: fixed; bottom: 20px; right: 20px; width: 380px; height: 260px; background: rgba(40,40,40,0.95); color: #fff; font: 13px/1.5 'Consolas', monospace; z-index: 99999; border: 1px solid #555; box-shadow: 0 4px 12px rgba(0,0,0,0.2); border-radius: 6px; overflow: hidden; } .log-header { padding: 8px 12px; background: #333; border-bottom: 1px solid #444; display: flex; justify-content: space-between; align-items: center; } .log-content { height: calc(100% - 40px); overflow-y: auto; padding: 8px; } .log-entry { margin: 4px 0; padding: 6px; border-radius: 3px; animation: fadeIn 0.3s; } @keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } } .log-entry.info { background: rgba(26,82,118,0.7); } .log-entry.warn { background: rgba(183,149,11,0.7); } .log-entry.error { background: rgba(146,43,33,0.7); } .timestamp { color: #7f8c8d; margin-right: 10px; } .close-btn { background: #666; border: none; color: #fff; border-radius: 3px; padding: 2px 8px; cursor: pointer; } `); this.container = document.createElement("div"); this.container.id = "xinliu-logger"; this.container.innerHTML = `
Xinliu Logger v1.1
`; document.querySelector("body").appendChild(this.container); this.contentEl = this.container.querySelector(".log-content"); } // 核心日志方法 addEntry(level, ...args) { const timestamp = new Date().toLocaleTimeString(); const message = args .map((arg) => typeof arg === "object" ? JSON.stringify(arg, null, 2) : String(arg) ) .join(" "); // 创建日志条目 const entryEl = document.createElement("div"); entryEl.className = `log-entry ${level}`; entryEl.innerHTML = ` [${timestamp}] ${message} `; // 添加并维护条目数量 this.contentEl.appendChild(entryEl); this.entries.push(entryEl); if (this.entries.length > this.maxEntries) { this.contentEl.removeChild(this.entries.shift()); } // 自动滚动到底部 this.contentEl.scrollTop = this.contentEl.scrollHeight; } // 公开的日志方法 info(...args) { this.addEntry("info", ...args); } warn(...args) { this.addEntry("warn", ...args); } error(...args) { this.addEntry("error", ...args); } } // 初始化日志系统 // window.log = new XinliuLogger(); // // 使用示例 // setTimeout(() => { // log.info('系统初始化完成'); // log.warn('检测到非标准分辨率', window.screen.width + 'x' + window.screen.height); // log.error('API请求失败', { // status: 404, // url: location.href // }); // }, 1000); // 获取版本号 const getVersion = () => GM_info.script.version; function sleep(ms) { return new Promise((resolve) => setTimeout(resolve, ms)); } //提示========== // 注入样式 const style = document.createElement("style"); style.textContent = ` .custom-toast { position: fixed; left: 50%; transform: translateX(-50%); padding: 12px 24px; border-radius: 4px; background: #333; color: white; box-shadow: 0 2px 8px rgba(0,0,0,0.2); opacity: 0; transition: all 0.3s ease; z-index: 9999; top: 20px; margin-top: 0; } .custom-toast.show { opacity: 1; margin-top: 0 !important; } .custom-toast.success { background: #67c23a; } .custom-toast.warning { background: #e6a23c; } .custom-toast.error { background: #f56c6c; } .custom-toast.info { background: #909399; } `; document.head.appendChild(style); // 提示队列管理 const toastStack = { list: [], add(toast) { this.list.push(toast); this.updatePositions(); }, remove(toast) { this.list = this.list.filter((t) => t !== toast); this.updatePositions(); }, updatePositions() { this.list.forEach((toast, index) => { const baseTop = 20; const spacing = 60; const targetTop = baseTop + index * spacing; toast.style.top = `${targetTop}px`; }); }, }; // 提示函数 window.showToast = function (message, type = "info", duration = 3000) { const toast = document.createElement("div"); toast.className = `custom-toast ${type}`; toast.textContent = message; document.body.appendChild(toast); void toast.offsetHeight; // 触发重绘 toastStack.add(toast); toast.classList.add("show"); setTimeout(() => { toast.classList.remove("show"); setTimeout(() => { toast.remove(); toastStack.remove(toast); }, 300); }, duration); }; // // 使用示例 // showToast('第一个提示', 'success'); // setTimeout(() => showToast('第二个提示在下方', 'error'), 500); // setTimeout(() => showToast('第三个提示继续下移', 'info'), 1000); //提示---------- //圆球===================== const sheet = new CSSStyleSheet(); sheet.replaceSync(` /* 加载转圈圈 */ .loading { width: 30px; height: 30px; border: 2px solid #000; border-top-color: transparent; border-radius: 100%; animation: circle infinite 0.75s linear; } /* 加载转圈圈动画 */ @keyframes circle { 0% { transform: rotate(0); } 100% { transform: rotate(360deg); } } /* 下面是卡片的样式 */ #overlay { position: fixed; top: 50%; left: 50%; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.5); z-index: 999; transform: translate(-50%, -50%); } #card { position: fixed; top: 50%; left: 50%; width: 500px; /* 设置卡片的宽度 */ height: 300px; /* 设置卡片的高度 */ background-color: white; border: 1px solid #0057ff ; padding: 20px; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); z-index: 2147483647; transform: translate(-50%, -50%); border-radius: 8px } /* 下面是卡片中输入框还有下拉框的样式 */ #card select { width: 100%; padding: 12px 20px; margin: 8px 0; box-sizing: border-box; border: 2px solid #ccc; border-radius: 4px; background-color: #f8f8f8; font-size: 16px; -webkit-appearance: none; -moz-appearance: none; appearance: none; background-image: url('data:image/svg+xml;charset=US-ASCII,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22292.4%22%20height%3D%22292.4%22%3E%3Cpath%20fill%3D%22%23007CB2%22%20d%3D%22M287%2069.4a17.6%2017.6%200%200%200-13-5.4H18.4c-5%200-9.3%201.8-12.9%205.4A17.6%2017.6%200%200%200%200%2082.2c0%205%201.8%209.3%205.4%2012.9l128%20127.9c3.6%203.6%207.8%205.4%2012.8%205.4s9.2-1.8%2012.8-5.4L287%2095c3.5-3.5%205.4-7.8%205.4-12.8%200-5-1.9-9.2-5.5-12.8z%22%2F%3E%3C%2Fsvg%3E'); background-repeat: no-repeat; background-position: right 10px top 50%; background-size: 12px 12px; } #card label { display: block; margin-bottom: 8px; font-size: 16px; color: #333; font-weight: bold; } #card input[type="text"],#card textarea { width: 100%; padding: 12px 20px; margin: 8px 0; box-sizing: border-box; border: 2px solid #ccc; border-radius: 4px; background-color: #f8f8f8; font-size: 16px; } #card button,.card button { margin-bottom: 10px; margin-top: 10px; margin-left: 10px; margin-right: 10px; padding: 8px 16px; background-color: rgb(0, 102, 204); color: white; border: none; border-radius: 4px; cursor: pointer; } `); function addStyleSheet(sheet) { const allSheets = [...document.adoptedStyleSheets, sheet]; document.adoptedStyleSheets = allSheets; } addStyleSheet(sheet); // 存储请求返回的数据 let responseData = []; function addBallAttributes(ball, text) { ball.style.cssText = ` position: fixed; right: 10px; bottom: 10px; width: 60px; height: 60px; background-color: #0066CC; border-radius: 50%; cursor: pointer; display: flex; align-items: center; justify-content: center; font-size: 12px; color: white; z-index: 9999; `; ball.textContent = text; } // 创建隐藏的小球元素 const ball = document.createElement("div"); addBallAttributes(ball, "检查链接"); document.body.appendChild(ball); // 创建悬浮窗口元素 const floatingWindow = document.createElement("div"); floatingWindow.style.cssText = ` position: fixed; right: 20px; top: 20px; width: 50vw; height: 80vh; background-color: white; border: 1px solid #0066CC; border-radius: 8px; display: none; padding: 20px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); z-index: 9999; `; // 改成 cssom document.body.appendChild(floatingWindow); // 创建关闭按钮 const closeButton = document.createElement("div"); closeButton.style.cssText = ` position: absolute; right: 10px; top: 10px; cursor: pointer; font-size: 20px; color: #0066CC; `; // 改成 cssom closeButton.innerHTML = "×"; floatingWindow.appendChild(closeButton); // 创建按钮容器 const buttonContainer = document.createElement("div"); buttonContainer.style.cssText = ` margin-bottom: 20px; `; // 改成 cssom floatingWindow.appendChild(buttonContainer); function addButtonAttributes(checkButton, text) { checkButton.textContent = text; //"检查"; checkButton.style.cssText = ` margin-right: 10px; padding: 8px 16px; background-color: #0066CC; color: white; border: none; border-radius: 4px; cursor: pointer; `; // 改成 cssom } // 创建检查按钮 const checkButton = document.createElement("button"); addButtonAttributes(checkButton, "检查"); buttonContainer.appendChild(checkButton); // 创建下载按钮 const downloadButton = document.createElement("button"); addButtonAttributes(downloadButton, "下载"); buttonContainer.appendChild(downloadButton); // 创建链接统计文本容器 const linkStatsContainer = document.createElement("div"); linkStatsContainer.style.cssText = ` margin-bottom: 20px; font-size: 14px; color: #333333; `; // 改成 cssom floatingWindow.appendChild(linkStatsContainer); // 创建表格容器 const tableContainer = document.createElement("div"); tableContainer.style.cssText = ` height: calc(100% - 100px); overflow-y: auto; overflow-x: auto; `; // 改成 cssom floatingWindow.appendChild(tableContainer); // 创建进度条 const progressBar = document.createElement("progress"); progressBar.style.cssText = ` width: 100%; margin-top: 10px; display: none; `; // 改成 cssom progressBar.value = 0; progressBar.max = 100; floatingWindow.appendChild(progressBar); // 显示小球 ball.style.display = "flex"; // 点击小球展开悬浮窗口 ball.addEventListener("click", function () { floatingWindow.style.display = "block"; ball.style.display = "none"; }); // 点击关闭按钮 closeButton.addEventListener("click", function () { floatingWindow.style.display = "none"; ball.style.display = "flex"; tableContainer.innerHTML = ""; linkStatsContainer.innerHTML = ""; responseData = []; // 清空存储的数据 }); // 点击检查按钮发送请求 checkButton.addEventListener("click", function () { checkButton.disabled = true; checkButton.style.backgroundColor = "rgb(105, 102, 102)"; const loading = document.createElement("div"); loading.className = "loading"; loading.id = "loading-indicator"; // 添加一个唯一ID tableContainer.appendChild(loading); sendRequest().then(() => { checkButton.disabled = false; checkButton.style.backgroundColor = "rgb(0, 102, 204)"; // 使用更安全的方式移除loading const loadingElement = document.getElementById("loading-indicator"); if (loadingElement) { loadingElement.remove(); } }); }); // 点击下载按钮 downloadButton.addEventListener("click", function () { if (responseData.length > 0) { console.log(responseData); downloadExcel(responseData); } else { alert("没有可下载的数据!"); } }); // 发送请求 async function sendRequest() { let maxPageNum = 4; let pageNum = 1; let totalPage = 1; let allData = []; do { const headers = { accept: "application/json, text/plain, */*", "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6", "content-type": "application/json;charset=UTF-8", priority: "u=1, i", "sec-ch-ua": '"Not A(Brand";v="8", "Chromium";v="132", "Microsoft Edge";v="132"', "sec-ch-ua-mobile": "?0", "sec-ch-ua-platform": '"Windows"', "sec-fetch-dest": "empty", "sec-fetch-mode": "cors", "sec-fetch-site": "same-origin", Referer: location.href, Origin: location.origin, "User-Agent": navigator.userAgent, }; if (location.href.indexOf("vSellerId") != -1) { headers["v-seller-id"] = location.search.match( /(?<=vSellerId=)[0-9a-z].*/g ); } const response = await fetch( `https://ad.xiaohongshu.com/api/leona/rtb/creativity/list?pageNum=${pageNum}&pageSize=50`, { method: "POST", headers: headers, body: JSON.stringify({ startTime: new Date().toISOString().split("T")[0], endTime: new Date().toISOString().split("T")[0], pageNum: pageNum, pageSize: 50, }), } ); const data = await response.json(); // console.log(data.data.list); allData = allData.concat(data.data.list); totalPage = data.data.totalPage; pageNum++; } while (pageNum <= totalPage || pageNum <= maxPageNum); try { // 保存响应数据 responseData = allData; // 统计链接重复次数 const clickUrlCounts = {}; const expoUrlCounts = {}; allData.forEach((item) => { if (item.clickUrls && item.clickUrls[0]) { const clickUrl = extractUrlParam(item.clickUrls[0]); clickUrlCounts[clickUrl] = (clickUrlCounts[clickUrl] || 0) + 1; } if (item.expoUrls && item.expoUrls[0]) { const expoUrl = extractUrlParam(item.expoUrls[0]); expoUrlCounts[expoUrl] = (expoUrlCounts[expoUrl] || 0) + 1; } }); // 读取option 本地持久化的存储 const storedOption = localStorage.getItem("data"); const option = JSON.parse(storedOption); option.forEach((item) => { const link = item.link; const relink = link.match(/e=[^&]+/); if (relink) { item.relink = relink[0]; } else { item.relink = link; } }); console.log(option); if (storedOption) { Object.entries(clickUrlCounts).forEach(([url, count]) => { if (url) { const div = document.createElement("div"); div.style.cssText = ` margin-bottom: 5px; `; // 改成 cssom div.textContent = `点击链接:${url} 有${count}条`; const relink = url.match(/e=.*?(&|$)/)[0]; if (option.some((item) => item.relink === relink)) { div.textContent += ` 配置符合:${ option.find((item) => item.relink === relink).name }`; } else { div.textContent += " 无配置符合"; } linkStatsContainer.appendChild(div); } }); Object.entries(expoUrlCounts).forEach(([url, count]) => { if (url) { const div = document.createElement("div"); div.style.cssText = ` margin-bottom: 5px; `; // 改成 cssom div.textContent = `曝光链接:${url} 有${count}条`; const relink = url.match(/e=.*?(&|$)/)[0]; if (option.some((item) => item.relink === relink)) { div.textContent += ` 配置符合:${ option.find((item) => item.relink === relink).name }`; } else { div.textContent += " 无配置符合"; } linkStatsContainer.appendChild(div); } }); } else { Object.entries(clickUrlCounts).forEach(([url, count]) => { if (url) { const div = document.createElement("div"); div.style.cssText = ` margin-bottom: 5px; `; // 改成 cssom div.textContent = `点击链接:${url} 有${count}条`; div.textContent += " 无配置符合"; linkStatsContainer.appendChild(div); } }); Object.entries(expoUrlCounts).forEach(([url, count]) => { if (url) { const div = document.createElement("div"); div.style.cssText = ` margin-bottom: 5px; `; // 改成 cssom div.textContent = `曝光链接:${url} 有${count}条`; div.textContent += " 无配置符合"; linkStatsContainer.appendChild(div); } }); } createTable(allData); showToast("读取成功", "success"); } catch (error) { console.error("解析响应数据时出错:", error); showToast("读取报错,可能是没有配置", "error"); } } // 提取URL参数 function extractUrlParam(url) { const match = url.match(/https:\/\/magellan.alimama.com\/(.*?)&/); return match ? match[1] : ""; } // 创建表格 function createTable(data) { const table = document.createElement("table"); table.style.cssText = ` width: 100%; border-collapse: collapse; background-color: white; `; // 改成 cssom // 创建表头 const thead = document.createElement("thead"); thead.style.cssText = ` background-color: #0066CC; `; // 改成 cssom const headerRow = document.createElement("tr"); const headers = ["创建时间", "创意名", "创意ID", "点击链接", "曝光链接"]; headers.forEach((headerText) => { const th = document.createElement("th"); th.style.cssText = ` border: 1px solid #0066CC; padding: 12px; color: white; font-weight: bold; `; // 改成 cssom th.textContent = headerText; headerRow.appendChild(th); }); thead.appendChild(headerRow); table.appendChild(thead); // 创建表体 const tbody = document.createElement("tbody"); data.forEach((item, index) => { const row = document.createElement("tr"); row.style.cssText = ` background-color: ${index % 2 === 0 ? "#F5F8FA" : "white"}; `; // 改成 cssom const createTime = item.creativityCreateTime; const creativityName = item.creativityName; const creativityId = item.creativityId; const clickUrl = item.clickUrls ? JSON.stringify(item.clickUrls.map(extractUrlParam)).replace( /,/g, "\n" ) : ""; const expoUrl = item.expoUrls ? JSON.stringify(item.expoUrls.map(extractUrlParam)).replace(/,/g, "\n") : ""; const values = [ createTime, creativityName, creativityId, clickUrl, expoUrl, ]; values.forEach((value) => { const td = document.createElement("td"); td.style.cssText = ` border: 1px solid #E5E5E5; padding: 12px; color: #333333; `; // 改成 cssom td.textContent = value; row.appendChild(td); }); tbody.appendChild(row); }); table.appendChild(tbody); // 清空表格容器并插入新表格 tableContainer.innerHTML = ""; tableContainer.appendChild(table); } // 下载Excel function downloadExcel(data) { // 添加BOM头,解决中文乱码问题 // 数据是原始数据创意层级 下载添加笔记di const BOM = "\uFEFF"; const headers = [ "创建时间", "创意名", "创意ID", "点击链接", "曝光链接", "笔记id", ]; const csvContent = [headers.join(",")]; data.forEach((item) => { const createTime = item.creativityCreateTime || ""; const creativityName = item.creativityName || ""; const creativityId = item.creativityId || ""; const clickUrl = item.clickUrls && item.clickUrls[0] ? JSON.stringify(item.clickUrls.map(extractUrlParam)).replace( /,/g, "\n" ) : ""; const expoUrl = item.expoUrls && item.expoUrls[0] ? JSON.stringify(item.expoUrls.map(extractUrlParam)).replace( /,/g, "\n" ) : ""; const noteId = item.noteId + "" || ""; // 处理CSV中的特殊字符 const escapeCsvValue = (value) => { if (typeof value !== "string") return value; if ( value.includes(",") || value.includes('"') || value.includes("\n") ) { return `"${value.replace(/"/g, '""')}"`; } return value; }; const values = [ createTime, creativityName, creativityId, clickUrl, expoUrl, noteId, ].map(escapeCsvValue); csvContent.push(values.join(",")); }); const csv = BOM + csvContent.join("\n"); const blob = new Blob([csv], { type: "text/csv;charset=utf-8" }); const url = URL.createObjectURL(blob); const link = document.createElement("a"); const timestamp = new Date().toLocaleString().replace(/[/:]/g, "-"); link.setAttribute("href", url); link.setAttribute("download", `data_${timestamp}.csv`); document.body.appendChild(link); link.click(); document.body.removeChild(link); URL.revokeObjectURL(url); } function option() { const div = document.createElement("div"); div.className = "card"; div.style.cssText = ` position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); z-index: 9999; width: 500px; height: 300px; overflow-x: auto; overflow-y: auto; background: white; border: 1px solid rgb(0, 102, 204); border-radius: 8px; `; const table = document.createElement("table"); table.style.cssText = ` width: 100%; border-collapse: collapse; `; const addButton = document.createElement("button"); addButton.textContent = "添加"; addButton.onclick = () => { const newRow = document.createElement("tr"); const newTd1 = document.createElement("td"); const newLinkInput = document.createElement("input"); newLinkInput.type = "text"; newTd1.appendChild(newLinkInput); newRow.appendChild(newTd1); const newTd2 = document.createElement("td"); const newNameInput = document.createElement("input"); newNameInput.type = "text"; newTd2.appendChild(newNameInput); newRow.appendChild(newTd2); tbody.insertBefore(newRow, tbody.children[0]); }; const saveButton = document.createElement("button"); saveButton.textContent = "保存(关闭)"; saveButton.onclick = () => { const rows = tbody.rows; const data = []; for (let i = 0; i < rows.length; i++) { const link = rows[i].cells[0].children[0].value; const name = rows[i].cells[1].children[0].value; data.push({ link, name }); } localStorage.setItem("data", JSON.stringify(data)); div.style.display = "none"; }; const clearButton = document.createElement("button"); clearButton.textContent = "清空"; clearButton.onclick = () => { tbody.innerHTML = ""; // 清空tbody中的所有内容 }; div.appendChild(addButton); div.appendChild(saveButton); div.appendChild(clearButton); const thead = document.createElement("thead"); const tr = document.createElement("tr"); const th1 = document.createElement("th"); th1.textContent = "链接"; tr.appendChild(th1); const th2 = document.createElement("th"); th2.textContent = "名字"; tr.appendChild(th2); thead.appendChild(tr); const tbody = document.createElement("tbody"); const storedData = localStorage.getItem("data"); if (storedData) { const data = JSON.parse(storedData); data.forEach((item) => { const row = document.createElement("tr"); const td1 = document.createElement("td"); const linkInput = document.createElement("input"); linkInput.type = "text"; linkInput.value = item.link; td1.appendChild(linkInput); row.appendChild(td1); const td2 = document.createElement("td"); const nameInput = document.createElement("input"); nameInput.type = "text"; nameInput.value = item.name; td2.appendChild(nameInput); row.appendChild(td2); tbody.appendChild(row); }); } else { const row = document.createElement("tr"); const td1 = document.createElement("td"); const linkInput = document.createElement("input"); linkInput.type = "text"; td1.appendChild(linkInput); row.appendChild(td1); const td2 = document.createElement("td"); const nameInput = document.createElement("input"); nameInput.type = "text"; td2.appendChild(nameInput); row.appendChild(td2); tbody.appendChild(row); } table.appendChild(thead); table.appendChild(tbody); div.appendChild(table); document.body.appendChild(div); } //tools================== function create_car() { // 创建遮罩层 const overlay = document.createElement("div"); overlay.id = "overlay"; // 创建卡片 const card = document.createElement("div"); card.id = "card"; // 创建关闭按钮 const closeButton = document.createElement("span"); closeButton.textContent = "x"; closeButton.style.position = "absolute"; closeButton.style.top = "10px"; closeButton.style.right = "10px"; closeButton.style.cursor = "pointer"; closeButton.addEventListener("click", function () { document.body.removeChild(overlay); document.body.removeChild(card); }); card.appendChild(closeButton); return { overlay, card, closeButton, }; } //tools------------------- //======================改名 // 创建打开卡片的按钮 const openButton = document.createElement("button"); addButtonAttributes(openButton, "修改单元内计划字符"); // 为打开按钮添加点击事件监听器 openButton.addEventListener("click", function () { const { overlay, card, closeButton } = create_car(); // 创建第一个输入框及其标签 const oldCharLabel = document.createElement("label"); oldCharLabel.textContent = "旧字符"; const oldCharInput = document.createElement("input"); oldCharInput.type = "text"; // 创建第二个输入框及其标签 const newCharLabel = document.createElement("label"); newCharLabel.textContent = "新字符"; const newCharInput = document.createElement("input"); newCharInput.type = "text"; // 创建替换按钮 const replaceButton = document.createElement("button"); replaceButton.textContent = "替换"; replaceButton.addEventListener("click", async function () { const oldChar = oldCharInput.value; const newChar = newCharInput.value; await mainSend(oldChar, newChar); // 这里可以执行其他脚本,例如替换页面上的文本 console.log(`将 "${oldChar}" 替换为 "${newChar}"`); }); // 将元素添加到卡片中 card.appendChild(closeButton); card.appendChild(oldCharLabel); card.appendChild(oldCharInput); card.appendChild(newCharLabel); card.appendChild(newCharInput); card.appendChild(replaceButton); // 将遮罩层和卡片添加到页面中 document.body.appendChild(overlay); document.body.appendChild(card); }); async function mainSend(old1, new1) { const n = location.href.match(/[0-9]{1,20}/g); const headers = { accept: "application/json, text/plain, */*", "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6", "content-type": "application/json;charset=UTF-8", priority: "u=1, i", "sec-ch-ua": '"Not(A:Brand";v="99", "Microsoft Edge";v="133", "Chromium";v="133"', "sec-ch-ua-mobile": "?0", "sec-ch-ua-platform": '"macOS"', "sec-fetch-dest": "empty", "sec-fetch-mode": "cors", "sec-fetch-site": "same-origin", // "x-b3-traceid": "37e8ffc9e25f798c", }; if (location.href.indexOf("vSellerId") != -1) { headers["v-seller-id"] = location.search.match( /(?<=vSellerId=)[0-9a-z].*/g ); } const r = await fetch( "https://ad.xiaohongshu.com/api/leona/rtb/creativity/list", { headers: headers, // referrer: // "https://ad.xiaohongshu.com/aurora/ad/manage/103584356/192658846/creativity", referrerPolicy: "strict-origin-when-cross-origin", body: `{\"campaignId\":${n[0]},\"unitId\":${n[1]},\"startTime\":\"${ new Date().toISOString().split("T")[0] }\",\"endTime\":\"${ new Date().toISOString().split("T")[0] }\",\"pageNum\":1,\"pageSize\":50}`, method: "POST", mode: "cors", credentials: "include", } ); const j = await r.json(); const total = j.data.list.length; let completed = 0; const sheet = new CSSStyleSheet(); sheet.replaceSync(` #progressBar { width: 0; height: 20px; background-color: #54FF9F; position: fixed; bottom: 10px; left: 50%; transform: translateX(-50%); z-index: 2147483647; } `); addStyleSheet(sheet); // document.adoptedStyleSheets = [sheet]; const progressBar = document.createElement("div"); progressBar.id = "progressBar"; progressBar.innerText = "进度"; document.body.appendChild(progressBar); for (let index = 0; index < j.data.list.length; index++) { const element = j.data.list[index]; const oldName = element.creativityName; const regex = new RegExp(old1, "g"); const newName = oldName.replace(regex, new1); await reanmeSend(element.creativityId, newName); completed++; const progress = (completed / total) * 100; progressBar.style.width = `${progress}%`; } document.body.removeChild(progressBar); showToast("完成", "success"); // alert("完成"); } async function reanmeSend(id, name) { const headers = { accept: "application/json, text/plain, */*", "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6", "content-type": "application/json;charset=UTF-8", priority: "u=1, i", "sec-ch-ua": '"Not(A:Brand";v="99", "Microsoft Edge";v="133", "Chromium";v="133"', "sec-ch-ua-mobile": "?0", "sec-ch-ua-platform": '"macOS"', "sec-fetch-dest": "empty", "sec-fetch-mode": "cors", "sec-fetch-site": "same-origin", "x-b3-traceid": "dee287ce9b6526cc", }; if (location.href.indexOf("vSellerId") != -1) { headers["v-seller-id"] = location.search.match( /(?<=vSellerId=)[0-9a-z].*/g ); } return fetch( "https://ad.xiaohongshu.com/api/leona/rtb/creativity/batch/update/name", { headers: headers, //"referrer": "https://ad.xiaohongshu.com/aurora/ad/manage/103596579/192712174/creativity", referrerPolicy: "strict-origin-when-cross-origin", body: `{\"creativityId\":${id},\"creativityName\":\"${name}\"}`, method: "POST", mode: "cors", credentials: "include", } ); } //调价函数====================== function getCurrentTimestamp() { return Math.floor(Date.now() / 1000); } async function getData(body, bid, result) { body.removeBind = 0; body.sourceFlag = "web"; body.pageEnterTime = getCurrentTimestamp() - 10; body.pageSubmitTime = getCurrentTimestamp(); body.keywordWithBid.map((e) => { e.bid = bid * 100; }); const headers = { accept: "application/json, text/plain, */*", "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6", "content-type": "application/json", priority: "u=1, i", "sec-ch-ua": '"Chromium";v="134", "Not:A-Brand";v="24", "Microsoft Edge";v="134"', "sec-ch-ua-mobile": "?0", "sec-ch-ua-platform": '"Windows"', "sec-fetch-dest": "empty", "sec-fetch-mode": "cors", "sec-fetch-site": "same-origin", "x-b3-traceid": "631398efd0ea1db1", }; if (location.href.indexOf("vSellerId") != -1) { headers["v-seller-id"] = location.search.match( /(?<=vSellerId=)[0-9a-z].*/g ); } const r = await fetch("https://ad.xiaohongshu.com/api/leona/rtb/unit", { headers: headers, // "referrer": "https://ad.xiaohongshu.com/aurora/ad/edit/unit/107358958/208378008/4/2?byManage=true&manageLevel=byAccount&AFormGrayFlag=false", referrerPolicy: "strict-origin-when-cross-origin", body: JSON.stringify(body), method: "PUT", mode: "cors", credentials: "include", }); const j = await r.json(); showToast(`单元:【${body.unitName}】,id:【${body.unitId}】,${j.msg}`, "success"); console.log(`单元:【${body.unitName}】,id:【${body.unitId}】,${j.msg}`); result.push(`单元:【${body.unitName}】,id:【${body.unitId}】,调整出价${bid},${j.msg}`); } async function set_bid(bid, state, uidValue) { const headers = { accept: "application/json, text/plain, */*", "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6", "content-type": "application/json", priority: "u=1, i", "sec-ch-ua": '"Chromium";v="134", "Not:A-Brand";v="24", "Microsoft Edge";v="134"', "sec-ch-ua-mobile": "?0", "sec-ch-ua-platform": '"Windows"', "sec-fetch-dest": "empty", "sec-fetch-mode": "cors", "sec-fetch-site": "same-origin", "x-b3-traceid": "e900951027b4cc32", }; if (location.href.indexOf("vSellerId") != -1) { headers["v-seller-id"] = location.search.match( /(?<=vSellerId=)[0-9a-z].*/g ); } var data = []; let pageNum = 1; let totalPage = 1; // 修改价格 do w do { const r = await fetch( "https://ad.xiaohongshu.com/api/leona/rtb/unit/search", { headers: headers, referrer: "https://ad.xiaohongshu.com/aurora/ad/manage/creativity", referrerPolicy: "strict-origin-when-cross-origin", body: `{\"startTime\":\"${ new Date().toISOString().split("T")[0] }\",\"endTime\":\"${ new Date().toISOString().split("T")[0] }\",\"pageNum\":${pageNum},\"pageSize\":100,\"placementList\":[2]}`,//placementList是搜索 method: "POST", mode: "cors", credentials: "include", } ); const j = await r.json(); data = data.concat(j.data.list); totalPage = j.data.totalPage; pageNum++; } while (pageNum <= totalPage); showToast(`获取数据:当前获取总单元${data.length}条\n开始执行调价`, "info"); const result = []; if (state == "all") { console.log("全部调整"); showToast(`当前模式全部调整`, "info"); } if (state == "uid") { console.log("只调整输入"); showToast(`当前模式根据输入调整`, "info"); const uid = uidValue.trim().split("\n"); var t = []; for (let index = 0; index < uid.length; index++) { const element = uid[index]; if (data.filter((item) => item.unitId == element).length > 0) { t.push(data.filter((item) => item.unitId == element)[0]); } } data = t; } const progress = new ChainProgress(); progress.setTotal(data.length); /* -------------------- 使用示例 -------------------- */ // // // 初始化设置总步数 // // // 每次事件成功调用 // document.querySelector('.btn').addEventListener('click', () => { // // }); for (let index = 0; index < data.length; index++) { const element = data[index]; showToast(`当前执行单元${element.unitName},调整出价为${bid}`, "info"); console.log(`当前执行单元${element.unitName},调整出价为${bid}`); await getData(element, bid, result); progress.next(); await sleep(1000); } alert(result.join("\n")); return 1; } //调价函数---------------------- // 创意开启关闭创意============================ // 关闭计划 async function closePlan(chunkedA, isColse) { const text = isColse == 1 ? "开启创意" : "关闭创意"; const headers = { accept: "application/json, text/plain, */*", "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6", "content-type": "application/json;charset=UTF-8", priority: "u=1, i", "sec-ch-ua": '"Not(A:Brand";v="99", "Microsoft Edge";v="133", "Chromium";v="133"', "sec-ch-ua-mobile": "?0", "sec-ch-ua-platform": '"macOS"', "sec-fetch-dest": "empty", "sec-fetch-mode": "cors", "sec-fetch-site": "same-origin", "x-b3-traceid": "c1adc74c127d40f2", }; if (location.href.indexOf("vSellerId") != -1) { headers["v-seller-id"] = location.search.match( /(?<=vSellerId=)[0-9a-z].*/g ); } for (let i = 0; i < chunkedA.length; i++) { const ids = chunkedA[i]; let retry = true; while (retry) { const r = await fetch( "https://ad.xiaohongshu.com/api/leona/rtb/creativity/batch/status", { headers: headers, referrer: "https://ad.xiaohongshu.com/aurora/ad/manage/creativity", referrerPolicy: "strict-origin-when-cross-origin", // 2是关闭 1是开启 body: JSON.stringify({ ids: ids, actionType: parseInt(isColse), }), method: "PUT", mode: "cors", credentials: "include", } ); const res = await r.json(); console.log(res.msg); if (res.msg === "成功") { showToast(`${text},${res.msg}:${JSON.stringify(ids)}`, "success"); retry = false; } else { retry = true; } await new Promise((resolve) => setTimeout(resolve, 500)); } } } // 关闭计划笔记 noteid 和 名称 async function closePlanNote(ids, isColse, creativeIdSelect) { // 确保 isColse 是有效的值 if (isColse === null || isColse === undefined) { showToast.error("isColse 参数无效"); return; // 或者抛出错误 } const headers = { accept: "application/json, text/plain, */*", "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6", "content-type": "application/json;charset=UTF-8", priority: "u=1, i", "sec-ch-ua": '"Not(A:Brand";v="99", "Microsoft Edge";v="133", "Chromium";v="133"', "sec-ch-ua-mobile": "?0", "sec-ch-ua-platform": '"macOS"', "sec-fetch-dest": "empty", "sec-fetch-mode": "cors", "sec-fetch-site": "same-origin", "x-b3-traceid": "c1adc74c127d40f2", }; if (location.href.indexOf("vSellerId") != -1) { headers["v-seller-id"] = location.search.match( /(?<=vSellerId=)[0-9a-z].*/g ); } for (let index = 0; index < ids.length; index++) { const id = ids[index]; var bbody = ``; // 判断是否还有制表符 if (id.indexOf("\t") != -1) { const idArr = id.split("\t"); const n = idArr[1] == "信息流" ? 1 : 2; bbody = `{\"startTime\":\"2025-03-27\",\"endTime\":\"2025-03-27\",\"${creativeIdSelect.value}\":\"${idArr[0]}\",\"pageNum\":1,\"pageSize\":50,\"placementList\":[${n}]}`; } else { const idArr = [id]; bbody = `{\"startTime\":\"2025-03-27\",\"endTime\":\"2025-03-27\",\"${creativeIdSelect.value}\":\"${idArr[0]}\",\"pageNum\":1,\"pageSize\":50}`; } const r = await fetch( "https://ad.xiaohongshu.com/api/leona/rtb/creativity/list", { headers: headers, referrer: "https://ad.xiaohongshu.com/aurora/ad/manage/creativity", referrerPolicy: "strict-origin-when-cross-origin", body: bbody, method: "POST", mode: "cors", credentials: "include", } ); const res = await r.json(); if (res.data.list.length > 0) { const data = res.data.list.map((e) => e.creativityId); const chunkedA = data.reduce((acc, _, index) => { const chunkIndex = Math.floor(index / 50); if (!acc[chunkIndex]) { acc[chunkIndex] = []; } acc[chunkIndex].push(_); return acc; }, []); console.log(isColse); await closePlan(chunkedA, isColse); } } } function split_array(array, number) { // 将数组a以number个为一组切割 const chunkedA = array.reduce((acc, _, index) => { const chunkIndex = Math.floor(index / number); if (!acc[chunkIndex]) { acc[chunkIndex] = []; } acc[chunkIndex].push(_); return acc; }, []); return chunkedA; } // 创意开启关闭创意----------------------------- // 创建配置按钮 const optionButton = document.createElement("button"); addButtonAttributes(optionButton, "配置"); // 开启关闭创意============================ const openOrClose = document.createElement("button"); addButtonAttributes(openOrClose, "关闭/开启创意"); openOrClose.onclick = () => { const { overlay, card, closeButton } = create_car(); // 创建第一个下拉列表 const creativeIdSelect = document.createElement("select"); creativeIdSelect.options.add(new Option("创意ID", "creativeId")); creativeIdSelect.options.add(new Option("文字匹配", "name")); creativeIdSelect.options.add(new Option("笔记ID", "noteId")); card.appendChild(creativeIdSelect); // 创建第二个下拉列表 const toggleSelect = document.createElement("select"); toggleSelect.options.add(new Option("关闭", "2")); toggleSelect.options.add(new Option("开启", "1")); card.appendChild(toggleSelect); // 创建多行文本输入框 const textArea = document.createElement("textarea"); card.appendChild(textArea); //1 是信息流 2是搜索 // \"placementList\":[2] // 创建请求按钮 const requestButton = document.createElement("button"); requestButton.textContent = "请求"; requestButton.onclick = async () => { const input_list = textArea.value .trim() .split(/\n|,\n/g) .map((e) => e.trim()); const d = toggleSelect.value; if (input_list.length === 0) { showToast("请输入内容", "error"); return; } if (input_list[0].length <= 11 && creativeIdSelect.value === "noteId") { showToast("不符合笔记ID", "error"); return; } if ( input_list[0].length >= 11 && creativeIdSelect.value === "creativeId" ) { showToast("不符合创意ID", "error"); return; } console.log(creativeIdSelect.value); if (creativeIdSelect.value === "creativeId") { const chunkedA = split_array(input_list, 50); // console.log(); closePlan(chunkedA, d); } if ( creativeIdSelect.value === "name" || creativeIdSelect.value === "noteId" ) { const chunkedA = input_list; closePlanNote(chunkedA, d, creativeIdSelect); } }; card.appendChild(requestButton); // 将遮罩层和卡片添加到页面中 document.body.appendChild(overlay); document.body.appendChild(card); }; // 批量调价搜索词 const modify_the_price = document.createElement("button"); addButtonAttributes(modify_the_price, "批量调整出价"); modify_the_price.onclick = () => { const { overlay, card, closeButton } = create_car(); // 创建第一个下拉列表 const creativeIdSelect = document.createElement("select"); creativeIdSelect.options.add(new Option("全部调价", "all")); creativeIdSelect.options.add(new Option("单元id调价", "uid")); const priceInput = document.createElement("input"); priceInput.type = "number"; priceInput.id = "dynamicPriceInput"; priceInput.inputMode = "numeric"; priceInput.pattern = "[0-9]*\\.?[0-9]*"; priceInput.placeholder = "请输入金额"; priceInput.autocomplete = "off"; priceInput.step = "0.01"; const textArea = document.createElement("textarea"); textArea.style.display = "none" textArea.placeholder = "请输入单元ID"; creativeIdSelect.addEventListener("change", function () { // 判断是否选择第二个选项(索引从0开始) if (this.value === "uid") { // 或判断值:this.value === '2' textArea.style.display = "block"; } else { textArea.style.display = "none"; } }); card.appendChild(creativeIdSelect); card.appendChild(priceInput); // 创建多行文本输入框 card.appendChild(textArea); //1 是信息流 2是搜索 // \"placementList\":[2] // 创建请求按钮 const requestButton = document.createElement("button"); requestButton.textContent = "请求"; requestButton.addEventListener("click",async function() { this.disabled = true; const c = this.style.backgroundColor this.style.backgroundColor = "rgb(105, 102, 102)"; const Newbid = priceInput.valueAsNumber; const r = await set_bid(Newbid, creativeIdSelect.value, textArea.value); this.style.backgroundColor = c; this.disabled = false; }); // const bid = prompt("请输入出价"); // //判断bid是否是数值 并且就bid转换成小数 // if (isNaN(bid)) { // showToast("请输入数字", "error"); // return; // } // if (bid) { // var Newbid = parseFloat(bid); // set_bid(Newbid); // } card.appendChild(requestButton); // 将遮罩层和卡片添加到页面中 document.body.appendChild(overlay); document.body.appendChild(card); }; // const download_today = document.createElement("button"); // addButtonAttributes(download_today, "下载今日创建"); // download_today.onclick = () => { // fetch("https://ad.xiaohongshu.com/api/leona/rtb/creativity/list", { // "headers": { // "accept": "application/json, text/plain, */*", // "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6", // "content-type": "application/json", // "priority": "u=1, i", // "sec-ch-ua": "\"Chromium\";v=\"134\", \"Not:A-Brand\";v=\"24\", \"Microsoft Edge\";v=\"134\"", // "sec-ch-ua-mobile": "?0", // "sec-ch-ua-platform": "\"macOS\"", // "sec-fetch-dest": "empty", // "sec-fetch-mode": "cors", // "sec-fetch-site": "same-origin", // "x-b3-traceid": "268ef6d4ba91e008" // }, // "referrer": "https://ad.xiaohongshu.com/aurora/ad/manage/creativity", // "referrerPolicy": "strict-origin-when-cross-origin", // "body": "{\"startTime\":\"2025-03-28\",\"endTime\":\"2025-03-28\",\"creativityCreateBeginTime\":\"2025-03-27\",\"creativityCreateEndTime\":\"2025-03-27\",\"pageNum\":1,\"pageSize\":20}", // "method": "POST", // "mode": "cors", // "credentials": "include" // }); // }; // 加载元素 optionButton.onclick = option; buttonContainer.appendChild(optionButton); buttonContainer.appendChild(openButton); buttonContainer.appendChild(openOrClose); buttonContainer.appendChild(modify_the_price); // buttonContainer.appendChild(download_today); })();