news 2026/9/20 12:19:54

python-docx 与 docxtpl 自动生成一周工作计划表模板

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
python-docx 与 docxtpl 自动生成一周工作计划表模板

简介:这是一份面向职场人士、团队负责人及行政办公人员的一周工作计划表模板,用于解决周内任务零散、优先级不清、进度难以跟踪的问题,适合个人时间管理、部门周计划填报与团队协作分工等日常办公场景。包内共1个docx文档,约14KB,体量轻巧,可直接用Word打开填写打印,也可按需改成Excel或在线协作表格。文档结构完整,含部门、负责人、日期等表头信息,并设置本周主要任务目标、任务分解的每日工作安排明细、工作完成标准与备注等栏位,按星期一至星期五逐日列出,周末安排休息,便于对照SMART原则填写可衡量目标,明确每项任务的起止时间与交付标准,并在周末回顾调整、优化下周安排。目前已有450人学习下载,适合刚接手周计划编制、希望养成规划习惯的读者参考套用。

1. 每周都要重排一遍的一周工作计划表模板.docx,问题出在哪

周一早上九点,群里一句「本周计划按模板交一下」,接下来半小时就是复制上周的文件、另存为、改周次、删旧任务、忘了改日期区间,最后把「第 32 周」留给同事发现。一份 8 行 7 列的一周工作计划表模板.docx,人力成本从来不在打字,而在每次都重复同一套结构动作,还保证不了不出错。

拆开看,这是两个技术问题:文档结构的生成,和数据到文档的映射。前者适合用 python-docx 直接拼 OOXML 表格,把列宽、行高、合并、底纹固化进代码;后者适合在 Word 里排好版,再用 docxtpl 打 Jinja2 占位符,把 CSV 或任务系统导出的清单灌进去。两条路可以只走一条,也可以组合。

这篇写给需要每周、每项目批量出文档的人:运维值班表、测试周报、外包项目周计划的维护者。从 .docx 的真实结构开始,一路做到能自动生成、自动自检、自动转 PDF。

2. 拆开一周工作计划表模板.docx:OOXML 结构、选型与最小可跑环境

2.1 把 .docx 当 zip 拆开看 document.xml

任何 .docx 都是一个 zip 包。把后缀改成 .zip 解压,或者直接在命令行里列目录,会看到word/document.xmlword/styles.xmlword/settings.xml这几个核心成员。正文全在document.xml里,结构是w:body下面挂着w:p(段落)和w:tbl(表格),表格再往下是w:tr(行)、w:tc(单元格)、w:pw:r(run)、w:t(文本)。

# 不落盘,直接看包里的成员 unzip -l 一周工作计划表模板.docx | head -20 # 只看表格部分的开头,确认 tr/tc 层级 unzip -p 一周工作计划表模板.docx word/document.xml \ | tr '>' '>\n' | grep -E 'w:tbl|w:tr|w:tc|w:gridCol' | head -20

理解这层之后,python-docx 的行为就不再神秘:cell._tc拿到的是 lxml 元素,table._tbl.tblPr拿到的是表格属性节点。API 没覆盖的能力(列宽精确值、单元格底纹、边框线型、标题行重复),全都可以在这层直接改 XML 补上,不用换库。

一个容易忽略的事实:Word 里的「样式」只在styles.xml里定义一次,单元格里的直接格式(字体、底纹、宽度)则会写进每个w:tcPr。这意味着同一张表格里,默认排版和直接格式是两套东西,改样式不一定会影响已经带直接格式的单元格。

2.2 python-docx 与 docxtpl 的选型边界

方案工作方式适合场景不适合
python-docx 从零构造代码里逐行建表、设样式列数/行数随数据变,版式要程序化控制复杂版式,美术要求高,页眉页脚带图形
docxtpl + Jinja2Word 里排好版,模板里放占位符版式固定、内容变化,一周一份或多份需要动态增删列、动态改表结构
直接改 document.xml解压后字符串或 lxml 操作极少数 API 覆盖不到的属性微调常规场景,维护成本高

