星之子 发表于 2026-1-31 19:15:31

【油猴脚本】积分记录一键统计

动机
像试着统计一下自己究竟通过售卖附件获得了多少金币,就调教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, 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');
      const searchBtn = form ? form.querySelector('button') : 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;
                  const link = pgContainer.querySelector('a');
                  if (link) urlTemplate = (link.href.indexOf('http') === -1 ? window.location.protocol + '//' + window.location.host + '/' + link.getAttribute('href') : link.href).replace(/&amp;/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);
})();



星象占卜

Se7en 发表于 2026-1-31 19:24:12

挺方便的這樣就能更直觀的知道畫了多少金幣買附件。

娱乐法师火布偶 发表于 2026-1-31 19:24:51

本帖最后由 娱乐法师火布偶 于 2026-1-31 19:27 编辑

同理应该也可以统计通过举报获得了多少金币呢
今年一月的举报收获如下:


去年2月到12月的举报收获如下:(不能从1月开始统计,超过100页了)

Burry 发表于 2026-1-31 19:29:15

数据统计的脚本,特别的方便记录自己金币变化。

柏芸 发表于 2026-1-31 19:39:37

个人觉得看着自己的附件卖了多少似乎还是挺有成就感的,虽然说看下载次数也是一个道理:P

momohang 发表于 2026-1-31 19:40:39

谢谢这个! 虽然帖子没有很多但拿来统计一下数据还是很不错的,加上有用上批量兑换,很容易就把之前的数据洗走了

Rolf_0 发表于 2026-1-31 19:46:05

经常发资源的大佬能用得上,看到自己收集的金币一定很满足

crino66666 发表于 2026-1-31 19:54:47

倒也是方便不少,感觉这样更清晰了

毛茸茸兽兽 发表于 2026-1-31 20:00:00

吼~看3楼还可以知道举报获得多少金币欸,还挺有成就感的

狂野哈士奇 发表于 2026-1-31 20:09:12

对于常发帖的用户来说是蛮不错的一个统计查看工具呢

PURO_ 发表于 2026-1-31 20:13:26

马上要补货了,是不是也可以看自己在补货期间花了多少金币呢,那还蛮有趣的{:6_188:}https://img.gamemale.com/album/202508/31/092111u1rzt6h6tzeezd11.jpg

lqiang1990 发表于 2026-1-31 20:17:20

好棒的脚本,确实很想知道,自己的积分详情,

x14443 发表于 2026-1-31 20:26:58

感觉这对于发帖多的大佬才有用呢 ;P像2我这种小卡拉米都是一个个看的;P

lyrt1996 发表于 2026-1-31 20:27:03

看起来是一个很不错的工具诶,不过我个人可能暂时用不上吧(指不关心金币支出

盘上雷 发表于 2026-1-31 20:34:26

看到统计出来的大数字心里还是满满的成就感

喵喵镜你好弱啊 发表于 2026-1-31 20:40:12

啊,这么好的功能可惜手机不能用

zibatco2 发表于 2026-1-31 20:44:23

对于发帖大户感觉挺实用的~挺实用的小插件呢~感谢星大佬分享啦;P

2297988 发表于 2026-1-31 21:08:56

不咋举报也不卖附件的俺就只好默默仰望楼上的大佬们了=3=

一只随行 发表于 2026-1-31 21:12:30

感觉偶尔统计一下看看大数字也会心情很好哇{:6_184:}

1458209048 发表于 2026-1-31 21:25:49

明显就感觉方便许多了,感谢大佬的制作和分享
页: [1] 2 3
查看完整版本: 【油猴脚本】积分记录一键统计