Skip to content

Repository files navigation

tax-export · 税务数据导出(Chrome 扩展)

一个 Chrome 浏览器扩展(MV3),在个人所得税电子税务局 https://etax.chinatax.gov.cn/ 自动采集「申报查询」与「专项附加扣除信息查询」数据,导出完整 JSON 与合并 PDF 报表。跨页面刷新自动续采——这是它相对 bookmarklet 方案的核心优势。

⚠️ 本项目仅供学习研究。使用前请务必阅读文末《免责声明》。

为什么是扩展(不是 bookmarklet)

电子税务局点「查看」进入详情页时页面会刷新,导致 bookmarklet 的 JS 上下文销毁、脚本中断。Chrome 扩展通过两层架构彻底解决:

层 职责 生命周期
background(service worker) 用 chrome.storage.local 存采集进度 持久(页面刷新不影响)
content script 注入页面操作 DOM,每步把进度汇报给 background 页面刷新后自动重新注入

页面刷新后,content script 重新注入 → 从 background 读回进度 → 根据当前页面判断该从哪步继续。用户无需干预,采集自动接着跑。

功能

  • 🛡️ 域名限定:仅在 etax.chinatax.gov.cn 注入,其它站点无副作用。
  • 📊 申报数据全套采集:
    • 我要查询 → 申报查询
    • 默认视图先抓:进页面不设日期条件,自带约 2 年数据,先抓这批(更快,也避开日期组件)
    • 条件查询补采:默认视图采完后,把 税款所属期(month picker) 与 申报日期(date picker) 均设到「4 年前 1 月」(2026 → 2022-01)再查,与默认视图重复的年份跳过
    • 查询 → 已完成 → 提取申报列表(去重)
    • 逐条「查看」抓详情:基础信息 + 计税详情 + 工资薪金收入明细(翻页);点「查看」按申报项目+税款所属期文字匹配目标行(列表顺序乱也不点错),匹配失败回退行号
    • 退税记录 tab:两项合计——汇算已退税额1(退税金额合计,排除「税务审核不通过」)与 已预缴税额(仅统计「国库处理完成」「税务审核中」,「已撤销退税申请」等一律不计;页面有「已预缴税额」列时优先取该列)(无该 tab 自动跳过)
    • 总收入 = 工资薪金收入 + 资薪奖金收入(计税详情表两行之和,JSON/PDF 申报概况均导出)
    • 计税汇总「收入」口径:=「总收入明细」页头的 收入总额 + 单独计税奖金(如 298254.85+1330.94);页头未读到时保持计税详情汇总原值。计税详情表「工资薪金」行 = 页头「收入总额」 − 工资明细中「全年一次性奖金」行合计(收入总额含并入奖金,须剔除),单独计税奖金(页头金额)单独入库,JSON/PDF 均导出
    • 资薪奖金收入与类型(计税详情表「工资薪金」行下方自动插入,JSON/PDF 均导出 资薪奖金类型):无奖金 → 0、类型「无奖金」;奖金并入综合所得(单独计税=0,工资明细含「全年一次性奖金」行)→ 该类行收入合计、类型「奖金并入综合所得」,这些行即「单独计税奖金明细」;单独计税(页头 .qnycxjj-money 金额>0)→ 该金额、类型「奖金单独计税」,「单独计税奖金明细」合成一行(合计),且工资薪金明细剔除全年一次性奖金行(不重复计入工资)。奖金明细不再从页面点击抓取(曾误抓工资行)
    • 从详情页返回后自动重置查询条件,继续下一条
    • 已作废 tab 补采:已完成逐条采完后自动切「已作废」tab,与已完成重复年份的行跳过,其余照常进详情(报表标注「已作废」)
    • 今年(当前年)数据不采集:申报列表按年份过滤掉当前年,专项附加扣除年度止于上一年
    • 收入纳税明细查询(申报查询全部阶段采完后衔接):我要查询 → 收入纳税明细查询。申报查询缺失的年份(如列表只有 2025/2024/2022,缺 2023)→ 翻页逐行「查看」读月度详情(本期收入/减除费用/专项扣除等),按月汇算生成该年年度数据(标注数据来源);已有申报数据的年份:当年无奖金自动跳过,有奖金则读「已申报税额合计」→ 已预缴税额 并翻页扫描明细合并 所得项目小类=「全年一次性奖金」行的「已申报税额(元)」→ 资薪奖金税额;任一步失败跳过不阻塞
  • 🧾 专项附加扣除信息采集(申报完成后自动衔接):
    • 我要查询 → 专项附加扣除信息查询
    • 逐年导出(4 年前到上一年,如 2022→2025;今年不采):用 year picker 选扣除年度,选年即自动刷新
    • 提取每条扣除卡片(项目 / 子女姓名·被赡养人·住房地址等键值 / 最后修改时间)
    • 逐条「查看」抓明细:基本信息 / 教育信息 / 被赡养人信息 / 分摊方式 / 申报方式 / 设置扣除比例 等分段
    • 多主体不丢(子女教育/3岁以下婴幼儿照护/赡养老人等):同页多个同名段(如两个孩子的「教育信息」)或段内多行,全部保留并按主体拆成逐条 item(报表/PDF 中多行展示);同(项目,年度)多次采集自动按内容去重合并
    • 申报月数(子女教育/3岁以下婴幼儿照护/赡养老人条目附带):子女教育按「当前受教育阶段开始时间/结束时间」时间段与当年相交月数计算(如 2021-09-01/2025-07-31 → 2025 年报 7 个月;只有一端时按该月起/止);3岁以下婴幼儿照护按出生日期计算(出生月 ~ 满 3 周岁当月,如 2022-05 生 → 2022 年报 8 个月、2025 年报 5 个月);赡养老人按出生日期计算(满 60 周岁次月起算,如 1964-05 生 → 2024 年报 7 个月、其后每年 12 个月);随 JSON 与 PDF 导出
    • 同项目同主体跨年名称相同 → 直接复用已采明细,不重复进明细页
  • 👨‍👩‍👧 家庭成员采集(全部采集的最后阶段):右上头像 → 个人信息管理 → 家庭成员信息,逐卡片点「编辑」读 关系/姓名/出生日期(弹窗结构未校准,按通用 el-form-item 读取);专项附加扣除已查到的成员(子女/被赡养人)同名跳过、合并输出;任一步失败跳过不阻塞
  • 🔒 导出脱敏:保存的 JSON / PDF(含内嵌 JSON 附件) / 历史缓存中,姓名(张三→张*)、身份证号(前6后4)、手机号(前3后4)、邮箱(本地部分仅留首字符)、门牌号均打码;合同编号保留前4后2(2009渝银房贷字第611803号→2009*3号);贷款银行只留前2字(中信银行→中信);公司与住址、就读学校只保留省级行政区(重庆市江北区…→重庆市;重庆石马河玉带山小学→重庆市)。例外:本人姓名在 PDF 中不脱敏——文件名与报表标题/「纳税人信息」均显示真实姓名(明文 realName 仅存于历史记录,不进 payload 与内嵌 JSON 附件);家属姓名(配偶/子女/被赡养人/出租人)仍打码。
  • 📤 导出:
    • 采集完成后自动生成并下载 PDF:{姓名}_个税报告_{年度数}_{采集时间}.pdf —— 把数据渲染为中文 HTML 报表后打印,阅读友好(文件名与报表内均为真实姓名;如 张三_个税报告_4年_20260818_153012.pdf);含家庭成员独立一栏与页脚页码
    • 完整 JSON 作为缓存写入历史(不下载文件),供「历史」tab 重新导出 PDF
  • 🔄 跨刷新续采:点「查看」、面包屑返回等任何页面跳转后,自动从断点继续。
  • 🪟 popup 控制台:点扩展图标显示状态/进度/实时日志。

