您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Greasy Fork is available in English.
自动提取 Cookie 并请求竞价数据接口
// ==UserScript== // @name 获取竞价数据(shop.48.cn) // @namespace http://tampermonkey.net/ // @version 1.8.1 // @description 自动提取 Cookie 并请求竞价数据接口 // @author GPT // @match https://shop.48.cn/pai/item/* // @grant GM_xmlhttpRequest // @license MIT // ==/UserScript== (function () { 'use strict'; // 延迟函数 function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } // 获取起竞价 function getStartingBid() { const container = document.querySelector("#TabTab03Con1"); if (!container) return null; const html = container.innerHTML; const match = html.match(/起竞价:<span>(\d+)<\/span>元/); if (match && match[1]) { return parseInt(match[1], 10); } return null; } // ✅ 获取 URL 中的商品 ID function getItemIdFromURL() { const match = window.location.href.match(/item\/(\d+)/); return match ? match[1] : null; } // ✅ 构建 POST 参数 function buildParams(itemId) { return new URLSearchParams({ id: itemId, numPerPage: 100, pageNum: 0, r: Math.random().toString() }); } // ✅ 获取指定 Cookie 值 function getCookie(name) { const cookies = document.cookie.split("; "); for (const cookie of cookies) { const [key, value] = cookie.split("="); if (key === name) return value; } return null; } // ✅ 构建 Cookie 请求头 function buildCookieHeader() { const cookieNames = [ "Hm_lvt_f32737cfa62ed971bb3185792d3204eb", "route", ".AspNet.ApplicationCookie", "HMACCOUNT", "__RequestVerificationToken", "Hm_lpvt_f32737cfa62ed971bb3185792d3204eb" ]; const cookieMap = {}; cookieNames.forEach(name => { const value = getCookie(name); if (value) { cookieMap[name] = value; } else { console.warn(`未找到 cookie: ${name}`); } }); if (Object.keys(cookieMap).length === 0) return null; return Object.entries(cookieMap) .map(([k, v]) => `${k}=${v}`) .join("; "); } // ✅ 发起 POST 请求 async function fetchBidAmountAtIndex(targetIndex, itemId, cookieHeader, initialLimit = 100, maxLimit = 1000, pageSize = 100) { let validList = []; // 第一阶段:逐步放大 numPerPage // for (let numPerPage = initialLimit; numPerPage <= maxLimit; numPerPage += 100) { // const params = new URLSearchParams({ // id: itemId, // numPerPage: numPerPage.toString(), // pageNum: "0", // r: Math.random().toString() // }); // const response = await fetch("https://shop.48.cn/pai/GetShowBids", { // method: "POST", // headers: { // "Content-Type": "application/x-www-form-urlencoded", // "Cookie": cookieHeader // }, // body: params // }); // if (!response.ok) { // throw new Error(`请求失败,状态码 ${response.status}`); // } // const data = await response.json(); // console.error(data); // validList = data.list.filter(entry => entry.auction_status === 1); // if (validList.length >= targetIndex) { // console.error(validList); // return validList[targetIndex - 1].bid_amt; // } // // 如果这一页返回的数据已经小于请求条数,说明数据到底了,提前退出 // if (data.list.length < numPerPage) { // return 0; // } // } // 第二阶段:开始翻页 pageNum 从 1 往后翻 let pageNum = 1; initialLimit = 20 while (true) { const params = new URLSearchParams({ id: itemId, numPerPage: initialLimit.toString(), pageNum: pageNum.toString(), r: Math.random().toString() }); const response = await fetch("https://shop.48.cn/pai/GetShowBids", { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded", "Cookie": cookieHeader }, body: params }); if (!response.ok) { throw new Error(`请求失败,状态码 ${response.status}`); } const data = await response.json(); const dataList = data.list.slice(0, 20); const pageValid = dataList.filter(entry => entry.auction_status === 1); validList = validList.concat(pageValid); if (validList.length >= targetIndex) { return validList[targetIndex - 1].bid_amt; } if (data.PageCount < pageNum) { // 已到达最后一页 break; } if (pageNum % 3 === 0){ await sleep(900) } pageNum++; } return 0; } // 出价接口调用 async function placeBid(uid, amt, num = 1, code = "") { const formData = new URLSearchParams({ id: uid, amt: Math.ceil(amt).toString(), // 金额向上取整 num: num.toString(), code: code, r: Math.random().toString() }); try { const response = await fetch("/pai/ToBids", { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded" }, body: formData }); const data = await response.json(); // 页面提示和信息更新 if (!data.HasError) { layer?.msg?.(data.Message || "出价成功!"); const el1 = document.querySelector("#sp_auction_count_1"); if (el1) el1.innerText = data.ErrorCode; const el0 = document.querySelector("#sp_auction_count_0"); if (el0) el0.innerText = data.ErrorCode; // 可选函数(你可以取消注释) // SetInfoB(uid, 20, 0); // getInfoByTime(); return true; } else { layer?.msg?.(data.Message || "出价失败!"); const el1 = document.querySelector("#sp_auction_count_1"); if (el1) el1.innerText = data.ErrorCode; const el0 = document.querySelector("#sp_auction_count_0"); if (el0) el0.innerText = data.ErrorCode; await sleep(1000); return false; } } catch (error) { console.error("出价异常:", error); layer?.msg?.("出价接口调用失败"); return false; } } // 创建按钮 function createFetchButton() { // 1. 创建容器 const container = document.createElement("div"); container.id = "bid-fetch-container"; Object.assign(container.style, { position: "fixed", top: "80px", right: "20px", zIndex: "9999", display: "flex", flexDirection: "column", alignItems: "center", gap: "8px", backgroundColor: "white", padding: "12px", borderRadius: "10px", boxShadow: "0 0 10px rgba(0,0,0,0.2)", cursor: "move", // 设置鼠标样式 userSelect: "none" }); // 2. 拖动逻辑 let isDragging = false; let offsetX, offsetY; container.addEventListener("mousedown", function (e) { isDragging = true; offsetX = e.clientX - container.getBoundingClientRect().left; offsetY = e.clientY - container.getBoundingClientRect().top; document.body.style.userSelect = "none"; // 禁止文本选中 }); document.addEventListener("mousemove", function (e) { if (isDragging) { const left = e.clientX - offsetX; const top = e.clientY - offsetY; container.style.left = `${left}px`; container.style.top = `${top}px`; container.style.right = "auto"; // 防止初始 right 冲突 } }); document.addEventListener("mouseup", function () { isDragging = false; document.body.style.userSelect = ""; // 恢复文本选中 }); // 3. 输入框 // 目标名次输入框 + 标签 const rankLabel = document.createElement("label"); rankLabel.innerText = "目标名次:"; rankLabel.style.fontSize = "14px"; rankLabel.style.marginRight = "5px"; const rankInput = document.createElement("input"); rankInput.type = "number"; rankInput.id = "positionInput"; rankInput.placeholder = "输入第几位"; rankInput.min = "1"; Object.assign(rankInput.style, { padding: "6px", width: "140px", fontSize: "14px", borderRadius: "6px", border: "1px solid #ccc" }); // 预算金额输入框 + 标签 const budgetLabel = document.createElement("label"); budgetLabel.innerText = "预算金额(不填默认无限):"; budgetLabel.style.fontSize = "14px"; budgetLabel.style.marginRight = "5px"; const budgetInput = document.createElement("input"); budgetInput.type = "number"; budgetInput.placeholder = "¥"; budgetInput.style.width = "80px"; budgetInput.style.marginRight = "20px"; // 4. 按钮 const btn = document.createElement("button"); btn.innerText = "📥 获取竞价数据"; btn.id = "fetchBidsBtn"; Object.assign(btn.style, { padding: "10px 16px", fontSize: "16px", backgroundColor: "#4CAF50", color: "white", border: "none", borderRadius: "8px", cursor: "pointer" }); // 5. 显示框 const output = document.createElement("div"); output.id = "bidAmtOutput"; output.innerText = "等待结果..."; Object.assign(output.style, { marginTop: "4px", fontSize: "14px", color: "#333" }); // 6. 按钮点击逻辑(保持原样,不变) btn.addEventListener("click", async () => { btn.innerText = "⏳ 正在获取..."; btn.disabled = true; try { const index = parseInt(rankInput.value); const budget = parseFloat(budgetInput.value); if (isNaN(index) || index <= 0) { layer?.msg?.("请输入有效的目标名次!"); return; } if (budget <= 0) { layer?.msg?.("请输入有效的预算金额!"); return; } const itemId = getItemIdFromURL(); const params = buildParams(itemId); const cookieHeader = buildCookieHeader(); if (!cookieHeader) { output.innerText = "未获取到 cookie"; return; } // 获取出价金额 let bidAmt = await fetchBidAmountAtIndex(index, itemId, cookieHeader); // 如果获取失败,使用起竞价 if (bidAmt === 0) { const startingBid = getStartingBid(); if (startingBid !== null) { bidAmt = startingBid; output.innerText = `第 ${index} 位无人出价,使用起竞价 ¥${startingBid}`; } else { output.innerText = `第 ${index} 位无人出价,且未能获取起竞价`; return; } } else { output.innerText = `第 ${index} 位出价金额:¥${bidAmt}`; } //自动出价 if (cbInput.checked) { const finalBid = Math.ceil(bidAmt) + 1; if (!isNaN(budget) && finalBid > budget) { layer?.msg?.(`⚠️ 出价 ¥${finalBid} 超出预算 ¥${budget},不执行出价`); return; } const success = await placeBid(itemId, finalBid); if (success) { console.log("自动出价成功"); } else { layer?.msg?.("❌ 自动出价失败!"); } } } catch (err) { console.error(err); output.innerText = "请求出错,请查看控制台"; } finally { btn.innerText = "📥 获取竞价数据"; btn.disabled = false; } }); // 7. 添加复选框 const checkbox = document.createElement("label"); checkbox.style.fontSize = "14px"; checkbox.style.cursor = "pointer"; const cbInput = document.createElement("input"); cbInput.type = "checkbox"; cbInput.id = "autoBidCheckbox"; cbInput.style.marginRight = "4px"; checkbox.appendChild(cbInput); checkbox.appendChild(document.createTextNode("自动 +1 元出价")); const warning = document.createElement("div"); warning.innerText = "⚠️ 自动出价在测试阶段 慎用 勾选了则自动出价 未勾选仅做查询"; warning.style.color = "red"; warning.style.fontWeight = "bold"; warning.style.margin = "8px 0"; // 8. 加入页面 container.appendChild(rankLabel); container.appendChild(rankInput); container.appendChild(budgetLabel); container.appendChild(budgetInput); container.appendChild(warning); // 警告文本 container.appendChild(checkbox); // 自动+1元 container.appendChild(btn); // 获取按钮 container.appendChild(output); // 输出结果 document.body.appendChild(container); } // ✅ 主执行函数 async function run() { const itemId = getItemIdFromURL(); if (!itemId) { console.warn("未找到商品 ID"); return; } const params = buildParams(itemId); const cookieHeader = buildCookieHeader(); if (!cookieHeader) { console.error("未能获取必要的 cookie,可能是未登录"); return; } try { const data = await fetchBids(params, cookieHeader); console.log("竞价数据:", data); } catch (error) { console.error("竞价请求失败:", error); } } // 主入口 function init() { createFetchButton(); // 添加按钮 } // ✅ 启动脚本 init(); })();