对于competitive-companion的修改
Xiaohaoyu1020 · · 科技·工程
Luogu 最近更新了题目的页面,导致之前 competitive-companion 当场去世。
找到原因,发现是之前的匹配规则完全失效了,为此我对其编译后的源码进行修改,在此处开源并开放使用。
由于没有合适的放下源代码的手段,因此请跟随本篇文章进行修改。
解压
下载的插件是一个 zip 文件,解压之后会是如下结构:
competitive_companion-2.58.0-chrome \
- js/
- content.js
- option.js
- background.js
- icon/
- 几个图标文件
- ...几个配置文件
问题集中出现在 content.js 里面,但是考虑到编译后的极压缩码分,实在是改不了一点。
应对策略:打开浏览器调试界面,使用原来的插件,爬取题目信息,此时会发生报错,顺着控制台报错可以找到浏览器自动格式化好的代码。
图解:
点开后就会又一份浏览器格式化的代码。
将这份代码复制,黏贴进入 content.js 当中,就得到了一份还算有可读性的代码。
修改
使用 VSCode 打开 content.js。
然后 Edit -> Find 或者 ctrl+F 。
输入 LuoguProblemParser 检索到如下位置(这是修改后的代码,可能有些地方不同,比如 'div > .....' 之类的但是大体结构相似)。
var LuoguProblemParser = class extends Parser {
getMatchPatterns() {
return ["https://www.luogu.com.cn/problem/*"]
}
async parse(url, html) {
let elem = htmlToElement(html)
, task = new TaskBuilder("Luogu").setUrl(url);
return elem.querySelector(".main-container") !== null ? this.parseFromPage(task, elem) : this.parseFromScript(task, elem),
task.build()
}
parseFromPage(task, elem) {
task.setName(elem.querySelector("header > div > div > h1").textContent.trim());
let timeLimitStr = elem.querySelector("header > div > div > div > div:nth-child(2) > div > div:nth-child(3) > span:nth-child(2)").textContent;
task.setTimeLimit(parseFloat(timeLimitStr) * 1e3);
let memoryLimitStr = elem.querySelector("header > div > div > div > div:nth-child(2) > div > div:nth-child(4) > span:nth-child(2)").textContent;
task.setMemoryLimit(parseInt(memoryLimitStr)),
elem.querySelectorAll(".io-sample").forEach(sample => {
let input = sample.querySelector("div:nth-child(1) > pre").textContent
, output = sample.querySelector("div:nth-child(2) > pre").textContent;
task.addTest(input, output)
}
)
}
parseFromScript(task, elem) {
for (let scriptElem of elem.querySelectorAll("script")) {
let script = scriptElem.textContent;
if (script.startsWith("window._feInjection")) {
let startQuoteIndex = script.indexOf('"')
, endQuoteIndex = script.substr(startQuoteIndex + 1).indexOf('"')
, encodedData = script.substr(startQuoteIndex + 1, endQuoteIndex)
, data = JSON.parse(decodeURIComponent(encodedData)).currentData.problem;
task.setName(`${data.pid} ${data.title}`.trim()),
task.setTimeLimit(Math.max(...data.limits.time)),
task.setMemoryLimit(Math.max(...data.limits.memory) / 1024);
for (let sample of data.samples)
task.addTest(sample[0], sample[1]);
return
}
}
throw new Error("Failed to find problem data")
}
}
当然如果不是这个位置,比如这个:
var parsers = [new A2OnlineJudgeProblemParser, new A2OnlineJudgeContestParser, new ACMPProblemParser, new AcWingProblemParser, new AizuOnlineJudgeProblemParser, new AizuOnlineJudgeBetaProblemParser, new AlgotesterProblemParser, new AlgoZenithNewProblemParser, new AlgoZenithOldProblemParser, new AnarchyGolfProblemParser, new AtCoderProblemParser, new AtCoderContestParser, new BaekjoonOnlineJudgeProblemParser, new BAPSOJProblemParser, new BAPSOJContestParser, new BeecrowdProblemParser, new BeecrowdContestParser, new BloombergCodeConProblemParser, new BUCTOJProblemParser, new BUCTOJContestParser, new CodeChefNewProblemParser, new CodeChefOldProblemParser, new CodeChefContestParser, new CodeDrillsProblemParser, new CodeforcesProblemParser, new CodeforcesContestParser, new CodeMarshalProblemParser, new CodeMarshalContestParser, new COJProblemParser, new COJContestParser, new ContestHunterProblemParser, new ContestHunterContestParser, new CPythonUZProblemParser, new CPythonUZContestParser, new CSAcademyProblemParser, new CSESProblemParser, new CSESContestParser, new CSUACMOnlineJudgeProblemParser, new CSUACMOnlineJudgeContestParser, new DimikOJProblemParser, new DMOJProblemParser, new DMOJContestParser, new DOMjudgeContestParser, new ECNUOnlineJudgeProblemParser, new ECNUOnlineJudgeContestParser, new EolympNormalProblemParser, new EolympBasecampProblemParser, new EolympNormalContestParser, new EolympBasecampContestParser, new FZUOnlineJudgeProblemParser, new FZUOnlineJudgeContestParser, new GoogleCodingCompetitionsProblemParser, new HackerEarthProblemParser, new HackerEarthCodeArenaParser, new HackerEarthContestParser, new HackerRankProblemParser, new HackerRankContestParser, new HDOJNewProblemParser, new HDOJProblemParser, new HDOJNewContestParser, new HDOJContestParser, new HITOnlineJudgeProblemParser, new HihoCoderProblemParser, new HihoCoderContestParser, new HKOIOnlineJudgeProblemParser, new HKOIOnlineJudgeContestParser, new HrbustOnlineJudgeProblemParser, new HydroProblemParser, new HydroContestParser, new InfoArenaProblemParser, new ITCoderHUTECHProblemParser, new JutgeProblemParser, new KattisProblemParser, new KattisContestParser, new KilonovaProblemParser, new KilonovaContestParser, new LanqiaoProblemParser, new LanqiaoContestParser, new LibraryCheckerProblemParser, new LibraryCheckerOldProblemParser, new LibreOJProblemParser, new LibreOJContestParser, new LightOJProblemParser, new LightOJContestParser, new LSYOIProblemParser, new LuoguProblemParser, new LuoguContestParser, new MendoProblemParser, new MetaCodingCompetitionsProblemParser, new MrJudgeProblemParser, new MSKInformaticsProblemParser, new NBUTOnlineJudgeProblemParser, new NBUTOnlineJudgeContestParser, new NepsAcademyProblemParser, new NewtonSchoolProblemParser, new NOJProblemParser, new NOJContestParser, new NowCoderProblemParser, new OmegaUpProblemParser, new OpenJudgeProblemParser, new OpenJudgeContestParser, new OTOGProblemParser, new PandaOnlineJudgeProblemParser, new PBInfoProblemParser, new PEGJudgeProblemParser, new PEGJudgeContestParser, new POJProblemParser, new POJContestParser, new PTAProblemParser, new QBXTOJProblemParser, new QDUOJProblemParser, new QDUOJContestParser, new QQWhaleProblemParser, new RoboContestProblemParser, new RoboContestContestParser, new SDUTOnlineJudgeProblemParser, new SeriousOJProblemParser, new SeriousOJContestParser, new SortMeProblemParser, new SPOJProblemParser, new SSOIERProblemParser, new StarryCodingProblemParser, new TheJobOverflowProblemParser, new TimusOnlineJudgeProblemParser, new TimusOnlineJudgeContestParser, new TLXProblemParser, new TLXContestParser, new TophProblemParser, new UDebugProblemParser, new UniversalCupProblemParser, new UniversalCupContestParser, new UOJProblemParser, new UOJContestParser, new USACOProblemParser, new USACOTrainingProblemParser, new UVaOnlineJudgeProblemParser, new VirtualJudgeProblemParser, new VirtualJudgeContestParser, new XXMProblemParser, new YandexProblemParser, new YandexContestParser, new YukicoderProblemParser, new YukicoderContestParser, new ZOJProblemParser, new ZUFEOJProblemParser, new ZUFEOJContestParser];
可以按下 ctrl 然后跳转到正确的位置。
var LuoguProblemParser = class extends Parser {
getMatchPatterns() {
return ["https://www.luogu.com.cn/problem/*"]
}
async parse(url, html) {
let elem = htmlToElement(html)
, task = new TaskBuilder("Luogu").setUrl(url);
return elem.querySelector(".main-container") !== null ? this.parseFromPage(task, elem) : this.parseFromScript(task, elem),
task.build()
}
parseFromPage(task, elem) {
task.setName(elem.querySelector("header > div > div > h1").textContent.trim());
let timeLimitStr = elem.querySelector("header > div > div > div > div:nth-child(2) > div > div:nth-child(3) > span:nth-child(2)").textContent;
task.setTimeLimit(parseFloat(timeLimitStr) * 1e3);
let memoryLimitStr = elem.querySelector("header > div > div > div > div:nth-child(2) > div > div:nth-child(4) > span:nth-child(2)").textContent;
task.setMemoryLimit(parseInt(memoryLimitStr)),
elem.querySelectorAll(".io-sample").forEach(sample => {
let input = sample.querySelector("div:nth-child(1) > pre").textContent
, output = sample.querySelector("div:nth-child(2) > pre").textContent;
task.addTest(input, output)
}
)
}
parseFromScript(task, elem) {
for (let scriptElem of elem.querySelectorAll("script")) {
let script = scriptElem.textContent;
if (script.startsWith("window._feInjection")) {
let startQuoteIndex = script.indexOf('"')
, endQuoteIndex = script.substr(startQuoteIndex + 1).indexOf('"')
, encodedData = script.substr(startQuoteIndex + 1, endQuoteIndex)
, data = JSON.parse(decodeURIComponent(encodedData)).currentData.problem;
task.setName(`${data.pid} ${data.title}`.trim()),
task.setTimeLimit(Math.max(...data.limits.time)),
task.setMemoryLimit(Math.max(...data.limits.memory) / 1024);
for (let sample of data.samples)
task.addTest(sample[0], sample[1]);
return
}
}
throw new Error("Failed to find problem data")
}
}
然后将如上代码,放在刚才检索到的位置上( js 和 c++有一部分语法的相似性,大概注意下大括号的位置)。
然后用浏览器加载文件夹即可。
这样又可以继续快乐的刷题了。