结论比较直白:版式交给 Word,内容交给代码。一周工作计划表模板.docx 的列结构是固定的七天 ×(日期、任务、优先级、负责人、工时、状态),变的是里面填什么,所以主力用 docxtpl。只有当你需要按月份天数生成不同行数、或者要把模板本身也作为产物生成出来时,才用 python-docx 从零画。

2.3 装环境与最小验证脚本

python -m venv .venv source .venv/bin/activate # Windows 用 .venv\Scripts\activate pip install python-docx docxtpl # 确认导入路径正确,避免装到同名包上 python -c "import docx, docxtpl; print(docx.__file__); print(docxtpl.__file__)"
# smoke_test.py:三行代码验证表格能不能生成 from docx import Document doc = Document() table = doc.add_table(rows=2, cols=7) # 1 行表头 + 1 行数据 table.style = "Table Grid" # 依赖内置样式,见下方提示 table.cell(0, 1).text = "任务事项" doc.save("smoke.docx")

提示:table.style = "Table Grid"取的是内置样式名。如果你是从自己的模板文件Document("xxx.docx")加载的,而那份文件里没有这个样式,会直接抛KeyError。稳妥做法是先doc.styles.add_style("Table Grid", 3)或干脆用 XML 自己画边框。

Document()不带参数时会用 python-docx 自带的默认模板,里面包含 Table Grid、Normal、Heading 系列样式,所以冒烟测试能跑通不代表换到业务模板上也跑得通,这一步必须提前验。

3. 用 python-docx 画出「一周工作计划表模板.docx」的表格骨架

3.1 页面尺寸、页边距与中文字体的 eastAsia 设置

from docx import Document from docx.shared import Cm, Pt from docx.oxml.ns import qn CN_FONT = "微软雅黑" doc = Document() sec = doc.sections[0] sec.page_width, sec.page_height = Cm(21.0), Cm(29.7) # A4 竖版 sec.left_margin = sec.right_margin = Cm(1.6) # 可用宽度 17.8cm sec.top_margin, sec.bottom_margin = Cm(2.0), Cm(1.8) normal = doc.styles["Normal"] normal.font.name = "Calibri" # 只影响西文 normal.font.size = Pt(10.5) normal.element.rPr.rFonts.set(qn("w:eastAsia"), CN_FONT) # 中文走这个通道

font.name只写w:rFonts的 ascii/hAnsi 两个属性,中文走的是w:eastAsia。只设前者时,Word 会把中文回退到默认的宋体,你在代码里写的「微软雅黑」等于没生效。同理,单元格里如果插入了新 run,也要重复设置一次 eastAsia,不能只靠样式继承。

字体选择上还有一条实践经验:本地 Word 用微软雅黑没问题,但如果你打算在 Linux 容器里用 headless 转 PDF,机器上没有这个字体,中文会变方块。容器里更保险的是「思源黑体」或「Noto Sans CJK SC」,用fc-list :lang=zh可以先确认字体装没装。

3.2 表头合并与七天骨架:cell.merge 的行为边界

from docx.enum.text import WD_ALIGN_PARAGRAPH HEADERS = ["日期", "星期", "任务事项", "优先级", "负责人", "计划工时", "完成状态"] WEEKDAYS = ["周一", "周二", "周三", "周四", "周五", "周六", "周日"] table = doc.add_table(rows=9, cols=7) # 1 标题行 + 1 表头行 + 7 天 table.style = "Table Grid" table.autofit = False # 等价于 w:tblLayout type="fixed" # 第 0 行整行合并成标题 title_cell = table.cell(0, 0).merge(table.cell(0, 6)) for c, name in enumerate(HEADERS): table.cell(1, c).text = name for r, day in enumerate(WEEKDAYS, start=2): table.cell(r, 1).text = day table.cell(r, 3).text = "P2" table.cell(r, 6).text = "未开始"

cell.merge(other)返回的是合并后的那个单元格对象,后续内容必须写进返回值,写进原来的cell(0, 0)有时能看到效果,有时看不到,取决于合并方向。合并之后,table.cell(0, 3)之类的索引仍然按 7 列网格返回,只是那几列返回的是同一个 tc 对象——这是新人最容易困惑的地方,看到「明明只写了一次却出现七次」或者「改了没反应」,基本都是没理清这层关系。

