ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

用 python-docx 与 Jinja2 自动化校验种子期商业计划书模板

用 python-docx 与 Jinja2 自动化校验种子期商业计划书模板 简介这份商业计划书模版面向种子期创业团队、初次创业者及需要撰写融资材料的项目负责人帮助在公司尚未正式注册、缺乏成熟财务数据的早期阶段把项目愿景、市场机会与团队执行力系统整理成投资人可读的正式文档。资源包共1个文件为docx格式约51KB采用提纲式结构使用者可直接在范本框架内填充内容而无需从零搭框架。模版按「概述、未来拟成立的项目公司概况、产品/服务与技术、研发情况、行业和市场」等章节展开并细化到基本情况设计、拟设立公司的股权结构、初期人员构成、管理团队情况、企业发展战略规划、产品服务描述、国内外研发情况与产业政策、研发投入与队伍、知识产权、目标用户及市场分析等条目同时附有撰写说明与格式要求提示可帮助读者逐项核对信息完整性。目前已有67人学习适合需要快速形成融资材料初稿、梳理商业逻辑并查漏补缺的早期项目。1. 种子期商业计划书模板其实是份带约束的数据契约下过这份《商业计划书模版(种子期).docx》的人十有八九第一反应是打开 Word 直接改。改到第三章想起来股权比例变了回头改 2.1.2 那张表改到第八章发现概述里的五年收入预测和财务简表已经对不上了最后交给投资人一版自己都不敢逐字核对的稿子。这份模板真正的价值不在排版而在它隐含的一整套约束十一章固定顺序、概述 5000 字上限、股权结构必须合计 100%、财务预测要求覆盖五年并给出预测依据、全文四号宋体。把这些约束当成人肉检查项出错只是时间问题把它们当成数据契约交给脚本去校验才有复现性。适合两类人正在准备种子轮材料的技术创始人以及需要批量产出 BP 的孵化器、FA 和投资机构中后台。下面按「解析骨架 → 建模表格 → 渲染回写 → 一致性校验 → 交付技巧」的顺序拆。2. 用 python-docx 把 11 章骨架解析成可校验的章节树2.1 .docx 的 OOXML 结构与 python-docx 对象模型.docx 本质是个 zip 包正文在word/document.xml里段落、表格、样式分散在不同 part。直接拿字符串正则去匹配 XML 能做但一遇到w:rPr里嵌套的字体设置就会翻车。常见做法是走 python-docx把Document对象当成入口只关心paragraphs、tables、styles三个集合。pip install python-docx lxml安装后先确认文档的样式名。中文版 Word 生成的标题样式名是「标题 1」英文版是Heading 1同一份文件在不同环境打开可能出现两种写法解析前必须归一化。from docx import Document doc Document(商业计划书模版(种子期).docx) def norm_style(name: str) - str: # 中文 Word 与英文 Word 的样式名需要统一否则层级判断会漏 return (name or ).replace(标题, Heading).replace( , ).lower() for p in doc.paragraphs[:20]: if p.text.strip(): print(repr(p.text.strip()[:40]), |, norm_style(p.style.name))p.style.name拿到的是样式显示名norm_style把它压成heading1、heading2、normal三种。这样后面判断层级只认归一化结果不认原始字符串。2.2 遍历段落重建十一章目录树模板的一级标题形如「一、概述」「二、未来拟成立的项目公司概况」二级是「2.1 公司的基本情况」三级是「2.1.1 基本情况设计」。用两个正则分别匹配再按出现顺序挂到树上。import re, json CH_RE re.compile(r^([一二三四五六七八九十])、\s*(.)$) SEC_RE re.compile(r^(\d\.\d)\s(.)$) SUB_RE re.compile(r^(\d\.\d\.\d)\s(.)$) tree [] for p in doc.paragraphs: text p.text.strip() if not text: continue style norm_style(p.style.name) m CH_RE.match(text) if m and style.startswith(heading1): tree.append({level: 1, cn: m.group(1), title: m.group(2), sections: []}) continue m SEC_RE.match(text) if m and tree and style.startswith(heading2): tree[-1][sections].append({no: m.group(1), title: m.group(2), subs: []}) continue m SUB_RE.match(text) if m and tree and tree[-1][sections] and style.startswith(heading3): tree[-1][sections][-1][subs].append({no: m.group(1), title: m.group(2)}) print(json.dumps(tree, ensure_asciiFalse, indent2)[:800])这段逻辑的关键点在于先匹配文本、再校验样式。如果反过来只看样式模板里那些用普通段落手打的「十、风险分析与控制措施」就会被漏掉——这份模板的第十章、第十一章在目录里存在正文却未必套了标题样式属于典型的半手工文档。2.3 用断言校验模板完整性拿到树之后就能写校验规则。模板的硬约束有四条一级章节数为 11二级编号在每章内从 1 连续递增三级编号前缀必须与所属二级一致「一、概述」正文不超过 5000 字。EXPECTED_CH 11 def validate(tree): errs [] if len(tree) ! EXPECTED_CH: errs.append(f一级章节数为 {len(tree)}模板要求 {EXPECTED_CH}) for i, ch in enumerate(tree, 1): for j, sec in enumerate(ch[sections], 1): want f{i}.{j} if sec[no] ! want: errs.append(f[{ch[title]}] 第 {j} 节编号是 {sec[no]}期望 {want}) for k, sub in enumerate(sec[subs], 1): want_sub f{i}.{j}.{k} if sub[no] ! want_sub: errs.append(f[{sec[title]}] 第 {k} 个子节编号是 {sub[no]}期望 {want_sub}) return errs for e in validate(tree): print(!, e)校验项判定依据常见失败原因章节总数一级标题计数等于 11删章、合并章二级编号连续章内序号从 1 递增手改编号后未重排三级前缀一致与所属二级编号同前缀复制粘贴自其它章节概述长度一级章节正文纯字数 ≤ 5000概述写成全文摘要跑一遍原模板能抓到两处真实问题第九章正文里「9。3 对股权投资的需求」和「9。3 投资人介入公司业务的程度建议」出现了重复编号而且用的是中文句号而非小数点第十七页往后的目录页码与正文实际页码已经错位。这些靠肉眼基本抓不住脚本两秒出结果。提示编号里的中文句号、全角括号是 Word 中文输入法的常见残留正则里用[。.]兼容比事后手工找快得多。3. 五张核心表格的结构化建模股权、人员、专利与财务预测3.1 模板里的五张关键表与字段定义模板真正承载数据的是五张表其余文字都是叙述。把它们抽出来单独存 JSON是后面所有校验和渲染的前提。位置表名核心字段2.1.2拟设立公司股权结构股东名称、证件号、出资比例、出资额、出资形式、到位时间2.1.3成立初期人员构成人员总数、博士/硕士/大专以上人数与占比2.2.2董事会组成及决策机制姓名、职务、工作单位、学历职称、电话4.4知识产权专利情况专利名称、类型、专利号、专利权人、申请日、授权日8.1财务预测简表主营业务收入、税前利润、所得税、净利润、毛利润率、净利润率、研发费用、研发投入占收入比doc.tables返回的顺序与文档中表格出现顺序一致用table.rows[i].cells[j].text逐格取值即可。注意合并单元格会让同一段文本在多个 cell 里重复出现取值前先对cell._tc做去重。3.2 用 dataclass 定义种子期项目实体from dataclasses import dataclass, field from typing import List dataclass class Shareholder: name: str cert_no: str ratio: float # 出资比例单位 % amount: float # 出资额单位 万元 form: str # 货币 / 技术 / 固定资产 paid_date: str dataclass class Company: name: str registered_capital: float 0.0 # 注册资本万元 paid_capital: float 0.0 # 实收资本万元 shareholders: List[Shareholder] field(default_factorylist) intangible_ratio: float 0.0 # 技术等无形资产出资占比《公司法》口径下种子期公司最容易出问题的是出资形式比例无形资产出资占比有上限实收资本超过注册资本属于异常。这类规则写成方法挂在 dataclass 上比写在文档批注里靠谱。def check_equity(c: Company): errs [] total_ratio sum(s.ratio for s in c.shareholders) total_amount sum(s.amount for s in c.shareholders) if abs(total_ratio - 100.0) 1e-6: errs.append(f出资比例合计 {total_ratio}%应为 100%) if abs(total_amount - c.registered_capital) 1e-6: errs.append(f出资额合计 {total_amount} 万元与注册资本 {c.registered_capital} 万元不符) if c.intangible_ratio 70: errs.append(f无形资产出资占比 {c.intangible_ratio}% 偏高需核对当期适用规则) for s in c.shareholders: expect c.registered_capital * s.ratio / 100 if abs(expect - s.amount) 0.01: errs.append(f{s.name}出资额 {s.amount} 与 注册资本×比例 得到的 {expect:.2f} 不符) return errs第三个断言用的是 70% 这个阈值具体上限随时间和地方口径会变实际使用时应以当期公布的规则为准脚本里把它做成常量方便替换。前两条属于纯算术任何时候都成立。3.3 表格与 JSON 双向转换模板里 2.1.2 那张表是空白的实际填写往往是团队在一个 Excel 里维护股东信息再手工誊抄进 Word。抄错一位小数后面所有融资测算全崩。稳妥做法是 Excel/JSON 作为唯一数据源Word 只是渲染产物。import json def table_to_shareholders(table): out [] for row in table.rows[1:]: # 第 0 行是表头 cells [c.text.strip() for c in row.cells] if not cells[0] or cells[0] 合 计: continue out.append({ name: cells[0], cert_no: cells[1], ratio: float(cells[2] or 0), amount: float(cells[3] or 0), form: cells[4], paid_date: cells[5] if len(cells) 5 else , }) return out with open(equity.json, w, encodingutf-8) as f: json.dump(table_to_shareholders(doc.tables[0]), f, ensure_asciiFalse, indent2)反向写入时cell.text value会丢掉原有格式需要改成操作cell.paragraphs[0].runs保留字体设置。这一步不做写回去的表格字体会从四号宋体变成默认的等线体打印出来一眼能看出拼接痕迹。4. Jinja2 渲染加交叉校验让概述数字和财务预测表自动对齐4.1 从数据渲染 Markdown 再回写 docx数据源稳定之后正文不必在 Word 里手写。用 Jinja2 生成 Markdown再用 pandoc 转 docx 并套用原模板作为参考样式整条链路可以脚本化。from jinja2 import Environment, FileSystemLoader env Environment(loaderFileSystemLoader(templates), trim_blocksTrue) tpl env.get_template(bp_seed.md.j2) md tpl.render( companycompany, financefive_year, # 五年财务预测行列表 milestonesmilestones, # 第十一章里程碑节点 ) open(bp_out.md, w, encodingutf-8).write(md)pandoc bp_out.md -o 商业计划书_种子期.docx \ --reference-doc商业计划书模版(种子期).docx--reference-doc是这条链路里最值钱的参数它把原模板里定义好的样式表四号宋体、标题层级、页码域整体继承过来模板里那些「不要删除和调整既有提纲和格式」的要求就自动满足了。换模板只需换这个参数渲染脚本一行不用动。4.2 五年财务数据的口径统一模板 8.1 给了八行指标但只给行不给公式这是最容易埋雷的地方。手工填表时连续三年「净利润 税前利润」这种错误极常见——忘了减所得税。def check_finance(rows): errs [] for r in rows: y r[year] net r[pre_tax] - r[tax] if abs(net - r[net_profit]) 0.01: errs.append(f第{y}年 净利润 {r[net_profit]} ≠ 税前利润-所得税 {net:.2f}) if r[revenue] 0: r_net r[net_profit] / r[revenue] * 100 r_rd r[rd_expense] / r[revenue] * 100 if abs(r_net - r[net_margin]) 0.1: errs.append(f第{y}年 净利润率 {r[net_margin]}% ≠ 计算值 {r_net:.2f}%) if abs(r_rd - r[rd_ratio]) 0.1: errs.append(f第{y}年 研发投入占收入比 {r[rd_ratio]}% ≠ 计算值 {r_rd:.2f}%) if r[tax] 0 and r[pre_tax] 0: errs.append(f第{y}年 亏损年度却计提所得税请核对税收优惠口径) return errs容差设 0.01万元和 0.1百分点是为了容忍模板里手填的四舍五入。要更严就把容差压到 1e-6但那样基本每份手工稿都会报错反而没人看告警。注意模板 8.1 并没有「主营业务成本」这一行所以「毛利润率」无法从表内数据反推。填表时必须另行列表说明成本构成否则两年后自己都还原不出口径。4.3 融资额、出让比例与股权结构表的联动校验第九章的融资需求、2.1.2 的股权结构、1.8 的融资说明三处必须自洽。核心公式只有一条投后估值 融资额 ÷ 出让比例。种子期常见的错误是写「融资 500 万出让 10%」同时投后估值又填了 3000 万。def check_financing(amount, equity_pct, post_money, pre_moneyNone): errs [] implied amount / (equity_pct / 100) if abs(implied - post_money) / post_money 0.02: errs.append(f融资额 {amount} / 出让 {equity_pct}% 投后 {implied:.0f}与填写值 {post_money} 偏差超 2%) if pre_money is not None and abs(pre_money amount - post_money) 1e-6: errs.append(投前估值 融资额 ≠ 投后估值) return errs跑通之后把结果写进 2.1.2 表的备注列投资人问起来能直接指到具体单元格。5. 样式继承、目录域与 pandoc 批量交付的收尾技巧5.1 四号宋体的字号映射与样式落点模板要求「全文请用四号宋体」。四号对应 14pt这个换算不熟的人经常填成 12pt小四打印出来明显偏小。中文字号磅值 pt常见用途五号10.5表格内文字小四12学生论文正文四号14本模板正文小三15一级标题中文字体必须同时设置西文名和w:eastAsia只设前者会让中文回落到默认字体。from docx.shared import Pt from docx.oxml.ns import qn st doc.styles[Normal] st.font.name 宋体 st.font.size Pt(14) st._element.rPr.rFonts.set(qn(w:eastAsia), 宋体)样式落到Normal上之后所有未显式指定字体的段落自动继承比逐个 run 去改稳得多。5.2 目录域与页码的自动更新模板目录里的页码是静态文本插删内容后不会跟着变。正确做法是把目录换成域在 Word 里删除旧目录插入 → 目录 → 自动目录生成的是TOC \o 1-3 \h \z \u域。之后每次更新按 CtrlA 再按 F9选择「更新整个目录」即可。如果文档要交给别人改最好在交付前先自己按一遍 F9避免对方打开时看到的是过期页码还以为内容缺失。5.3 用 pandoc 拆多版本与 diff 管理投资人版、内部版、路演提纲版往往共用同一份数据。把 Markdown 源文件按版本拆成多个.md.j2用同一个 JSON 上下文渲染几秒出三份 docx数字天然一致。版本管理上docx 是二进制git 存了也看不出差异。可行的做法是把 Markdown 中间产物一并提交改动用git diff bp_out.md看正式交付的 docx 只在打 tag 时提交一次。团队协作时再配一条.gitattributesecho *.docx binary .gitattributes echo *.md diffmarkdown .gitattributes这样 Word 文件不会被行尾转换搞坏Markdown 则保留逐行 diff 能力。真正需要长期维护的商业计划书八成的时间花在数字对齐而不是措辞上把对齐这件事交给脚本剩下的精力才够用来打磨第九章的投资退出条款。本文还有配套的精品资源点击获取
返回列表