您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Greasy Fork is available in English.
抓取竞价页面信息并导出为Excel
// ==UserScript== // @name SNH商城票务信息统计 // @namespace http://tampermonkey.net/ // @version 0.2.4 // @description 抓取竞价页面信息并导出为Excel // @author You // @match https://shop.48.cn/* // @grant GM_download // @require https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.17.4/xlsx.full.min.js // @license MIT // ==/UserScript== /* global XLSX */ (function() { 'use strict'; // Your code here... // 确保 XLSX 已经加载 if (typeof XLSX === 'undefined') { console.error('XLSX library not loaded!'); return; } function parseBidsData(bidListElement, totalBids) { const liElements = bidListElement.querySelectorAll("li"); liElements.forEach(li => { try { const bidStatus = li.querySelector(".jl_1")?.innerText.trim(); // 竞价状态 const jl2Elements = li.querySelectorAll(".jl_2"); const bidder = jl2Elements[0]?.innerText.trim(); // 出价人 const bidTime = jl2Elements[1]?.innerText.trim(); // 出价时间 const bidAmount = li.querySelector(".jl_3")?.innerText.trim(); // 出价金额 if (bidStatus?.includes("竞价成功")) { totalBids.push({ "出价状态": bidStatus, "出价人": bidder, "出价时间": bidTime, "出价金额": bidAmount }); } else if (!bidStatus?.includes("竞价成功") && checkBidExist(totalBids, bidder)) { totalBids.push({ "出价状态": "竞价失败", "出价人": bidder, "出价时间": bidTime, "出价金额": bidAmount }); } } catch (e) { // 忽略异常 } }); return totalBids; } // 检查某个出价人在已有的竞价数据中是否存在 function checkBidExist(bidsData, bidder) { if (bidsData.length === 0) { return true; } for (const bid of bidsData) { if (bid["出价人"] && bid["出价人"].includes(bidder)) { // 如果出价人已经存在,则返回 false return false; } } // 如果出价人不存在,则返回 true return true; } // 模拟点击翻页按钮 function clickNextPage() { const element = document.querySelector("#a_b_n"); if (element) { //console.log("找到元素,准备模拟点击。"); // 模拟点击 element.click(); } else { console.log("未找到目标元素。"); } } // 延迟函数 function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } async function waitForElement(selectorFunc, timeout = 10000, interval = 100) { const start = Date.now(); while (Date.now() - start < timeout) { const el = selectorFunc(); if (el) return el; await sleep(interval); } throw new Error("元素加载超时"); } // 从竞价列表中提取成功竞价的信息 async function autoBidUntilEnd(targetSuccessfulCount, bidType, theaterName) { const totalBidsData = []; // 等待实际竞价人数元素加载 const actualBidNumberElement = await waitForElement(() => document.evaluate('/html/body/div[2]/div/div[2]/div[3]/div[1]/ul/li[7]/span/span[3]', document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue, 10000); if (parseInt(actualBidNumberElement?.innerText || "0") === 0) { return totalBidsData; } // 等待最大页码元素加载 let maxPageElement = await waitForElement(() => document.querySelector(".pink.b_c"), 10000); while (maxPageElement.innerText.trim() === '') { location.reload(); // 相当于 driver.refresh() maxPageElement = await waitForElement(() => document.querySelector(".pink.b_c"), 10000); } const maxPage = parseInt(maxPageElement.innerText.trim()); let nowPage = 1; while (nowPage <= maxPage) { updateOverlayMessage(`正在抓取第 ${nowPage} 页数据`); const uBlist = document.getElementById("u_blist"); if (uBlist) { parseBidsData(uBlist, totalBidsData); } const uBlistM = document.getElementById("u_blistM"); if (uBlistM) { parseBidsData(uBlistM, totalBidsData); } // 点击下一页按钮 const nextButton = await waitForElement(() => document.querySelector("#a_b_n"), 10000); if (nextButton) { nextButton.click(); console.log(`加载第 ${nowPage} 页...`); nowPage++; await sleep(1000); // 模拟 time.sleep(0.15) } else { break; // 找不到下一页按钮,跳出循环 } } updateOverlayMessage("数据抓取完毕,正在整理座位信息..."); // 获取座位数组 const seats = getSeatPosition(theaterName, bidType, targetSuccessfulCount); // 分配座位号 totalBidsData.forEach((bid, idx) => { bid["座位类型"] = bidType; bid["座位号"] = (idx >= seats.length) ? "竞价失败" : seats[idx]; }); return totalBidsData; } // 获取座位类型 function getSeatType(itemName) { if (itemName.includes("超级")) { return "超级"; } else if (itemName.includes("SVIP")) { return "SVIP"; } else if (itemName.includes("摄影")) { return "摄影"; } else if (itemName.includes("杆位")) { return "杆位"; } else if (itemName.includes("普站")) { return "普站"; } else if (itemName.includes("VIP")) { return "VIP"; } else if (itemName.includes("普座")) { return "普座"; } else if (itemName.includes("MINILIVE")) { return "MINILIVE"; } else if (itemName.includes("拍立得") || itemName.includes("百场徽章粉丝纪念礼盒")) { return "拍立得"; } else if (itemName.includes("生日会")) { return "生日会"; } else if (itemName.includes("全纪录")) { return "全纪录"; } else { return "其他"; } } // 获取座位号 function getSeatPosition(theaterName, bidType, bidCount = 0) { if (theaterName.includes("SNHbirthday") && bidCount === 71 && bidType === "普站") { return getSeatPositionSNHBirthday(bidType); } else if (theaterName.includes("SNHbirthday") && bidCount === 76 && bidType === "普站") { return getSeatPositionSNH(bidType); } else if (theaterName.includes("SNHbirthday")) { return getSeatPositionSNHBirthday(bidType); } else if (theaterName.includes("SNH")) { return getSeatPositionSNH(bidType); } else if (theaterName.includes("HGH")) { return getSeatPositionHGH(bidType); } else if (theaterName.includes("BEJ")) { return getSeatPositionBEJ(bidType); } else if (theaterName.includes("MINILIVE")) { return getSeatPositionMiniLive(bidCount); } else if (theaterName.includes("拍立得")) { return getSeatPositionPLD(bidCount); } else if (theaterName.includes("生日会")) { return getSeatPositionBirthParty(bidCount); } else if (theaterName.includes("全纪录")) { return getSeatPositionXiezhen(bidCount); } else if (theaterName.includes("其它")) { return getSeatPositionOther(bidCount); } } // 特殊公演+兑换生公 function getSeatPositionSNH(bidType) { // 根据竞价类型和索引为每个竞价分配座位号 let seats = []; // 普座 if (bidType === "普座") { // 6排1到6排18 let rows6Col1To18 = []; for (let j = 1; j <= 18; j++) { rows6Col1To18.push(`6排${j}`); } // 5排18、19 | 6排18、19 let rows5_6Col19To20 = []; for (let i = 5; i <= 6; i++) { for (let j = 19; j <= 20; j++) { rows5_6Col19To20.push(`${i}排${j}`); } } // 4排21、22 | 5排21、22 | 6排21、22 let rows4_6Col21To22 = []; for (let i = 4; i <= 6; i++) { for (let j = 21; j <= 22; j++) { rows4_6Col21To22.push(`${i}排${j}`); } } // 3排23、24 | 4排23、24 | 5排23、24 | 6排23、24 let rows3_6Col23To24 = []; for (let i = 3; i <= 6; i++) { for (let j = 23; j <= 24; j++) { rows3_6Col23To24.push(`${i}排${j}`); } } // 7排到10排 let rows7To10 = []; for (let i = 7; i <= 10; i++) { for (let j = 1; j <= 24; j++) { rows7To10.push(`${i}排${j}`); } } seats = rows6Col1To18.concat(rows5_6Col19To20, rows4_6Col21To22, rows3_6Col23To24, rows7To10); } else if (bidType === "SVIP") { seats = []; for (let i = 1; i <= 24; i++) { seats.push(`1排${i}`); } } else if (bidType === "VIP") { seats = []; for (let i = 2; i <= 5; i++) { for (let j = 1; j <= (25 - 2 * (i - 2)); j++) { seats.push(`${i}排${j}`); } } } else if (bidType === "摄影") { seats = []; for (let i = 1; i <= 24; i++) { seats.push(`1排${i}`); } } else if (bidType === "杆位") { seats = []; for (let i = 1; i <= 24; i++) { seats.push(`${i}`); } } else if (bidType === "普站") { seats = []; for (let i = 25; i <= 100; i++) { seats.push(`${i}`); } } else if (bidType === "超级") { seats = ["中", "左", "右"]; } return seats; } // 上海剧场圈内生公 function getSeatPositionSNHBirthday(bidType) { // 根据竞价类型和索引为每个竞价分配座位号 let seats = []; // 普座 if (bidType === "普座") { // 6排1到6排18 let rows6Col1To18 = []; for (let j = 1; j <= 18; j++) { rows6Col1To18.push(`6排${j}`); } // 5排18、19 | 6排18、19 let rows5_6Col19To20 = []; for (let i = 5; i <= 6; i++) { for (let j = 19; j <= 20; j++) { rows5_6Col19To20.push(`${i}排${j}`); } } // 4排21、22 | 5排21、22 | 6排21、22 let rows4_6Col21To22 = []; for (let i = 4; i <= 6; i++) { for (let j = 21; j <= 22; j++) { rows4_6Col21To22.push(`${i}排${j}`); } } // 3排23、24 | 4排23、24 | 5排23、24 | 6排23、24 let rows3_6Col23To24 = []; for (let i = 3; i <= 6; i++) { for (let j = 23; j <= 24; j++) { rows3_6Col23To24.push(`${i}排${j}`); } } // 7排1、3、5、7、9、11、13、15、17、19 let rows7Col1To19 = []; for (let j = 1; j <= 20; j++) { if (j % 2 !== 0) rows7Col1To19.push(`7排${j}`); } // 7排21、22、23、24 let rows7Col21To24 = []; for (let j = 21; j <= 24; j++) { rows7Col21To24.push(`7排${j}`); } // 8排到10排 let rows8To10 = []; for (let i = 8; i <= 10; i++) { for (let j = 1; j <= 24; j++) { rows8To10.push(`${i}排${j}`); } } seats = rows6Col1To18.concat(rows5_6Col19To20, rows4_6Col21To22, rows3_6Col23To24, rows7Col1To19, rows7Col21To24, rows8To10); } else if (bidType === "VIP") { let rows2Col2To10 = []; for (let j = 1; j <= 10; j++) { if (j % 2 === 0) rows2Col2To10.push(`2排${j}`); } let rows2Col11To24 = []; for (let j = 11; j <= 24; j++) { rows2Col11To24.push(`2排${j}`); } let rows3To5 = []; for (let i = 3; i <= 5; i++) { for (let j = 1; j <= (25 - 2 * (i - 2)); j++) { rows3To5.push(`${i}排${j}`); } } seats = rows2Col2To10.concat(rows2Col11To24, rows3To5); } else if (bidType === "摄影") { seats = []; for (let i = 1; i <= 24; i++) { seats.push(`1排${i}`); } } else if (bidType === "杆位") { seats = []; for (let i = 1; i <= 24; i++) { seats.push(`${i}`); } } else if (bidType === "普站") { let stand25To30 = []; for (let i = 25; i <= 30; i++) { stand25To30.push(`${i}`); } let stand31To100 = []; for (let i = 36; i <= 100; i++) { stand31To100.push(`${i}`); } seats = stand25To30.concat(stand31To100); } else if (bidType === "超级") { seats = ["中", "左", "右"]; } return seats; } // 杭州剧场 function getSeatPositionHGH(bidType) { // 根据竞价类型和索引为每个竞价分配座位号 let seats = []; // 普座 if (bidType === "超级") { // 1排1到1排25 let rows1Col1To25 = []; for (let j = 1; j <= 25; j++) { rows1Col1To25.push(`1排${j}`); } // 2排1到2排29 let rows2Col1To29 = []; for (let j = 1; j <= 29; j++) { rows2Col1To29.push(`2排${j}`); } seats = rows1Col1To25.concat(rows2Col1To29); // 普座座位 } else if (bidType === "摄影") { // 摄影座位 seats = []; for (let i = 1; i <= 19; i++) { seats.push(`11排${i}`); } } return seats; } // 北京剧场 function getSeatPositionBEJ(bidType) { // 根据竞价类型和索引为每个竞价分配座位号 let seats = []; // 普座 if (bidType === "超级") { seats = ["中", "左", "右"]; } else if (bidType === "VIP") { // VIP座位 let rows1to4 = []; for (let i = 1; i <= 4; i++) { for (let j = 1; j <= 17; j++) { rows1to4.push(`${i}排${j}`); } } let rows5 = ["5排3"]; for (let j = 5; j <= 17; j++) { rows5.push(`5排${j}`); } let rows6 = ["6排13"]; for (let j = 15; j <= 17; j++) { rows6.push(`6排${j}`); } seats = rows1to4.concat(rows5).concat(rows6); // 限制为84个 } else if (bidType === "摄影") { seats = ["6排3", "6排6", "6排5", "6排8", "6排7", "6排10", "6排9", "6排12", "6排11", "6排14"]; } return seats; } // MiniLice function getSeatPositionMiniLive(bidNumber) { // 根据竞价类型和索引为每个竞价分配座位号 let seats = []; for (let i = 1; i <= bidNumber; i++) { seats.push(i.toString()); // MINILIVE座位 } return seats; } // 拍立得 function getSeatPositionPld(bidNumber) { // 根据竞价类型和索引为每个竞价分配座位号 let seats = []; for (let i = 1; i <= bidNumber; i++) { seats.push(i.toString()); // 拍立得位置 } return seats; } // 冷餐 function getSeatPositionBirthParty(bidNumber) { // 根据竞价类型和索引为每个竞价分配座位号 let seats = []; for (let i = 1; i <= bidNumber; i++) { seats.push(i.toString()); // 冷餐座位 } return seats; } function calculateSeatCount(pattern1, pattern2, text) { // 匹配单一区间 const matches1 = [...text.matchAll(pattern1)]; // 匹配多个区间 const matches2 = [...text.matchAll(pattern2)]; let totalSeats = 0; // 如果有单一区间 if (matches1.length > 0) { matches1.forEach(match => { const start = parseInt(match[1]); const end = parseInt(match[2]); totalSeats += (end - start + 1); }); } // 如果有多个区间 else if (matches2.length > 0) { matches2.forEach(match => { const start1 = parseInt(match[1]); const end1 = parseInt(match[2]); totalSeats += (end1 - start1 + 1); // 处理第二个区间(如果存在) if (match[3] && match[4]) { const start2 = parseInt(match[3]); const end2 = parseInt(match[4]); totalSeats += (end2 - start2 + 1); } }); } return totalSeats; } function getBidNumberSNH(bidType) { // 获取竞价区域的信息 let itemInfo = ""; const element = document.querySelector("#TabTab03Con1"); itemInfo = element.textContent.trim(); // 如果是“普站” if (bidType.includes("普站")) { const seatPattern1 = /站区序号(\d{3})至(\d{3})/g; // 单一区间(如:025至100) const seatPattern2 = /站区序号(\d{3})至(\d{2})(?:、(\d{2})至(\d{3}))?/g; // 多个区间(如:025至30、36至100) const seatCount = calculateSeatCount(seatPattern1, seatPattern2, itemInfo); return seatCount; } // 如果是生日会 if (itemInfo.includes("生日潮流包")) { if (bidType.includes("SVIP")) return 24; if (bidType.includes("VIP")) return 79; if (bidType.includes("摄影")) return 24; if (bidType.includes("杆位")) return 24; if (bidType.includes("超级")) return 3; if (bidType.includes("普座")) return 122; return 0; } else { // 通用配置 if (bidType.includes("SVIP")) return 24; if (bidType.includes("VIP")) return 84; if (bidType.includes("摄影")) return 24; if (bidType.includes("杆位")) return 24; if (bidType.includes("超级")) return 3; if (bidType.includes("普座")) return 132; return 0; } } function getBidNumberHGH(bidType) { if (bidType.includes("超级")) { return 54; } else if (bidType.includes("摄影")) { return 19; } return 0; } function getBidNumberBEJ() { let itemInfo = ""; const element = document.querySelector("#TabTab03Con1"); itemInfo = element.textContent.trim(); // 使用正则表达式提取所有票数信息,只需包含 "演出门票" const ticketCounts = itemInfo.match(/.*?演出门票.*?(\d+)张/); // 如果找到了票数信息 if (ticketCounts) { return parseInt(ticketCounts[1]); // 取第一个匹配的票数 } else { return 0; } } function getBidNumberMiniLive() { let itemInfo = ""; const element = document.querySelector("#TabTab03Con1"); itemInfo = element.textContent.trim(); // 使用正则表达式提取所有票数信息,只需包含 "入场资格" const ticketCounts = itemInfo.text.match(/入场资格(\d+)位/g); // 如果找到了票数信息 if (ticketCounts) { return parseInt(ticketCounts[1]); // 取第一个匹配的票数 } else { return 0; } } function getBidNumberPLD() { let itemInfo = ""; const element = document.querySelector("#TabTab03Con1"); itemInfo = element.textContent.trim(); // 使用正则表达式提取所有票数信息,只需包含 "共" const ticketCounts = itemInfo.match(/.*?共.*?(\d+)套/); // 如果找到了票数信息 if (ticketCounts) { return parseInt(ticketCounts[1]); // 取第一个匹配的票数 } else { return 0; } } function getBidNumberBirthParty(theaterName) { let itemInfo = ""; const element = document.querySelector("#TabTab03Con1"); itemInfo = element.textContent.trim(); if (theaterName.includes("SNH")) { // 使用正则表达式提取所有票数信息,只需包含 "名额" const ticketCounts = itemInfo.match(/.*?名额:.*?(\d+)名/); // 如果找到了票数信息 if (ticketCounts) { return parseInt(ticketCounts[1]); // 取第一个匹配的票数 } else { return 0; } } else if (theaterName.includes("BEJ")) { // 使用正则表达式提取所有票数信息,只需包含 "竞拍数量" const ticketCounts = itemInfo.match(/.*?竞拍数量:.*?(\d+)张/); // 如果找到了票数信息 if (ticketCounts) { return parseInt(ticketCounts[1]); // 取第一个匹配的票数 } else { return 0; } } return 0; } function getSeatPositionXiezhen(bidNumber) { const seats = []; for (let i = 1; i <= bidNumber; i++) { seats.push(String(i)); } return seats; } function getSeatPositionOther(bidNumber) { const seats = []; for (let i = 1; i <= bidNumber; i++) { seats.push(String(i)); } return seats; } function getItemId() { const url = window.location.href; // 获取当前页面的完整 URL const path = new URL(url).pathname; // 获取 URL 的路径部分 const itemId = path.split('/').pop(); // 获取路径中的最后一部分作为 item_id return itemId; } function formatDate(date) { const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, '0'); const day = String(date.getDate()).padStart(2, '0'); const hours = String(date.getHours()).padStart(2, '0'); const minutes = String(date.getMinutes()).padStart(2, '0'); const seconds = String(date.getSeconds()).padStart(2, '0'); return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`; } function updateMinMaxInfo(data, wsData) { // 过滤出 "竞价成功" 的记录 const successfulBids = data.filter(bid => bid['出价状态'] === '竞价成功'); // 转换 '出价时间' 为 Date 类型,并将 '出价金额' 转换为数字 successfulBids.forEach(bid => { bid['出价时间'] = new Date(bid['出价时间']); bid['出价金额'] = parseFloat(bid['出价金额']); }); // 提取最早出价时间、最晚出价时间、最高出价、最低出价 const earliestBid = successfulBids.reduce((a, b) => (a['出价时间'] < b['出价时间'] ? a : b)); const latestBid = successfulBids.reduce((a, b) => (a['出价时间'] > b['出价时间'] ? a : b)); const highestBid = successfulBids.reduce((a, b) => (a['出价金额'] > b['出价金额'] ? a : b)); const lowestBid = successfulBids.reduce((a, b) => (a['出价金额'] < b['出价金额'] ? a : b)); // 插入数据到 wsData wsData.push([]); // 空行 wsData.push(['最早出价者', earliestBid['出价人'], formatDate(earliestBid['出价时间']), earliestBid['出价金额'], earliestBid['座位类型'], earliestBid['座位号']]); wsData.push(['最晚出价者', latestBid['出价人'], formatDate(latestBid['出价时间']), latestBid['出价金额'], latestBid['座位类型'], latestBid['座位号']]); wsData.push(['最高出价者', highestBid['出价人'], formatDate(highestBid['出价时间']), highestBid['出价金额'], highestBid['座位类型'], highestBid['座位号']]); wsData.push(['最低出价者', lowestBid['出价人'], formatDate(lowestBid['出价时间']), lowestBid['出价金额'], lowestBid['座位类型'], lowestBid['座位号']]); //console.log("已更新最早、最晚、最高、最低出价信息"); return wsData; } function saveExcel(successfulBidsData, itemName, outputFile = "bidding_results.xlsx") { // 创建 Excel 工作簿 const wb = XLSX.utils.book_new(); let wsData = []; // 写入商品名称 wsData.push([itemName]); // 写入表头 const header = ["出价状态", "出价人", "出价时间", "出价金额", "座位类型", "座位号"]; wsData.push(header); // 写入竞价数据 successfulBidsData.forEach(bid => { wsData.push([bid["出价状态"], bid["出价人"], bid["出价时间"], bid["出价金额"], bid["座位类型"], bid["座位号"]]); }); wsData = updateMinMaxInfo(successfulBidsData, wsData) // 将数据转换为工作表 const ws = XLSX.utils.aoa_to_sheet(wsData); // 格式化表头,设置加粗 for (let i = 0; i < header.length; i++) { // eslint-disable-next-line dot-notation ws['A1'].font = { bold: true }; // 表头加粗 } // 将工作表添加到工作簿 XLSX.utils.book_append_sheet(wb, ws, "Bidding Results"); // 生成 Excel 文件并下载 const wbOut = XLSX.write(wb, { bookType: "xlsx", type: "array" }); // 创建一个 Blob 对象并触发下载 const blob = new Blob([wbOut], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }); const link = document.createElement('a'); link.href = URL.createObjectURL(blob); link.download = outputFile; link.click(); console.log(`竞价信息已下载为 ${outputFile}`); } //霸屏信息框 function showOverlayMessage() { let overlay = document.createElement("div"); overlay.id = "tampermonkey-overlay"; overlay.style.position = "fixed"; overlay.style.top = "0"; overlay.style.left = "0"; overlay.style.width = "100vw"; overlay.style.height = "100vh"; overlay.style.backgroundColor = "rgba(0, 0, 0, 0.85)"; overlay.style.color = "#fff"; overlay.style.fontSize = "24px"; overlay.style.zIndex = "99999"; overlay.style.display = "flex"; overlay.style.flexDirection = "column"; overlay.style.justifyContent = "center"; overlay.style.alignItems = "center"; overlay.innerHTML = ` <div id="overlay-message" style="margin-bottom: 20px;">脚本正在运行中,请稍候...</div> <button id="overlay-close-btn" style=" display: none; padding: 10px 20px; font-size: 18px; background-color: #4CAF50; border: none; color: white; cursor: pointer; border-radius: 6px; ">关闭</button> `; document.body.appendChild(overlay); // 添加点击关闭功能 document.getElementById("overlay-close-btn").addEventListener("click", hideOverlayMessage); } function updateOverlayMessage(msg) { const now = new Date().toLocaleTimeString(); const messageElement = document.getElementById("overlay-message"); if (messageElement) { messageElement.textContent = `[${now}] ${msg}`; } } function hideOverlayMessage() { const overlay = document.getElementById("tampermonkey-overlay"); if (overlay) { overlay.remove(); } } async function statsOneGood() { showOverlayMessage(); // 显示霸屏提示 // 更新信息 updateOverlayMessage("正在初始化脚本..."); // 获取剧场名称和 Excel 文件名 const theaterNameElement = document.querySelector("body > div:nth-child(2) > div > div:nth-child(2) > div:nth-child(2) > ul > li:nth-child(2) > p"); const excelNameElement = document.querySelector("body > div.body-content > div > div:nth-child(2) > div.i_txt.ma_b10 > ul > li.i_tit"); let theaterName = theaterNameElement ? theaterNameElement.textContent.trim() : ""; const excelName = excelNameElement ? excelNameElement.textContent.trim() : ""; // 获取商品名称 const titleNameElement = document.querySelector("body > div.body-content > div > div:nth-child(2) > div.i_txt.ma_b10 > ul > li.i_tit"); const titleName = titleNameElement ? titleNameElement.textContent.trim() : ""; // 获取商品详细信息并判断是否为生日潮流包 const itemInfoElement = document.querySelector("#TabTab03Con1"); const itemInfoText = itemInfoElement ? itemInfoElement.innerText : ""; const birthday = itemInfoText.includes("生日潮流包"); // 获取竞价类型 const bidType = getSeatType(titleName); let maxBidNum = 46; let bidNumber = 0; if (theaterName.includes("SNH") && titleName.includes("星梦剧院") && !titleName.includes("MINILIVE") && titleName.includes("礼包")) { bidNumber = getBidNumberSNH(bidType); if (birthday) theaterName = "SNHbirthday"; } else if (theaterName.includes("SNH") && titleName.includes("星梦空间") && !titleName.includes("MINILIVE") && titleName.includes("礼包")) { bidNumber = getBidNumberHGH(bidType); theaterName = "HGH"; } else if (theaterName.includes("BEJ") && !titleName.includes("生日会")) { bidNumber = getBidNumberBEJ(); } else if (titleName.includes("MINILIVE")) { bidNumber = getBidNumberMiniLive(); theaterName = "MINILIVE"; } else if (titleName.includes("拍立得") || titleName.includes("百场徽章粉丝纪念礼盒")) { bidNumber = getBidNumberPLD(); theaterName = "拍立得"; } else if (titleName.includes("生日会")) { bidNumber = getBidNumberBirthParty(theaterName); theaterName = "生日会"; } else if (titleName.includes("全纪录")) { bidNumber = getBidNumberXiezhen(); theaterName = "全纪录"; } else { bidNumber = getBidNumberOther(); theaterName = "其它"; } // 获取座位数后更新显示 updateOverlayMessage(`一共有 ${maxBidNum} 个位置,正在加载数据...`); console.log(`一共有 ${maxBidNum} 个位置`); let totalBidsData = []; // 用于存储所有竞价成功信息 totalBidsData = await autoBidUntilEnd(maxBidNum, bidType, theaterName); //console.log(totalBidsData); // 获取商品 ID //const itemId = getItemId(); updateOverlayMessage("完成数据处理,准备保存 Excel..."); saveExcel(totalBidsData, excelName, excelName); // 更新提示信息 updateOverlayMessage("数据已保存完毕,您可以点击下方按钮关闭提示框"); // 显示关闭按钮 const closeBtn = document.getElementById("overlay-close-btn"); if (closeBtn) { closeBtn.style.display = "block"; } // 设置自动关闭(60秒后) setTimeout(() => { hideOverlayMessage(); }, 60000); } // 示例调用 (async function() { // 创建按钮 const button = document.createElement('button'); button.innerText = '开始统计'; button.style.position = 'absolute'; // 使用 absolute 定位 button.style.zIndex = '1000'; // 设置按钮样式 //button.style.border = '2px solid black'; // 边框为黑色 button.style.backgroundColor = '#59c4ec'; // 底色为蓝色 button.style.color = 'white'; // 字体为黑色 button.style.fontSize = '13px'; // 按钮字体大一号 button.style.padding = '2px 5px'; // 添加内边距让按钮更美观 button.style.cursor = 'pointer'; // 鼠标悬停时显示手型 // 设置按钮点击事件 button.onclick = function() { statsOneGood(); // 调用 statsOneGood 函数 }; // 获取目标元素 const targetElement = document.querySelector('.i_tit'); if (targetElement) { // 获取目标元素的位置 const rect = targetElement.getBoundingClientRect(); // 设置按钮的位置(上方展示) button.style.top = `${rect.top - 13}px`; // 距离目标元素上方 30px button.style.left = `${rect.left}px`; // 左对齐 // 将按钮添加到页面上 document.body.appendChild(button); } else { console.error('未找到目标元素 .i_tit'); } })(); })();