table.autofit = False在 python-docx 里就是写w:tblLayout type="fixed",不需要自己拼 XML。它的作用是禁止 Word 打开时按内容重排列宽,否则你在代码里设的宽度,用户一编辑就全变了。

3.3 列宽、行高与固定布局:一张 A4 纸能放多少列

A4 宽 21cm,左右边距各 1.6cm,可用宽度 17.8cm。按下面这张表分配,7 列刚好铺满,任务事项列拿到 8.6cm,足够放下两行中文描述。

用途厘米dxa(1/1440 英寸)
0日期1.6907
1星期1.2680
2任务事项8.64876
3优先级1.4794
4负责人1.81021
5计划工时1.4794
6完成状态1.81021
合计17.810093
from docx.enum.table import WD_ROW_HEIGHT_RULE WIDTHS_CM = [1.6, 1.2, 8.6, 1.4, 1.8, 1.4, 1.8] # 列宽必须逐单元格设置,只设 gridCol 不够 for idx, w in enumerate(WIDTHS_CM): for cell in table.columns[idx].cells: cell.width = Cm(w) for row in table.rows: row.height = Cm(1.1) row.height_rule = WD_ROW_HEIGHT_RULE.AT_LEAST # 内容多了可以撑高 table.rows[1].height = Cm(0.9) # 表头窄一点

table.columns[idx].cells在存在合并单元格时也能用,合并行里七列返回同一个 tc,重复设置宽度没有副作用。行高的height_rule有三个取值:AT_LEAST表示最小高度可被内容撑开,EXACTLY会裁掉超出内容,AUTO交给 Word。周计划表的任务描述长度不可控,一律用AT_LEAST,用EXACTLY会出现「排版好看但内容被截断」的返工。

3.4 底纹、垂直居中与 tblBorders 的插入位置

from docx.enum.table import WD_ALIGN_VERTICAL from docx.oxml import OxmlElement def shade(cell, fill_hex): """给单元格加纯色底纹,fill_hex 不带 # ,例如 D9E2F3""" tcPr = cell._tc.get_or_add_tcPr() shd = OxmlElement("w:shd") shd.set(qn("w:val"), "clear") shd.set(qn("w:color"), "auto") shd.set(qn("w:fill"), fill_hex) tcPr.append(shd) # 顺序敏感,用 get_or_add_tcPr 保证合法 def write(cell, text, bold=False, align=None, bg=None): cell.vertical_alignment = WD_ALIGN_VERTICAL.CENTER p = cell.paragraphs[0] if align is not None: p.alignment = align run = p.add_run() run.text = text run.bold = bold run.font.name = CN_FONT # 必须先设 name,rPr.rFonts 才会被创建 run._element.rPr.rFonts.set(qn("w:eastAsia"), CN_FONT) if bg: shade(cell, bg) def set_table_borders(table, color="8EA9DB", sz=6): """sz 单位是 1/8 磅,6 表示 0.75pt""" tblPr = table._tbl.tblPr borders = OxmlElement("w:tblBorders") for edge in ("top", "left", "bottom", "right", "insideH", "insideV"): el = OxmlElement(f"w:{edge}") el.set(qn("w:val"), "single") el.set(qn("w:sz"), str(sz)) el.set(qn("w:color"), color) borders.append(el) # tblBorders 在 schema 里必须排在 tblLayout 之前 tblPr.insert_element_before(borders, "w:tblLayout", "w:tblCellMar", "w:tblLook")

shade()里用get_or_add_tcPr()而不是自己OxmlElement("w:tcPr")再插,是因为 OOXML 对tcPr内部子元素的顺序有要求,手插容易触发 Word 的「文件内容有问题」提示。

set_table_borders()里那一行insert_element_before是这段代码里最值得记的一笔。表格属性的 schema 顺序是固定的:tblStyle → tblW → jc → tblBorders → shd → tblLayout → tblCellMar → tblLook。如果你先执行了table.autofit = False(写了tblLayout),再tblPr.append(borders)tblBorders就跑到tblLayout后面去了。Word 通常能容忍,LibreOffice headless 转 PDF 时可能直接丢边框——同一份代码在两边表现不一致,排查起来极耗时间。

