- // ==UserScript==
- // @name mcbbs:将参与投票者的信息导出到csv
- // @namespace http://tampermonkey.net/
- // @version 0.1
- // @description https://www.mcbbs.net/thread-1464590-1-1.html
- // @author 破损的鞘翅
- // @match https://www.mcbbs.net/thread-*
- // @match https://www.mcbbs.net/forum.php?mod=viewthread*
- // @icon https://www.mcbbs.net/favicon.ico
- // @grant none
- // ==/UserScript==
- (function () {
- "use strict";
- // Your code here...
- class CSV {
- headers = [];
- datas = [];
- width = 0;
- constructor(...headers) {
- this.headers = headers.join(",");
- this.width = headers.length;
- }
- add(...data) {
- while (data.length < this.width) {
- data.push("");
- }
- this.datas.push(data.join(","));
- }
- saveAs(filename) {
- const a = document.createElement("a");
- a.href = URL.createObjectURL(new Blob([this.export], { type: "text/plain" }));
- a.download = filename + ".csv";
- document.body.append(a);
- a.click();
- a.remove();
- }
- get export() {
- const exports = [this.headers, ...this.datas];
- return exports.join("\r\n");
- }
- }
- async function fetchXml(url, init = {}) {
- const domParser = new DOMParser();
- const response = await fetch(url, init);
- const resText = await response.text();
- const resXml = domParser.parseFromString(resText, "text/xml");
- return domParser.parseFromString(resXml.documentElement.childNodes[0].data, "text/html");
- }
- async function getUserInfo(uid) {
- const res = await fetch(`https://www.mcbbs.net/home.php?mod=space&uid=${uid}`).then((res) => res.text());
- const html = new DOMParser().parseFromString(res, "text/html");
- try {
- return {
- uid,
- exp: html.querySelector("#psts>ul>li:nth-child(2)").childNodes[1].nodeValue.match(/[0-9]{1,}/)[0],
- nuggets: html.querySelector("#psts>ul>li:nth-child(4)").childNodes[1].nodeValue.match(/[0-9]{1,}/)[0],
- emeralds: html.querySelector("#psts>ul>li:nth-child(6)").childNodes[1].nodeValue.match(/[0-9]{1,}/)[0],
- nickname: html.querySelector("#uhd .mt").innerText.replace(/\n/g, ""),
- group: html.querySelector("#pbbs").previousElementSibling.querySelector("li:last-child a").innerText,
- };
- } catch {
- console.error(`获取用户 ${uid} 的信息失败。`);
- }
- }
- async function getDingTie(uid) {
- const result = await fetch(`https://auto.xmdhs.com/getforuid?uid=${uid}`).then((res) => res.json());
- return result.data?.length || 0;
- }
- async function getVoteResult(tid, page = 1, optionId = 0) {
- const result = []; //单个选项的投票结果
- const classifiedResult = {}; //投票结果的集合
- const url = new URL(`https://www.mcbbs.net/forum.php?mod=misc&action=viewvote&tid=${tid}&handlekey=viewvote&inajax=1`);
- url.searchParams.set("page", page);
- if (optionId > 0) {
- //optionId 大于0,为url添加参数,获取对应选项的投票结果。不加该参数则是获取第一个选项的结果。
- url.searchParams.set("polloptionid", optionId);
- }
- const html = await fetchXml(url.href);
- for (const li of html.querySelector("ul").children) {
- //将结果放入数组
- const uid = new URL(li.querySelector("a").href).searchParams.get("uid");
- result.push(uid);
- }
- if (html.querySelector(".nxt")) {
- //含有该元素,说明还有下一页,获取下一页的结果,放入数组
- const nextRes = await getVoteResult(tid, page + 1, optionId);
- result.push(...nextRes);
- }
- if (optionId > 0 || page > 1) {
- //optionId 大于 0 且 page 大于 1,说明该调用只获取单个选项的投票结果,返回之前获取的结果
- return result;
- } else {
- //反之,说明该调用是获取全部的投票结果。除了已经获取了的默认的结果,再获取其他选项的结果
- const options = html.querySelector("select").children;
- for (const option of options) {
- if (option.selected) {
- classifiedResult[option.innerText] = result;
- continue;
- }
- classifiedResult[option.innerText] = await getVoteResult(tid, 1, option.value);
- }
- return classifiedResult;
- }
- }
- function getButton() {
- const btn = document.createElement("a");
- btn.href = "javascript:void();";
- btn.addEventListener("click", async () => {
- showPrompt(null, null, "<span>开始获取数据,在此期间请勿再次点击本按钮</span>", 5000);
- try {
- const csv = new CSV("Type", "TotalCredits", "Nuggets", "Emeralds", "DingTies", "Nickname", "UserGroupName", "UID");
- const result = await getVoteResult(window.tid);
- for (const option in result) {
- for (const uid of result[option]) {
- console.log("正在获取用户:", uid);
- const { exp, nuggets, emeralds, nickname, group } = await getUserInfo(uid);
- const dingTie = await getDingTie(uid);
- csv.add(option, exp, nuggets, emeralds, dingTie, nickname, group, uid);
- }
- }
- csv.saveAs(document.querySelector("#thread_subject").innerText);
- showPrompt(null, null, "<span>数据获取完毕,确认数据完整前请勿关闭网页,若数据有缺损,请打开控制台查看错误信息</span>", 5000);
- } catch (err) {
- showPrompt(null, null, "<span>数据获取出错,请打开控制台查看错误信息</span>", 5000);
- throw err;
- }
- });
- btn.innerText = "将数据导出至CSV";
- return btn;
- }
- if (document.querySelector("#poll>.pinf") && document.querySelector("#poll>.pinf").innerText.search("查看投票参与人") > 1) {
- document.querySelector("#poll>.pinf").append(getButton());
- }
- })();
复制代码
|