返回 Skill 列表
extension
分类: 数据与分析无需 API Key

预制构件(叠合板)BOM清单统计

预制构件PDF图纸BOM清单自动提取与Excel填写。从预制混凝土构件(叠合板等)的PDF详图中识别底板参数表、底板配筋表、桁架钢筋表、预埋配件明细表、构件数量统计表,按PCMES BOM导入模板格式自动填写Excel,钢筋/物料列不足时自动扩展列,并支持表格美化(表头配色、边框、冻结窗格等)。触发场景:识别PDF图纸材料表填BOM、预制构件BOM导入、钢筋下料表提取、桁架钢筋统计、预埋配件统计、PCMES BOM填写、构件BOM清单生成。

person作者: user_ca7097cdhubcommunity

预制构件PDF图纸BOM清单提取与填写

概述

本技能用于从预制混凝土构件(叠合板等)的A4格式PDF详图中,自动提取材料表数据并填写到PCMES BOM导入模板Excel中。

适用场景

  • PDF图纸为A4幅面的预制构件详图,每页一个构件
  • 每页包含5类表格:底板参数表、底板配筋表、桁架钢筋表、预埋配件明细表、构件数量统计表
  • 输出为PCMES 2.0标准格式的BOM导入Excel模板
  • 钢筋类型或物料类型超出模板列数时,自动在右侧追加新列

工作流程

第1步:环境准备

确认Python环境已安装所需依赖:

# 使用managed python创建venv(如果尚未创建)
<python_path> -m venv <venv_path>
<venv_pip> install pdfplumber openpyxl PyMuPDF pillow

依赖包:PyMuPDF(fitz,PDF文本提取)、openpyxl(Excel读写)。

第2步:调查PDF结构

每份PDF的构件编号格式、楼栋、楼层、混凝土标号可能不同,需先调查:

import fitz, re
doc = fitz.open(pdf_path)
for i in range(len(doc)):
    text = doc[i].get_text()
    lines = [l.strip() for l in text.split('\n') if l.strip()]
    # 1. 构件编号:匹配 r'(\d+-\d+F-\d+)详图'
    # 2. 桁架类型:匹配 r'A\d{2,}(-\d+)?$'(至少2位数字,避免误匹配A2等图纸编号)
    # 3. 预埋配件:匹配 r'XH\d+'
    # 4. 混凝土标号:构件数量统计表中的C30/C35等
    # 5. 楼层信息:含 'F~' 的行
    # 6. 钢筋类型:匹配 r'\d+[a-z]?#(?:钢筋|加强筋)' 或 'JQJ'

关键注意:

  • A2是图纸编号标签(出现在页面底部),不是桁架类型。桁架正则要求至少2位数字:r'A\d{2,}(-\d+)?$'
  • 钢筋名称可能出现拼接(如"2#钢筋4#加强筋"在同一行),需用 split_concatenated_rebar_names() 拆分
  • 部分页面可能没有桁架钢筋表(纯底板构件)

第3步:提取PDF数据

使用 scripts/extract_and_fill_bom.py 脚本,或按以下逻辑自行编写:

3.1 底板参数表

正则匹配 底板参数表 后跟构件编号,然后依次提取6个数值: 底板厚、叠合层厚、实际板跨、实际板宽、混凝土体积、底板自重。

3.2 底板配筋表

匹配 底板配筋表\n桁架钢筋表|预埋配件明细表|构件数量统计表|合计 之间的文本。

解析逻辑:

  1. 过滤掉表头行(含"钢筋编号"、"钢筋规格"等关键词的行)
  2. split_concatenated_rebar_names() 拆分拼接的钢筋名称
  3. 逐行扫描,遇到钢筋名称(如"1#钢筋"、"1a#钢筋"、"JQJ")后,收集后续所有数值
  4. 最后3个数值为:单根长、总长、总重
  5. 数量 = round(总长 / 单根长)

3.3 桁架钢筋表

匹配 桁架钢筋表\n预埋配件明细表|构件数量统计表|合计 之间的文本。

解析逻辑:

  1. 过滤表头行和构件编号行
  2. 过滤 A2 等图纸编号(非桁架类型)
  3. 匹配桁架名称:r'A\d{2,}(-\d+)?$'(A80, A80-1, A90, A90-1, A130, A130-1, A140, A140-1等)
  4. 收集后续数值:道数、单道长度、单根重、总长、总重

3.4 预埋配件明细表

匹配 预埋配件明细表\n构件数量统计表|合计 之间的文本。

解析逻辑:按 XH\d+ 编号 → 名称 → 数量 → 备注 的4行一组解析。

配件编码对照:

  • XH1 → 八角照明金属线盒
  • XH4 → 消防金属线盒
  • XH5 → 弱电金属线盒
  • XH6 → 动力金属线盒

3.5 构件数量统计表

匹配 构件数量统计表\n合计 之间的文本。提取楼层(如"4F~11F")、混凝土强度(如C30)。