4. 用 docxtpl 把任务数据灌进一周工作计划表模板.docx

4.1 模板里三种标签的写法与 tr 标签的删行语义

先解释清楚 docxtpl 的标签前缀机制:它在渲染前会扫描文档,把带前缀的标签提升到对应层级,再交给 Jinja2。{%p ... %}提升到段落级,{%tc ... %}提升到单元格级,{%tr ... %}提升到表格行级。

标签作用放在哪里所在行的去向
{{ t.title }}变量替换任意单元格的 run 里保留
{%tr for t in tasks %}行级循环开始单独占一行整行被移除
{%tr endfor %}循环结束单独占一行整行被移除
{%tc if t.owner %}单元格级条件单元格内单元格保留
{%p ... %}段落级控制独立段落段落被移除

tr标签的语义是「包含这个标签的整行被替换成一行 Jinja 语句」,也就是说那一行本身不会出现在输出里,循环体是它与endfor之间的那几行。这带来一个高频事故:把 for 标签和数据写在同一个单元格里,那一行被整行删掉,循环体变成空的,渲染出来只剩表头。正确排布是三行结构——for 独占一行,数据占位独占一行,endfor 独占一行。

另一个坑是标签被 Word 拆散。Word 会把同一段文本按格式拆成多个w:r{{ t.title }}如果一半是宋体一半是加粗,docxtpl 在 XML 层面就找不到完整标签,结果是原样输出。稳妥操作是:标签单独敲一遍,粘贴时用「只保留文本」,或者选中该单元格后清除格式再重打。同时关掉自动更正里的「直引号替换为弯引号」,否则{{ t.get("k") }}里的引号会被改成中文引号,Jinja2 直接语法报错。

4.2 从 CSV 读任务、扁平化成行、渲染出周计划

import csv from collections import defaultdict from datetime import date, timedelta from docxtpl import DocxTemplate # 1) 读数据:一行一条任务,day 列是「周一」这类中文星期 tasks_by_day = defaultdict(list) with open("week_tasks.csv", encoding="utf-8-sig", newline="") as f: for row in csv.DictReader(f): tasks_by_day[row["day"]].append(row) # 2) 扁平化:一行一条任务,日期/星期只在当天首条打印,避免行合并难题 WEEKDAYS = ["周一", "周二", "周三", "周四", "周五", "周六", "周日"] flat = [] for day in WEEKDAYS: for i, t in enumerate(tasks_by_day.get(day, [])): flat.append({ "day": day if i == 0 else "", "date": t.get("date", ""), "title": t["title"], "priority": t.get("priority", "P2"), "owner": t.get("owner", ""), "hours": t.get("hours", "0"), "status": t.get("status", "未开始"), }) # 3) 周次与区间由日期算,不手写 today = date.today() monday = today - timedelta(days=today.weekday()) iso = today.isocalendar() ctx = { "week_no": iso.week, "date_range": f"{monday:%m月%d日} ~ {monday + timedelta(days=6):%m月%d日}", "tasks": flat, } tpl = DocxTemplate("一周工作计划表模板.docx") tpl.render(ctx, autoescape=True) # autoescape 见 4.3 tpl.save(f"一周工作计划表_{iso.year}W{iso.week:02d}.docx")

扁平化那一步是整个流程里最省事的决定。周计划表最直觉的结构是「每天一行、任务列表塞在一个单元格里」,但 Nested loop 在 Word 表格里会变成嵌套表格或换行 run,样式极难控制。改成一行一条任务、日期列只在当天首条输出,视觉上仍然读得通,模板复杂度下降一大截。

encoding="utf-8-sig"是为了吃掉 Excel 导出的 BOM,否则第一列列名会变成\ufeffdayrow["day"]直接 KeyError,这类报错看列名一模一样,很容易卡住。

4.3 UndefinedError、行错位与 XML 转义三类报错

第一类是jinja2.exceptions.UndefinedError: 't' is undefined。要么上下文里少键,要么模板里字段名拼错。快速定位的办法是渲染前先看模板用到哪些变量,tpl.get_undeclared_template_variables()会返回顶层变量名集合,把tasksweek_nodate_range逐个对一遍。模板里也可以给默认值兜底:{{ t.owner | default("待定") }}