采集逻辑(选择器、数据结构、日期组件操作)均来自同级 tax-tool(Python + Playwright)项目的真机校准结果。

安装(开发者模式)

  1. 打开 Chrome,地址栏输入 chrome://extensions。
  2. 右上角打开**「开发者模式」**开关。
  3. 点击**「加载已解压的扩展程序」**,选择本目录(tax-export/)。
  4. 扩展出现在列表中,工具栏显示蓝色图标。

Edge 同样支持:打开 edge://extensions,开启开发者模式,加载本目录。

使用

  1. 登录 https://etax.chinatax.gov.cn/。

  2. 点击工具栏的扩展图标 → 弹出控制台。

  3. 点击**「开始采集」**。

  4. 脚本自动完成全流程;采集过程中页面会因导航/详情查看而刷新,扩展会自动续采,无需任何操作。

  5. 全部完成后,浏览器自动下载:

    • {姓名}_个税报告_{年度数}_{采集时间}.pdf —— 中文 HTML 报表打印的 PDF(如 张三_个税报告_4年_20260818_153012.pdf,文件名为真实姓名)
    • 完整 JSON 作为缓存写入「历史」(不单独下载文件);在历史 tab 可重新导出 PDF

    JSON 结构(缓存于历史,供 PDF 重新生成):

    {
      "导出时间": "...",
      "申报": {
        "税款所属期起始": "...",
        "列表": [{ "申报项目":"2024年度综合所得年度汇算", "税款所属期":"...", "应缴税款(元)":"...", ... }],
        "详情": [{
          "_detail_sections": {
            "基础信息": { "kv": {...}, "sections": {...} },
            "计税详情": {
              "收入表": [{ "分类":"收入", "项目":"工资薪金", "金额(元)":"298254.85" }, ...],
              "汇总": { "收入":"...", "应纳税所得额":"...", "应纳税额":"...", "已缴税额":"..." },
              "逐项金额": { ... },
              "工资薪金明细": [{ "税款所属期":"2024-12", "收入(元)":"...", ... }]
            }
          }
        }]
      },
      "专项附加扣除": {
        "扣除年度范围": "2022~2026",
        "记录": [{ "项目":"子女教育", "子女姓名":"...", "扣除年度":"2022年", ... }],
        "明细": [{ "sections": { "基本信息": {...}, "教育信息": {...}, ... }, "kv": {...}, "项目":"...", "扣除年度":"..." }]
      }
    }

