// ==UserScript==
// @name 筛选ABDC
// @namespace http://tampermonkey.net/
// @version 2025-05-30-001
// @description 小工具
// @author 周利斌
// @match https://so1.imageoss.com/*
// @match https://so3.cljtscd.com/scholar*
// @match *://*/*
// @include *webofscience*
// @include *www-scopus-com*
// @icon https://www.google.com/s2/favicons?sz=64&domain=scholar.google.com
// @grant GM_setValue
// @grant GM_getValue
// @license MIT
// ==/UserScript==
//https://greasyfork.org/zh-CN/scripts/533214-%E7%AD%9B%E9%80%89abdc
(function () {
"use strict";
document.querySelectorAll(".gs_a").forEach(f=>f.setAttribute("translate",'no'))
const btnStyle = "padding:5px;min-width: auto;"
function appendTo(parentEle, tagName = "a", attrs = {}, functions = {}, id = "") {
attrs = typeof attrs !== "string" ? attrs : { textContent: attrs };
functions = typeof functions !== "function" ? functions : { click: functions };
if (id && document.getElementById(id)) return document.getElementById(id)
const ele = document.createElement(tagName);
if (id) ele.id = id;
for (const key in attrs) { ele[key] = attrs[key]; ele.setAttribute(key, attrs[key]); }
for (const key in functions) ele.addEventListener(key, functions[key]);
if (parentEle) parentEle.appendChild(ele);
return ele;
}
function waitUtilAsync(callback, interval = 1000, timeout = 10000) {
return new Promise((resolve, reject) => {
const start = Date.now();
const intervalId = setInterval(() => {
const d = callback();
if (d) {
clearInterval(intervalId);
resolve(d);
} else if (Date.now() - start > timeout) {
clearInterval(intervalId);
resolve(false);
}
}, interval);
});
}
function getRootDiv() {
const existingDiv = document.getElementById('z_root_div');
if (existingDiv) {
return existingDiv;
}
const rootDiv = document.createElement("div")
rootDiv.id = "z_root_div"
rootDiv.style = `
position: fixed;
z-index:999999;
background-color: rgba(42, 38, 43, 0.39);
cursor: move;
border:1px solid rgba(238, 11, 204, 0.55);
`;
document.body.appendChild(rootDiv);
if (typeof GM_getValue != undefined) {
// 恢复 rootDiv 的位置
const savedLeft = GM_getValue('rootDivLeft', 0);
const savedTop = GM_getValue('rootDivTop', 0);
document.body.clientHeight
rootDiv.style.left = (document.body.clientWidth < savedLeft ? 0 : savedLeft) + 'px';
rootDiv.style.top = (document.body.clientHeight < savedTop ? 0 : savedTop) + 'px';
}
let isDragging = false;
let offsetX, offsetY;
rootDiv.addEventListener('mousedown', (e) => {
isDragging = true;
offsetX = e.clientX - rootDiv.offsetLeft;
offsetY = e.clientY - rootDiv.offsetTop;
});
document.addEventListener('mousemove', (e) => {
if (isDragging) {
rootDiv.style.left = (e.clientX - offsetX) + 'px';
rootDiv.style.top = (e.clientY - offsetY) + 'px';
}
});
document.addEventListener('mouseup', () => {
if (isDragging) {
isDragging = false;
if (typeof GM_setValue != undefined) {
// 保存 rootDiv 的位置
GM_setValue('rootDivLeft', parseInt(rootDiv.style.left));
GM_setValue('rootDivTop', parseInt(rootDiv.style.top));
}
}
});
setTimeout(() => {
if (rootDiv.childElementCount == 0) rootDiv.remove()
}, 2000)
return rootDiv;
}
// Your code here...
async function filterRank(selector = ".gs_r.gs_or.gs_scl", checkSelector = "input[type=checkbox]") {
if (!(await waitUtilAsync(() => document.querySelector(selector)))) { console.log("未找到", selector); return; }
console.log("找到", selector);
const lastClickBtnTxt = GM_getValue("lastClickBtnTxt")
let lcb = undefined
if (!window.rankInfoObserver) {
window.rankInfoObserver =
new MutationObserver(mutations => {
mutations.forEach(mutation => {
mutation.addedNodes.forEach(node => {
if (node.nodeType === 1 && node.classList.contains('srankdiv')) {
console.log(`.srankdiv 的数量: ${document.querySelectorAll('.srankdiv').length}`);
if (lcb) {
setTimeout(() => lcb.click(), 500);
}
else {//显示全部
const qList = document.querySelectorAll(selector)
stat_info(qList)
}
}
});
});
});
window.rankInfoObserver.observe(document.body, { childList: true, subtree: true });
}
const divStat = appendTo(getRootDiv(), "div", "")
let btns = []
createRankBtn("显示全部", (m) => 1)
createRankBtn("ABDC A*/A", ms => ms.some(m => m.includes("ABDC A")));
createRankBtn("ABDC B", ms => ms.some(m => m.includes("ABDC B")));
createRankBtn("SSCI IF>2", ms => ms.some(m => m.includes("SSCI")) && ms.some(m => m.startsWith("IF") && asIF(m) > 2));
createRankBtn("IF>8", ms => ms.some(m => m.startsWith("IF") && asIF(m) > 8));
createRankBtn("CiteScore>12", ms => ms.some(m => m.includes("CiteScore") && asIF(m) > 12));
/**
*
* @param {string} content
* @returns number
*/
function asIF(content) {
const IF = parseFloat(content.match(/([\d\.]+)$/g)?.[0]) || 0
// console.log(content.match(/[\d\.]+/g), IF, content);
return IF
}
/**
*
* @param {number} id
* @param {string} btnTxt
* @param {(rankInfos:string[])=>boolean} checkFunc
*/
function createRankBtn(btnTxt = "", checkFunc = (a) => false) {
const btn = appendTo(getRootDiv(), "button", { style: btnStyle, textContent: btnTxt }, () => {
if (lcb != btn) {
lcb = btnTxt.includes("全部") ? undefined : btn
GM_setValue("lastClickBtnTxt", btnTxt)
}
btns.forEach(f => {f.style.backgroundColor = f == btn ? "#e686e6" : ""})
const qList = document.querySelectorAll(selector)
let check = 0, checked = 0;
for (const row of qList) {
if (!row.querySelector(".srankInfo")) continue;
const rks = [...row.querySelectorAll(".srankInfo")].map(a => a.textContent)
const ck = checkSelector && row.querySelector(checkSelector)
if (ck) {//wos 不隐藏未选中的
if (checkFunc(rks)) {
row.children[0].style.backgroundColor = getComputedStyle(row.querySelector(".srankInfo")).backgroundColor;
if (ck.checked) {
checked++;
} else {
ck.click();
check++;
}
}
}
else {//scholar 未选中隐藏
row.style.transition = "border-left .5s, max-height .5s, overflow-y .5s, padding .5s";
if (checkFunc(rks)) {
if (row.tagName == "TR") {
row.style.display = ""
} else {
row.style.borderLeft = ""
row.style.maxHeight = "";
row.style.overflowY = ""
row.style.padding = ""
}
check++
}
else {
if (row.tagName == "TR") {
row.style.display = "none"
} else {
row.style.borderLeft = "5px solid #300"
row.style.maxHeight = "1px"
row.style.overflowY = "hidden"
row.style.padding = "0px"
}
}
}
}
//统计信息
stat_info(qList, check, checked);
});
btns.push(btn)
if (btnTxt == lastClickBtnTxt) {
//重新加载的时候需要点击一次。
btn.click()
}
return btn
}
if (document.querySelector("#gs_bdy")) {
//设置谷歌查询结果的最小高度,让滚动条一直存在
document.querySelector("#gs_bdy").style.minHeight = "600px";
}
function stat_info(qList, check = 0, checked = 0) {
const checkCount = document.querySelector("#snRecListTop .mat-checkbox")?.textContent || "";
const page = document.querySelector("#snNextPageTop")?.value || "";
const pageAll = document.querySelector("body > app-wos > main > div > div > div.holder > div > div > div.held > app-input-route > app-base-summary-component > div > div.results.ng-star-inserted > app-page-controls.app-page-controls.ng-star-inserted > div > form > div")?.textContent || "";
const rankLength = // document.querySelectorAll(".srankdiv").length;
[...qList].map(a => a.querySelector(".srankInfo:not(.rcited,.ryear)")).filter(f => f).length;
const birdLength = document.querySelectorAll(".scicrx-btn .scicrx-svgicon").length;
const citeLength = document.querySelectorAll(".rcited").length;
divStat.textContent = `【选中${check}/已选${checked}/当前页${qList.length}/总选中${checkCount} / 页码:${page} ${pageAll} / 引用${citeLength}等级${rankLength}小鸟${birdLength}】`;
}
}
filterRank(".gs_r.gs_or.gs_scl", "")//scholar
filterRank(".summary-record")//wos
if (location.href.indexOf("scispace") > -1) {
filterRank("main table tr", "")//scispace
//查询100条
waitUtilAsync(() => document.querySelector(".border-primary [data-icon=files]"))
.then(() => {
function sciSpaceAutoQuery() {
const queryBtn = document.querySelector(".border-primary [data-icon=files]")?.parentElement
if (queryBtn) {
queryBtn.scrollIntoView({ behavior: "smooth", block: "center" });
setTimeout(sciSpaceAutoQuery, 2000)
if (!queryBtn.getAttribute("disabled")) {
queryBtn.click()
}
} else {
queryToolBtn.remove() //按钮消失
}
}
const queryToolBtn = appendTo(getRootDiv(),
"button", { style: btnStyle, textContent: "ss查询100条" },
() => {
sciSpaceAutoQuery()
}
)
})
}
})();