第二类是行数不对:输出比预期多一行空白,或者少了一整天的任务。绝大多数情况是{%tr for %}{%tr endfor %}没有独占整行,或者模板里残留了一个复制来的旧标签。用第 5 章的标签残留检查能一次扫出来。

第三类是任务描述里带了&<>这类字符,渲染后document.xml不合法,Word 打开报「文件已损坏,无法打开」。Jinja2 默认不转义,渲染时加autoescape=True就好。这一条在真实数据里命中率不低,任务描述写「联调 A&B 接口」就足以复现。

渲染之后如果发现字体变了,可以在保存的非模板文件上用 python-docx 再扫一遍:

from docx import Document def force_east_asia(path, font_name="微软雅黑"): doc = Document(path) def fix(paras): for p in paras: for r in p.runs: r.font.name = font_name r._element.rPr.rFonts.set(qn("w:eastAsia"), font_name) fix(doc.paragraphs) for t in doc.tables: for row in t.rows: for c in row.cells: # 合并单元格会重复遍历,重复设置无害 fix(c.paragraphs) doc.save(path)

5. 一周工作计划表模板.docx 的批量生成、自检与转 PDF 归档

5.1 按 ISO 周次生成文件名与归档目录

import os from datetime import date, timedelta def week_meta(day: date): iso = day.isocalendar() # 返回 (ISO 年, ISO 周, 星期) monday = day - timedelta(days=day.weekday()) return {"iso_year": iso.year, "iso_week": iso.week, "start": monday, "end": monday + timedelta(days=6)} def out_path(base, meta): folder = os.path.join(base, str(meta["iso_year"])) os.makedirs(folder, exist_ok=True) name = f"一周工作计划表_{meta['iso_year']}W{meta['iso_week']:02d}.docx" return os.path.join(folder, name)

跨年那几周必须用isocalendar().year,不能用date.year。1 月 1 日有可能属于上一年的第 52 或 53 周,用date.year生成目录会把同一周的两个文件分到两个年份文件夹里,归档以后基本找不回来。文件名用W{week:02d}补零,保证ls出来的顺序和时间顺序一致。

5.2 反向读取自检:把「打开 Word 看一眼」变成断言