popup 关闭后再打开,会自动恢复显示当前进度与历史日志。若中途想重来,可在 chrome://extensions 里点扩展的「清除存储」或重载。

PDF 导出原理

JSON → PDF 不依赖外部 PDF 库(避免中文字体嵌入问题),而是走 Chrome 自带打印引擎:

  1. 把 JSON payload 渲染成自包含、打印友好的中文 HTML 报表(report.html + report.js)。
  2. background 用 chrome.windows.create({ state:'minimized' }) 隐藏打开该报表页。
  3. 报表就绪后通知 background;background 用 chrome.debugger(CDP)Page.printToPDF 拿到 base64 PDF。
  4. 用 pdf-lib(vendor/pdf-lib.min.js)把 payload JSON 作为 EmbeddedFile 附件写入 PDF(页面不显示、内容不变,仅 Adobe 等带附件面板的阅读器可见回形针)。
  5. chrome.downloads 下载 PDF。嵌入失败时自动降级为普通 PDF,不影响下载。

转换时会短暂出现最小化窗口 + 调试黄条(CDP 打印必需),属正常现象。中文使用系统中文字体(PingFang SC / Microsoft YaHei),无字体嵌入开销。

从 PDF 取回内嵌 JSON

解析端无需从表格反解,直接读附件即可拿到原始完整 JSON(UTF-8):

# pip install pypdf
import json
from pypdf import PdfReader
payload = json.loads(PdfReader('税务数据报表_xxx.pdf').attachments['payload.json'][0].decode('utf-8'))

其他工具:PDFBox doc.getAttachments();qpdf qpdf --show-attachment payload.json in.pdf out.json。

目录结构

tax-export/
├── manifest.json          # MV3 清单
├── background.js          # service worker:存进度 + JSON 导出 + PDF(printToPDF) + 历史重导
├── report.html            # JSON→HTML 报表渲染页(隐藏 minimized window 加载)
├── report.js              # payload → 自包含中文 HTML 报表
├── vendor/
│   └── pdf-lib.min.js     # pdf-lib(npm run vendor 从 node_modules 同步):PDF 内嵌 JSON 附件
├── content/               # 注入页面的脚本(按 manifest 顺序加载)
│   ├── utils.js           # 底层工具 + JobStore + 日志适配层
│   ├── datepickers.js     # 日期组件(month/date picker)
│   ├── list.js            # 申报:列表准备 + 提取 + 点查看
│   ├── detail.js          # 申报:详情采集(基础信息/计税/工资薪金)
│   ├── deduction.js       # 专项附加扣除:年份选择 + 卡片提取 + 明细导出
│   └── main.js            # 跨刷新状态机主编排
├── popup/                 # 控制台 UI
│   ├── popup.html / .css / .js
└── icons/                 # 16/48/128 图标

状态机(跨刷新续采原理)

采集流程被拆成可持久化的状态,每步存盘,刷新后从断点继续:

【申报查询】(默认视图 → 条件查询 → 已作废,三段 衔接)
navigating → list → (点查看) → detail → (抓详情) → returning → (回列表) → list → ... → 默认视图遍历完
                ↑___________________________________________________|
                          current++ 后继续下一条
【条件查询补采】(默认视图遍历完后衔接)
cond → (设日期条件+查询) → 提取列表,排除默认视图已采年份 → 并入 rows → 继续逐条「查看」
【已作废 tab 补采】(条件查询遍历完后衔接)
voided → (重设条件+点已作废 tab) → 提取列表,排除已采年份 → 并入 rows → 继续逐条「查看」

【专项附加扣除】(申报完成后自动衔接)
deduction-navigating → deduction-year(逐年 setStartYear + 抽卡片)
   → deduction-detail(抓明细) → deduction-returning(面包屑回列表) → 下一条卡片
   → 卡片遍历完 → 下一年 → ... → 全部完成 → 导出

