agentsclimarketplace

Icve Exam Extract

Skill BitsAstro/Icve-Exam-Extract

用 Kimi WebBridge 从 icve/zjy2 的 viewExam 考试回看页(如 https://zjy2.icve.com.cn/study/viewExam?...)提取所有"红色背景=做错"的题目,并整理成可直接粘贴进 Word 的结构化格式。 触发场景:用户给出 icve 的 viewExam 类 URL,要求"提取错题/做错的题/红题",或要整理考试错题本。From its SKILL.md

Install
npx -y skills add BitsAstro/Icve-Exam-Extract

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 2 stars2 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

5.3 KB, ~1.6k tokens by cl100k_base, as published. Nobody here has run it

icve viewExam 错题提取(Kimi WebBridge)

通过 Kimi WebBridge 操控用户已登录的浏览器(含隐私窗口),读取答题卡红色(错)题号并抓取每题完整内容。

前置条件

  • Kimi WebBridge daemon 运行在 http://127.0.0.1:10086(二进制 C:\Users\a\.kimi-webbridge\bin\kimi-webbridge.exe)。
  • 浏览器扩展已连接(curl http://127.0.0.1:10086/statusextension_connected)。
  • 用户已在浏览器(隐私窗口需扩展开启"隐私模式时启用")打开目标 viewExam 页面并登录。

调用约定(Windows)

  • 每个请求体写成 JSON 文件(避免 PowerShell 行内传参把中文变 ?),用 curl.exe -s -X POST http://127.0.0.1:10086/command -H "Content-Type: application/json" --data-binary "@<文件>" 发送。
  • 请求体必须带顶层 "session" 字段(同一任务固定一个名字,如 exam-extract)。

步骤

1. 借用用户当前标签(必须传真实 URL)

find_tab 即使 active:true 也要求 url 匹配已打开的标签——直接传用户给的 URL + active:true

{"action":"find_tab","args":{"url":"<用户给的viewExam完整URL>","active":true},"session":"exam-extract"}

2. 合并脚本:扫红色错题号 + 抓题目数据

evaluate 执行下面 JS(一次性返回结构化 JSON):

  • 红色(错) vs 蓝色(对) 背景色挂在答题卡 .tagItemcomputed style 上:错=rgb(159,19,18)、对=rgb(21,51,152)。(注意:链接本身 background 是 transparent,要查 .tagItem 元素!)
  • 每题是 .subjectDet,字段:题号/题型/分值 .xvhao;题干 .seeTitle .htmlP.ql-editor;用户得分 .titleBox .el-tag;选项 .optionList.el-radio__label(单选)/.el-checkbox__label(多选);正确答案 .answer;解析 .analysis .htmlP.ql-editor
(() => {
  const tags = Array.from(document.querySelectorAll('.tagItem'));
  const wrong = [];
  for (const tag of tags) {
    const txt = (tag.textContent || '').trim();
    const n = Number(txt);
    if (!Number.isInteger(n) || n < 1 || n > 500) continue;
    const cs = getComputedStyle(tag);
    const bg = cs.backgroundColor;
    const m = bg.match(/\d+/g);
    const p = m ? [+m[0], +m[1], +m[2]] : null;
    if (p && p[0] > 120 && p[1] < 100 && p[2] < 100) wrong.push(n);
  }
  const wset = new Set(wrong);
  const subs = Array.from(document.querySelectorAll('.subjectDet'));
  const out = [];
  for (const sub of subs) {
    const xvhao = sub.querySelector('.xvhao');
    if (!xvhao) continue;
    const mm = (xvhao.textContent || '').match(/(\d+)/);
    if (!mm) continue;
    const num = parseInt(mm[1], 10);
    if (!wset.has(num)) continue;
    const header = (xvhao.textContent || '').trim();
    const stemEl = sub.querySelector('.seeTitle .htmlP.ql-editor');
    const stem = stemEl ? stemEl.textContent.trim() : '';
    const tagEl = sub.querySelector('.titleBox .el-tag');
    const userScore = tagEl ? tagEl.textContent.trim() : '';
    const optLabels = sub.querySelectorAll('.optionList .el-radio__label, .optionList .el-checkbox__label');
    const options = Array.from(optLabels).map(o => o.textContent.trim());
    const ansEl = sub.querySelector('.answer');
    const correctAnswer = ansEl ? ansEl.textContent.trim() : '';
    let analysis = '';
    const anaEl = sub.querySelector('.analysis .htmlP.ql-editor');
    if (anaEl) analysis = anaEl.textContent.trim();
    if (!analysis) { const a2 = sub.querySelector('.analysis'); if (a2) analysis = a2.textContent.replace('解析:','').replace('解析:','').trim(); }
    out.push({num, header, stem, userScore, options, correctAnswer, analysis});
  }
  out.sort((a,b)=>a.num-b.num);
  return JSON.stringify({wrongCount: wrong.length, count: out.length, questions: out});
})()

写 JSON 文件时注意:JS 里的 /\d+/g/(\d+)/ 在 JSON 字符串中反斜杠要写成 \\d

3. 格式化输出(Python)

curl 返回包在 {"ok":true,"data":{"type":"string","value":"<内层JSON>"}},先取 data.valuejson.loads

  • 题头解析坑:Python 原始字符串 r'...' 里的 \u3010 不会被解释成【。改用 header.find('【') 按括号切分最稳:
    def parse_header(header):
        i1=header.find('【'); i2=header.find('】'); i3=header.find('('); i4=header.find(')')
        if i1>=0 and i2>i1 and i3>i2 and i4>i3:
            return header[:i1].strip().rstrip('.'), header[i1+1:i2].strip(), header[i3+1:i4].strip()
        return None,None,None
    
  • 输出模板(每题间空一行):
    [题号].【[题型]】([分值])
    [题干]
    [用户得分] 分
    [选项A内容]
    [选项B内容]
    ...
    正确答案: [答案]
    解析:[解析]
    
  • 写出 <阶段>测试_错题整理.txt(UTF-8)。

收尾

  • 删掉中间临时 JSON(请求体、data 文件),保留格式脚本和最终 txt。
  • 若多阶段,各自成文件;可后续合并或导出 Word/PDF。

What ships with it: 3 files

11.2 KB alongside SKILL.md

Gives 0 of the 12 instructions most education skills give in ~1.6k tokens

Counted across 169 of the 171 authors here whose files we hold, read 2026-08-07

  • Search for existing resources before creating new onesin 7 of 169, across 3 files
  • Check tool responses for errors before proceedingin 7 of 169, across 3 files
  • Reduce request frequency on rate limit errorsin 7 of 169, across 3 files
  • Confirm connection status is ACTIVE before running workflowsin 7 of 169, across 3 files
  • Execute prerequisite steps first in workflowsin 7 of 169, across 3 files
  • Handle pagination by fetching until exhaustedin 7 of 169, across 3 files
  • Re-authenticate if the connection expiredin 6 of 169, across 2 files
  • Always call RUBE_SEARCH_TOOLS first to get schemasin 6 of 169, across 2 files
  • Pass strictly schema-compliant tool argumentsin 6 of 169, across 2 files
  • Run the skill generator if the shared file is missingin 6 of 169, across 3 files
  • Create the coursein 5 of 169, across 3 files
  • List enrolled studentsin 5 of 169, across 3 files

Said here and by no other author read

  • check extension connection status via curl
  • use the provided url to find the active browser tab
  • keep the same session name for all requests
  • write each request body to a json file
  • send requests using curl.exe with the data binary flag
  • inject javascript to extract all red questions

Grouped from the skills themselves: near-identical wordings counted once, and counted by distinct author, so one author publishing three of these counts once. Length counted with cl100k_base; the agent that loads this file may tokenize it differently.

Keep looking

Skills are one crate of 325,949. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.