import re from docx import Document TAG_RE = re.compile(r"\{\{|\{%") def audit(path, expect_label, min_task_rows=1): doc = Document(path) texts = [p.text for p in doc.paragraphs] data_rows = 0 for t in doc.tables: data_rows += max(len(t.rows) - 2, 0) # 扣掉标题行和表头行 for row in t.rows: for c in row.cells: texts.append(c.text) blob = "\n".join(texts) problems = [] if TAG_RE.search(blob): problems.append("仍有未渲染的 Jinja 标签") if expect_label not in blob: problems.append(f"正文里找不到周次标识 {expect_label}") if data_rows < min_task_rows: problems.append(f"任务数据行只有 {data_rows} 行") return problems
检查项判据常见失败原因
标签残留正文搜不到{{{%占位符拼写错,或被 Word 拆成多个 run
周次标识正文里出现W34这类串文件名和正文用了不同的周计算口径
任务行数数据行数 ≥ 任务条数tr 标签没独占一行,循环体为空
日期区间isocalendar算出来一致模板里手写日期没随周次更新

把这四项做成函数,生成之后立刻跑一遍,失败就退出非零码。挂在 CI 或者 cron 上,周一早上收到的就不是「表填错了」,而是构建失败的通知——问题在生成阶段就暴露了,人工只剩确认。

5.3 headless 转 PDF 与并发锁的坑

# 单文件转换 soffice --headless --convert-to pdf --outdir ./weeks/2025 \ ./weeks/2025/一周工作计划表_2025W34.docx # 批量的正确姿势:每个进程隔离用户配置目录,避免互相锁 for f in ./weeks/2025/*.docx; do soffice -env:UserInstallation=file:///tmp/lo_$$ --headless \ --convert-to pdf --outdir ./weeks/2025 "$f" done

-env:UserInstallation这一段不是可选项。LibreOffice 的 headless 实例共用同一个用户配置目录,批量并发时第二个进程会连不上第一个实例,表现是命令返回 0 但 PDF 没生成,或者卡住几十秒后超时。给每个进程一个独立目录,问题消失。

转出来的 PDF 里如果中文是方块,说明容器缺 CJK 字体,用fc-list :lang=zh | head确认,空了就装 Noto Sans CJK。别去改代码里的字体名,那是掩盖问题。

6. 让一周工作计划表模板.docx 扛住模板变更:格式契约与渲染前校验

6.1 用 dataclass 固定字段,渲染前做变量对账

模板和代码会分别演进:有人往模板里加了一列风险等级,代码里没人补这个键,渲染时不报错,只是那格永远是空的。等谁发现了,已经过去三周。用 dataclass 把数据结构钉住,再和模板声明的变量做差集,能在渲染前拦住。

from dataclasses import dataclass, fields from docxtpl import DocxTemplate @dataclass class Task: day: str date: str title: str priority: str = "P2" owner: str = "" hours: str = "0" status: str = "未开始" tpl = DocxTemplate("一周工作计划表模板.docx") declared = tpl.get_undeclared_template_variables() provided = {f.name for f in fields(Task)} | {"week_no", "date_range", "tasks"} missing = declared - provided if missing: raise SystemExit(f"模板引用了代码没提供的变量:{sorted(missing)}")

get_undeclared_template_variables()返回的是顶层变量名,循环内部的t.title只会体现为tasks,所以它是个粗粒度的守门员——但恰好够用,因为「有人加了一列」这件事,最终一定表现为模板里多了一个顶层变量或tasks里多了一个字段。反过来,provided - declared里的多余字段也值得打一条警告,说明代码在往一个已经废弃的列里写数据。

6.2 把渲染跑成一次 pytest:模板改坏了先失败在 CI

比渲染前对账更省心的做法,是把整条链路压成一个测试用例,用固定输入渲染一次,然后跑第 5 章那套audit()断言。

# test_week_docx.py import subprocess, sys from pathlib import Path def test_render_and_audit(tmp_path): csv_in = tmp_path / "week_tasks.csv" csv_in.write_text( "day,date,title,owner,hours,status\n" "周一,08-18,联调 A&B 接口,张三,4,未开始\n" "周三,08-20,回归测试,李四,6,未开始\n", encoding="utf-8-sig", ) subprocess.run([sys.executable, "render_week.py", str(csv_in), str(tmp_path)], check=True) out = next(tmp_path.glob("*.docx")) problems = audit(str(out), expect_label="W", min_task_rows=2) assert problems == [], problems

这份 CSV 的第一行描述特意带了&,用来锁住 4.3 里提到的转义问题——把autoescape=True去掉,这个测试立刻红。测试跑在 CI 上,模板改了、代码没跟上,失败点就在提交阶段,而不是周一早上的群里那句「你这格怎么是空的」。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/20 12:17:16

Modbus调试工具痛点解析:从串口助手到协议级调试器的跨越

1. 为什么我会盯上MThings&#xff1a;传统调试工具的三个死穴在工业现场摸爬滚打久了&#xff0c;你会发现一个特别尴尬的事实&#xff1a;调试设备的工具&#xff0c;往往比设备本身还难伺候。早些年我调Modbus设备&#xff0c;包里永远塞着三样东西——串口调试助手、USB转4…

作者头像 李华
网站建设 2026/9/20 12:17:08

C波段一分三微带功分器设计:威尔金森结构与隔离电阻实现

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/20 12:15:41

VS Code 中 opencode 插件安装配置与实战避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/20 12:14:04

我用GetQzonehistory把QQ空间说说、评论和配图搬进本地表格

我用GetQzonehistory把QQ空间说说、评论和配图搬进本地表格 【免费下载链接】GetQzonehistory 获取QQ空间发布的历史说说 项目地址: https://gitcode.com/GitHub_Trending/ge/GetQzonehistory 跑完 GetQzonehistory 一次&#xff0c;本地 resource/result/你的QQ号/ 目录…

作者头像 李华