第4步:填写Excel

4.1 列布局

详见 references/column_mapping.md。核心结构:

| 列范围 | 内容 | 格式 | |--------|------|------| | A-K | 构件基本信息 | 类型/型号/体积/重量/混凝土/尺寸/模具/备注 | | L-O | 楼层信息 | 楼栋/单层数量/起始层/终止层 | | P-X | 基础钢筋(3组×3列) | 1#钢筋(Φ10)、2#钢筋(Φ10)、JQJ(Φ8) | | Y-AG | 基础桁架钢筋(3组×3列) | A80、A80-1、A90 | | AH-AK | 预埋配件(4列) | XH4/XH1/XH5/XH6 | | AL+ | 扩展列(按需添加) | 新桁架/新钢筋类型 |

钢筋列格式(3列):单根长(mm) / 数量(根) / 总重(KG) 桁架列格式(3列):单道长度 / 道数 / 总重 物料列格式(1列):数量

4.2 扩展列规则

当出现模板中没有的钢筋/桁架类型时,从AL列开始向右追加:

  1. 先放新桁架类型(3列一组),再放新钢筋类型(3列一组)
  2. 表头第3行写规格(如Φ8、Φ14)或桁架代号(如A140),不写钢筋代号
  3. 新列样式从同类型已有列复制(钢筋从P列,桁架从Y列,物料从AH列)

4.3 清理模板公式

模板中AI-AL列可能有 #REF! 公式(引用已删除的工作表),需用空字符串 '' 覆盖(用 None 可能不生效)。

第5步:表格美化

使用 scripts/beautify_bom.py 脚本,或按以下逻辑:

  1. 删除说明行:如需删除原第1-2行(标题+说明),必须先 unmerge_cells 所有合并区域,再 delete_rows,最后重新创建合并区域(openpyxl的 delete_rows 不会自动调整合并单元格范围)
  2. 表头配色:第1行深蓝底(#4472C4)白字,第2-3行浅蓝底(#8EA9DB)白字
  3. 数据行:交替底色(白色/#F2F7FC)
  4. 边框:统一浅蓝细线(#B4C6E7)
  5. 列宽:型号14、尺寸10、数量8、长度12、重量10
  6. 冻结窗格:C4(固定表头3行+前2列)
  7. 隐藏网格线ws.sheet_view.showGridLines = False

第6步:验证

填写完成后需交叉验证:

  1. 构件总数是否与PDF页数一致
  2. 每个构件的钢筋/桁架类型是否与PDF一致
  3. 楼栋、楼层、混凝土标号是否正确
  4. 抽查3-5个构件的数值与PDF原文比对

使用脚本

extract_and_fill_bom.py

主提取脚本,接受命令行参数:

python extract_and_fill_bom.py <pdf_path> <xlsx_template> <xlsx_output> <building> <floor_start> <floor_end> <concrete>

示例:

python extract_and_fill_bom.py \
  "C:/Users/.../3#楼4-11层详图0710-1.pdf" \
  "C:/Users/.../PCMES_2.0_xxx_BOM导入_9928.xlsx" \
  "C:/Users/.../output.xlsx" \
  "3#" "4F" "11F" "C30"

脚本会自动:

  • 扫描所有PDF页面,提取5类表格数据
  • 统计所有钢筋/桁架类型
  • 在Excel模板中添加扩展列
  • 填写数据并复制样式
  • 打印验证摘要

beautify_bom.py

美化脚本,接受命令行参数:

python beautify_bom.py <xlsx_path> [--delete-rows <N>]

示例:

python beautify_bom.py "C:/Users/.../output.xlsx" --delete-rows 2

常见问题

Q: PDF提取不到文本?

A: 检查PDF是否为扫描件(图片型PDF)。如果是,需先用OCR处理。本技能仅支持文本型PDF。

Q: 钢筋名称拼接在一起?

A: 如"2#钢筋4#加强筋"在同一行,使用 split_concatenated_rebar_names() 函数拆分。该函数用正则 r'\d+[a-z]?#(?:钢筋|加强筋)'finditer 定位每个名称的起止位置。

Q: delete_rows后合并单元格错位?

A: openpyxl的 delete_rows 不会自动调整 merged_cells.ranges。必须先 unmerge_cells 所有合并区域,删行后再重新 merge_cells

Q: 不同构件同一钢筋类型规格不同?

A: 钢筋表头写最常见规格(取众数),不单独加规格列。如1a#钢筋多数为Φ8,个别为Φ10/Φ12,表头写Φ8。

Q: 桁架类型误匹配A2?

A: A2是图纸编号,不是桁架。正则改为 r'A\d{2,}(-\d+)?$',要求至少2位数字。

Q: 模板中有#REF!公式?

A: AI-AL列可能有引用已删除工作表的VLOOKUP公式。用空字符串 '' 覆盖,不要用 None(可能不生效)。