|
|
动机
像试着统计一下自己究竟通过售卖附件获得了多少金币,就调教Gemini写了这个脚本。虽然最终效果不尽如人意,但由于是对“积分记录”这个页面的大部分选项都有效,或许还有一些我没想到过的用途。
功能
这个脚本在积分记录页面添加了一个“一键统计”按钮,选择好几个限制条件后点击一下,就可以统计出相关的条目数和总的积分变化。
美中不足的是由于论坛限制,超过100页的部分获取不到,会显示“分页数不在允许的范围内”,按照每页20条计算,只能获取到前2000条。如果发帖很多、售卖附件获得金币的条目数也很多的话,就得自己控制时间范围,保证不超过2000条,否则脚本获取不全。
关于对服务器可能造成的压力:脚本以每5页为一组进行抓取,每组之间休息500毫秒;且通过脚本获取的内容全部为文本格式。可以认为对服务器的压力不大。
代码
@Name @Match @Icon
- // ==UserScript==
- // @name 功能:GameMale积分记录一键统计
- // @namespace http://tampermonkey.net/
- // @version 1.0
- // @description 引入并发控制与频率限制,保护服务器,防止触发封禁
- // @author Gemini
- // @match *://www.gamemale.com/home.php?mod=spacecp&ac=credit&op=log*
- // @grant GM_xmlhttpRequest
- // ==/UserScript==
- (function() {
- 'use strict';
- function parseHTML(html) { return new DOMParser().parseFromString(html, 'text/html'); }
- function extractDataFromDoc(doc) {
- let count = 0, sum = 0;
- const rows = doc.querySelectorAll('table.dt tbody tr');
- rows.forEach(row => {
- const amountCell = row.querySelector('td:nth-child(2)');
- if (amountCell) {
- const match = (amountCell.innerText || amountCell.textContent).match(/([-+]?\d+)/);
- if (match) {
- const value = parseInt(match[0], 10);
- if (!isNaN(value)) { sum += value; count++; }
- }
- }
- });
- return { count, sum };
- }
- // 关键辅助函数:延时
- const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
- function init() {
- const form = document.querySelector('form[action*="home.php?mod=spacecp&ac=credit&op=log"]');
- const searchBtn = form ? form.querySelector('button[name="search"]') : null;
- if (!form || !searchBtn) return;
- const calcBtn = document.createElement('button');
- calcBtn.type = 'button';
- calcBtn.className = 'pn';
- calcBtn.style.marginLeft = '10px';
- calcBtn.innerHTML = '<strong>一键统计</strong>';
- const resultSpan = document.createElement('span');
- resultSpan.style.marginLeft = '10px';
- resultSpan.style.fontSize = '14px';
- searchBtn.parentNode.insertBefore(calcBtn, searchBtn.nextSibling);
- searchBtn.parentNode.insertBefore(resultSpan, calcBtn.nextSibling);
- calcBtn.onclick = async function() {
- resultSpan.innerHTML = '<span style="color:#999;">正在初始化...</span>';
- calcBtn.disabled = true;
- try {
- const formData = new FormData(form);
- const firstPageDoc = await new Promise((resolve, reject) => {
- GM_xmlhttpRequest({
- method: "POST",
- url: form.action,
- data: formData,
- onload: (res) => resolve(parseHTML(res.responseText)),
- onerror: (err) => reject(err)
- });
- });
- const firstPageData = extractDataFromDoc(firstPageDoc);
- let totalSum = firstPageData.sum;
- let totalCount = firstPageData.count;
- const pgContainer = firstPageDoc.querySelector('.pg');
- let maxPage = 1, urlTemplate = "";
- if (pgContainer) {
- const labelSpan = pgContainer.querySelector('label span');
- maxPage = labelSpan ? parseInt(labelSpan.title.match(/(\d+)/)[1]) : 1;
- const link = pgContainer.querySelector('a[href*="page="]');
- if (link) urlTemplate = (link.href.indexOf('http') === -1 ? window.location.protocol + '//' + window.location.host + '/' + link.getAttribute('href') : link.href).replace(/&/g, '&');
- }
- // --- 并发控制核心逻辑 ---
- if (maxPage > 1 && urlTemplate) {
- const BATCH_SIZE = 5; // 每组发 5 个请求
- const DELAY = 500; // 每组之间休息 0.5 秒
- for (let i = 2; i <= maxPage; i += BATCH_SIZE) {
- const currentBatchEnd = Math.min(i + BATCH_SIZE - 1, maxPage);
- resultSpan.innerHTML = `<span style="color:#007bff;">正在抓取第 ${i}~${currentBatchEnd} 页 (总 ${maxPage} 页)...</span>`;
- const batchPromises = [];
- for (let j = i; j <= currentBatchEnd; j++) {
- const pageUrl = urlTemplate.replace(/page=\d+/, `page=${j}`);
- batchPromises.push(new Promise(res => {
- GM_xmlhttpRequest({
- method: "GET",
- url: pageUrl,
- onload: (r) => res(extractDataFromDoc(parseHTML(r.responseText))),
- onerror: () => res({ count: 0, sum: 0 })
- });
- }));
- }
- const batchResults = await Promise.all(batchPromises);
- batchResults.forEach(d => { totalSum += d.sum; totalCount += d.count; });
- if (currentBatchEnd < maxPage) await sleep(DELAY); // 还没抓完就休息一下
- }
- }
- const sumColor = totalSum >= 0 ? '#1a9c1a' : '#ff0000';
- resultSpan.innerHTML = `共 <strong>${totalCount}</strong> 条,总变更:<span style="color:${sumColor}; font-weight:bold;">${totalSum > 0 ? '+' : ''}${totalSum}</span>`;
- } catch (err) {
- resultSpan.innerText = "统计异常";
- console.error(err);
- } finally {
- calcBtn.disabled = false;
- }
- };
- }
- setTimeout(init, 500);
- })();
复制代码
来自群组: 星象占卜 |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
x
评分
-
查看全部评分
|