【导出】
申报 + 专项附加扣除 → 完整 JSON 下载 + 写入历史(可重导 PDF)

content script 注入时先读 background 的进度,根据 stage + 当前页面(申报列表/详情、专项附加扣除列表/明细)定位断点:

  • 申报:detail + 在详情页 → 抓详情;returning + 在列表页 → current++;list + 在列表页 → 继续逐条
  • 专项附加扣除:deduction-detail + 在明细页 → 抓明细;deduction-returning + 在列表页 → 下一条卡片;deduction-year + 在列表页 → 继续当年
  • 其它 → 安全回退或从头开始

配置

content/utils.js 顶部常量可调:

常量 默认 含义
YEAR_OFFSET -4 申报:目标年 = 当前年 + 偏移(2026 → 2022)
MONTH 1 申报:月份(1 = 一月)
MAX_ROWS 50 申报列表最多处理条数
MAX_PAGES 50 工资薪金明细最多翻页数
DEDUCT_YEARS_OFFSET -4 专项附加扣除起始年 = 当前年 + 偏移,逐年抓到上一年(2026 → 2022..2025;今年不采)

改完后在 chrome://extensions 点扩展的「刷新」按钮重新加载即可。

已知限制

  • 专项附加扣除任一步失败不阻塞:导航失败或无数据时,JSON 中该字段为 null,申报数据仍正常导出。
  • JSON 导出用 chrome.downloads + data URL;超大 JSON 理论上受 data URL 长度限制(实测常规申报数据远低于阈值)。
  • PDF 导出依赖 CDP(chrome.debugger),转换时浏览器顶栏会出现调试黄条(无法隐藏),属正常。
  • 站点结构若改版,选择器需更新(content 日志会指出失败步骤,单条详情/明细失败不阻塞整体)。
  • 需手动登录;扩展不触碰账号密码与加密层(与 tax-tool 合规口径一致)。

隐私与数据安全

  • 扩展仅在 etax.chinatax.gov.cn 域名下运行,采集的全部数据只保存在你本机(chrome.storage.local),不上传任何服务器、不经过任何第三方。
  • 导出的 JSON / PDF 含你的个人税务信息,请妥善保管,不要分享给他人或提交到公开仓库。
  • 本仓库的 demo/tax_data.json 与 demo/output/(示例数据生成结果)已被 .gitignore 排除;若你本地生成的文件含真实个人信息,请勿提交到公开仓库。

免责声明

使用本软件前请仔细阅读以下条款。下载、安装或使用本软件即表示你已阅读、理解并同意本声明的全部内容。 若不同意,请立即停止使用并删除本软件。

  1. 仅供个人学习与研究:本软件仅用于个人学习、技术研究,以及整理本人在个人所得税电子税务局的申报数据,供办理本人年度汇算清缴、退税时参考。
  2. 非官方工具:本软件与国家税务机关、国家税务总局及任何官方机构无任何关联,亦未获得任何官方授权或认可。本软件产生的数据不具备任何法律效力,办理税务事项请以电子税务局官方渠道的数据与口径为准。
  3. 信息真实性自担:因使用本软件采集、计算、导出的数据而进行的任何申报、更正、退税等操作,均属于使用者本人的自主行为;因数据误差、站点改版、软件缺陷或操作不当导致的任何后果(包括但不限于申报错误、退税延误、补税及滞纳金等),由使用者自行承担,作者不承担任何责任。
  4. 不构成税务建议:本软件(含 demo/ 中的退税计算模板)输出的任何金额、计算结果仅为参考,不构成任何税务、法律或财务建议。涉及重大税务决策请咨询专业人士或主管税务机关。
  5. 禁止滥用:严禁将本软件用于批量采集他人数据、爬取、攻击、干扰网站正常运行或其他任何违法违规用途;使用者须遵守《中华人民共和国网络安全法》《中华人民共和国个人信息保护法》及电子税务局的用户协议。
  6. 按「现状」提供:本软件按「现状」免费开源提供,不提供任何明示或默示的担保(包括但不限于适销性、特定用途适用性、不侵权的保证)。在法律允许的最大范围内,作者对因使用或无法使用本软件而产生的任何直接、间接、偶然、特殊或后果性损害概不负责。
  7. 条款可随时变更:本免责声明及软件功能可能随时更新而不另行通知,请以最新版本为准。

许可证

本项目基于 MIT License 开源发布。

About

Chrome 扩展(MV3):在个人所得税电子税务局自动采集申报数据并导出 JSON/PDF,跨页面刷新自动续采。仅供学习研究。

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages