
1. 周五下午的周报噩梦到底卡在哪一步每到周五下午很多开发者的状态都差不多浏览器开了七八个标签页后台数据、竞品页面、运营看板来回切一边截图一边往 Excel 里贴最后再打开 PPT 模板把图表一张张拖进去对齐。整个过程里真正需要动脑的部分可能只有 10%剩下 90% 都是机械搬运。更难受的是数据一旦更新前面粘贴的内容全部作废只能重来。我试过把这件事拆开看其实链路非常清晰第一步从网页把数据抓下来第二步把数据变成图表第三步把图表和结论填进 PPT 模板。这三步分别对应三个成熟的 Python 库——Playwright 负责浏览器自动化抓取Pyecharts 负责生成交互式图表python-pptx 负责读写 PPT 文件。把它们串起来就是一条可复用的桌面自动化周报流水线。这篇文章面向的是需要周期性产出周报的开发者不要求你会前端也不要求你懂 PPT 底层 XML。你只需要有 Python 基础能看懂函数和类就能跟着把整条链路跑通。我会给出可直接复制的抓取脚本、图表导出配置、PPT 占位符替换代码并且演示如何通过统一的 Key/API 通道完成一次端到端运行与结果校验。整条链路在本地运行数据不出内网适合对数据敏感的场景。先明确一下最终效果运行一个 Python 脚本它会自动打开目标网页、等待数据渲染、抽取指标、生成折线图和柱状图、把图表图片和文字结论填进你准备好的 PPT 模板最后输出一个weekly_report_final.pptx。整个过程大约 30 秒你只需要在周五下午点一下运行。在动手之前先把三个库的职责和安装方式说清楚。Playwright 是微软开源的浏览器自动化框架通过浏览器调试协议直接通信支持 Chromium、Firefox、WebKit 三种内核内置智能等待适合处理 JavaScript 异步渲染的动态页面。Pyecharts 是 Apache ECharts 的 Python 封装链式调用几行代码就能生成带交互的图表支持导出 HTML 和图片。python-pptx 是操作.pptx文件的核心库不需要安装 Microsoft Office 就能读写幻灯片、文本框、表格和图片。安装命令如下建议放在虚拟环境里执行python -m venv venv source venv/bin/activate # Windows 用 venv\Scripts\activate pip install playwright pyecharts python-pptx pandas playwright install chromiumplaywright install chromium这一步会下载浏览器内核第一次执行需要几分钟。如果你所在的环境下载较慢可以只装 chromium不必装全部内核。装完之后用playwright --version确认一下版本能输出版本号就说明环境没问题。接下来要解决的是统一调用通道的问题。抓取、图表、PPT 三步里抓取阶段经常需要调用模型来做页面结构理解或数据清洗如果每个环节都单独配一套 Key维护起来很麻烦。我的做法是把模型调用统一走一个 API 通道Base URL 和 Key 只配一次后面所有脚本都复用。这样换模型、换 Key 的时候只改一个地方不会出现某个脚本还在用旧 Key 的情况。2. 接入 TaoToken 统一通道把 Key 和 Base URL 配一次在写抓取脚本之前先把模型调用的通道配好。这一步的意义在于后面无论是让模型帮你解析页面结构、清洗抓下来的脏数据还是生成周报的文字结论都走同一个入口不用在每个脚本里重复填 Key。对于周报这种周期性任务配置一次、长期复用比每次临时拼凑要省心得多。TaoToken 提供的是统一的 API 通道官网地址是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 入口是 https://taotoken.net/api 。你需要先在控制台创建一个 API Key然后把它写进环境变量而不是硬编码在脚本里。硬编码的 Key 一旦提交到 Git 仓库等于把钥匙挂在门上这个坑我见过太多次。创建 Key 的入口在控制台的 API Keys 页面登录后新建一个 Key复制出来保存好。注意 Key 只在创建时完整显示一次关掉页面就看不到了所以复制后先存到安全的地方。如果你用的是团队协作环境建议给每个成员单独建 Key方便后续按人排查调用量。配置环境变量的方式Linux 和 macOS 用export TAOTOKEN_API_KEY你的Key export TAOTOKEN_BASE_URLhttps://taotoken.net/apiWindows PowerShell 用$env:TAOTOKEN_API_KEY你的Key $env:TAOTOKEN_BASE_URLhttps://taotoken.net/api如果你希望长期生效Linux/macOS 可以写进~/.bashrc或~/.zshrcWindows 可以用系统环境变量面板添加。写完之后用echo $TAOTOKEN_API_KEY确认能读到值。对于使用 Claude Code 或类似编码工具的开发者配置方式略有不同。Claude Code 的配置文件通常放在用户目录下的 settings 文件里你需要填三件套Base URL、API Key、Model ID。Base URL 填https://taotoken.net/apiAPI Key 填你创建的那串Model ID 按你实际要用的模型填写。这三者缺一不可只填 Key 不填 Base URL请求会打到默认地址出现 401 或连接失败。如果你用的是 Cline 这类支持 MCP 的编辑器插件配置逻辑类似也是在设置里找到 API Provider选择自定义 Base URL然后把 Key 和 Model ID 填进去。Codex 的auth.json配置同理需要保证 Base URL、Key、Model ID 三个字段都正确。这里要提醒一句不要把 MCP 直连到生产数据库MCP 适合做工具调用和辅助操作生产库的读写权限要严格隔离。配好之后写一个最小的验证脚本确认通道能通import os import requests base_url os.getenv(TAOTOKEN_BASE_URL) api_key os.getenv(TAOTOKEN_API_KEY) resp requests.post( f{base_url}/v1/chat/completions, headers{ Authorization: fBearer {api_key}, Content-Type: application/json, }, json{ model: 你的模型ID, messages: [{role: user, content: 回复 ok}], }, timeout30, ) print(resp.status_code) print(resp.json())如果返回 200 并且内容里有ok说明通道正常。如果返回 401先检查 Key 有没有复制完整、有没有多余空格如果返回连接错误检查 Base URL 是不是写成了带路径的完整地址。这一步验证通过后后面的脚本就可以放心复用这套配置。需要说明的是周报链路里模型调用不是必须的。抓取、图表、PPT 三步本身可以纯本地完成。模型的价值在于处理非结构化内容比如把抓下来的大段文本总结成三句结论或者根据页面结构变化自动调整选择器。你可以先跑通纯本地版本再按需接入模型能力。3. 可复制配置抓取、图表、PPT 三段脚本这一节给出三段可直接复制的配置和代码。为了让结构清晰我把抓取、图表、PPT 分别封装成类最后用一个主流程串起来。你可以把代码拆成三个文件也可以放在一个文件里按自己的习惯来。先看抓取部分。Playwright 的核心是async_playwright上下文管理器启动浏览器、创建上下文、打开页面、等待网络空闲、抽取数据。这里的关键点是wait_untilnetworkidle它会等到网络请求基本停止再继续适合数据异步加载的页面。另外加一个指数退避重试应对偶发的网络抖动。import asyncio import json from playwright.async_api import async_playwright class WeeklyScraper: def __init__(self, headlessTrue): self.headless headless async def fetch_metrics(self, url, selectors): async with async_playwright() as p: browser await p.chromium.launch(headlessself.headless) context await browser.new_context( viewport{width: 1920, height: 1080}, user_agent( Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 ), ) page await context.new_page() await page.goto(url, wait_untilnetworkidle, timeout60000) await page.evaluate(window.scrollTo(0, document.body.scrollHeight)) await asyncio.sleep(1) result {} for key, selector in selectors.items(): try: text await page.inner_text(selector, timeout5000) result[key] text.strip() except Exception: result[key] None await browser.close() return result async def fetch_with_retry(self, url, selectors, max_retries3): for attempt in range(max_retries): try: return await self.fetch_metrics(url, selectors) except Exception as e: if attempt max_retries - 1: raise await asyncio.sleep(2 ** attempt)调用方式scraper WeeklyScraper(headlessTrue) selectors { revenue: .metric-revenue .value, orders: .metric-orders .value, conversion: .metric-conversion .value, } data asyncio.run(scraper.fetch_with_retry(https://example.com/dashboard, selectors)) print(json.dumps(data, ensure_asciiFalse, indent2))这里的选择器.metric-revenue .value只是示例你要换成目标页面真实的 CSS 选择器。怎么找在浏览器里右键目标元素选“检查”在开发者工具里右键对应的 HTML 节点选“Copy selector”粘贴出来就是。注意动态页面里 class 名可能带哈希后缀这种选择器不稳定优先用语义化的 class 或data-*属性。再看图表部分。Pyecharts 的链式调用很直观add_xaxis加横轴add_yaxis加纵轴set_global_opts设置标题、提示框、工具箱。生成 HTML 之后如果要把图表放进 PPT需要转成图片。Pyecharts 自带snapshot功能但依赖snapshot-selenium或snapshot-phantomjs配置略麻烦。更稳的做法是用 Playwright 打开生成的 HTML截图保存为 PNG。from pyecharts.charts import Line, Bar, Page from pyecharts import options as opts from pyecharts.globals import ThemeType class ChartBuilder: def __init__(self): self.page Page(layoutPage.DraggablePageLayout) def add_line(self, dates, sales, target): line ( Line(init_optsopts.InitOpts(width100%, height400px, themeThemeType.LIGHT)) .add_xaxis(dates) .add_yaxis(销售额(万元), sales, linestyle_optsopts.LineStyleOpts(width3)) .add_yaxis(目标(万元), target, linestyle_optsopts.LineStyleOpts(type_dashed)) .set_global_opts( title_optsopts.TitleOpts(title本周销售趋势), tooltip_optsopts.TooltipOpts(triggeraxis), toolbox_optsopts.ToolboxOpts(feature{saveAsImage: {}}), ) ) self.page.add(line) return line def add_bar(self, categories, values, title): bar ( Bar(init_optsopts.InitOpts(width100%, height400px, themeThemeType.MACARONS)) .add_xaxis(categories) .add_yaxis(指标值, values, label_optsopts.LabelOpts(is_showTrue, positiontop)) .set_global_opts( title_optsopts.TitleOpts(titletitle), tooltip_optsopts.TooltipOpts(triggeraxis), ) ) self.page.add(bar) return bar def render(self, output_htmlreport_charts.html): self.page.render(output_html) return output_html把 HTML 转成 PNG 的辅助函数import asyncio from playwright.async_api import async_playwright async def html_to_png(html_path, png_path, width1200, height800): async with async_playwright() as p: browser await p.chromium.launch(headlessTrue) page await browser.new_page(viewport{width: width, height: height}) await page.goto(ffile://{html_path}, wait_untilnetworkidle) await page.screenshot(pathpng_path, full_pageTrue) await browser.close() asyncio.run(html_to_png(report_charts.html, report_charts.png))最后是 PPT 部分。python-pptx 的核心思路是加载模板遍历幻灯片找到占位符或特定文本框替换内容。模板里可以预先放好标题、正文占位符、图片占位框。替换文本用shape.text_frame.text插入图片用slide.shapes.add_picture。from pptx import Presentation from pptx.util import Inches, Pt class PPTBuilder: def __init__(self, template_path): self.prs Presentation(template_path) def fill_title(self, title, subtitle): slide self.prs.slides[0] for shape in slide.shapes: if shape.has_text_frame: if {{title}} in shape.text_frame.text: shape.text_frame.text shape.text_frame.text.replace({{title}}, title) if {{subtitle}} in shape.text_frame.text: shape.text_frame.text shape.text_frame.text.replace({{subtitle}}, subtitle) def fill_bullets(self, slide_index, bullets): slide self.prs.slides[slide_index] for shape in slide.shapes: if shape.has_text_frame and {{bullets}} in shape.text_frame.text: tf shape.text_frame tf.clear() for i, b in enumerate(bullets): p tf.paragraphs[0] if i 0 else tf.add_paragraph() p.text b p.font.size Pt(18) def add_chart_image(self, slide_index, image_path, left, top, height): slide self.prs.slides[slide_index] slide.shapes.add_picture(image_path, Inches(left), Inches(top), heightInches(height)) def save(self, output_path): self.prs.save(output_path)模板里的占位符用{{title}}、{{subtitle}}、{{bullets}}这种双花括号形式替换逻辑简单不容易误伤正常文本。图片位置用英寸指定Inches(1)就是 1 英寸。如果你不确定模板里占位符的位置可以先写个脚本打印所有 shape 的文本确认一下。主流程把三段串起来def run_pipeline(): scraper WeeklyScraper(headlessTrue) selectors {revenue: .metric-revenue .value, orders: .metric-orders .value} data asyncio.run(scraper.fetch_with_retry(https://example.com/dashboard, selectors)) builder ChartBuilder() builder.add_line([周一, 周二, 周三, 周四, 周五], [12.5, 13.2, 15.8, 14.9, 18.9], [12, 13, 14, 15, 16]) builder.add_bar([本品, 竞品A, 竞品B], [18.9, 15.2, 12.8], 竞品对比) html builder.render(report_charts.html) asyncio.run(html_to_png(html, report_charts.png)) ppt PPTBuilder(weekly_template.pptx) ppt.fill_title(第 20 周周报, 数据截至周五 18:00) ppt.fill_bullets(1, [销售额 18.9 万元环比 15.9%, 订单量 2347 笔转化率 3.8%]) ppt.add_chart_image(2, report_charts.png, left1, top1.5, height4.5) ppt.save(weekly_report_final.pptx) if __name__ __main__: run_pipeline()这套配置里抓取、图表、PPT 三段各自独立你可以单独替换其中一段。比如目标页面不需要登录抓取部分可以换成requests图表不需要交互可以换成 MatplotlibPPT 模板复杂可以只替换文字不插图。模块化的好处就是改一处不影响其他部分。4. 端到端运行与结果校验配置写完之后跑一次完整流程看看每一步的输出是否符合预期。运行命令就是python run_pipeline.py如果代码放在多个文件里确保导入路径正确。运行过程中Playwright 会短暂启动一个无头浏览器你可以在终端看到进度输出。第一步校验抓取结果。脚本跑完后先打印data字典确认每个指标都抓到了值没有None。如果某个字段是None说明选择器没匹配到元素回到浏览器里重新确认选择器。常见原因是页面结构变了或者元素在 iframe 里。iframe 里的元素需要先page.frame_locator定位不能直接用page.inner_text。第二步校验图表。打开生成的report_charts.html在浏览器里看图表是否正常渲染横轴纵轴数据对不对标题有没有显示。如果图表空白多半是数据为空或者格式不对。Pyecharts 对数据类型比较敏感add_yaxis的第二个参数必须是列表不能传单个数字。如果 HTML 能打开但截图是空白检查html_to_png里的wait_until是不是networkidle有时候图表渲染需要额外等待可以在截图前加await page.wait_for_timeout(2000)。第三步校验 PPT。打开weekly_report_final.pptx检查标题页的{{title}}是否被替换正文的项目符号是否正确图表图片是否插入到指定位置。如果占位符没被替换说明模板里的文本和代码里的匹配字符串不一致可能是多了空格或者换行。python-pptx 的text_frame.text会把多个段落合并成一个字符串如果占位符跨段落匹配会失败。建议把占位符放在同一个段落里。第四步校验模型通道。如果你的流程里接入了模型调用比如用模型生成周报结论那么运行后检查返回内容是否正常。可以在脚本里加一行日志打印模型返回的status_code和usage字段确认调用成功且计费正常。如果返回 401回到第 2 节检查 Key 和 Base URL如果返回 429说明触发了频率限制需要在调用之间加延迟。端到端跑通之后建议把整个流程做成定时任务。Linux/macOS 用crontab -e添加一行比如每周五下午 4 点执行0 16 * * 5 cd /path/to/project /path/to/venv/bin/python run_pipeline.py pipeline.log 21Windows 用任务计划程序创建一个基本任务触发器设为每周五 16:00操作设为启动python.exe参数填脚本路径。这样每周五下午你就不用管了到点自动生成 PPT你只需要打开检查一下。关于结果校验还有一个实用技巧在 PPT 生成后用 python-pptx 反向读取一遍把关键文本打印出来和预期值对比。这相当于一个自动化断言能提前发现替换失败的问题。from pptx import Presentation def verify_ppt(path): prs Presentation(path) for i, slide in enumerate(prs.slides): for shape in slide.shapes: if shape.has_text_frame and shape.text_frame.text.strip(): print(fslide {i}: {shape.text_frame.text[:50]}) print(f总页数: {len(prs.slides)}) verify_ppt(weekly_report_final.pptx)如果输出里还有{{开头的占位符说明替换逻辑漏了某个 shape回去检查模板和代码的匹配规则。这个校验步骤花不了几秒但能避免把带占位符的 PPT 发给领导。5. 常见报错排查401、local proxy failed、reading choices、OAuth跑自动化链路时报错集中在几个地方。这一节按真实报错信息来排查每条给出原因和解决方式。401 Unauthorized。这个最常见出现在模型调用环节。原因通常是 Key 不对、Key 过期、或者 Base URL 配错。排查顺序先echo $TAOTOKEN_API_KEY确认环境变量能读到再检查请求头里Authorization是不是Bearer加 Key注意 Bearer 后面有一个空格最后确认 Base URL 是https://taotoken.net/api没有多余路径。如果用的是 Claude Code 或 Cline检查配置文件里的三件套是否齐全——Base URL、API Key、Model ID缺任何一个都会 401。另外Key 如果是在控制台刚创建的确认一下有没有复制完整有时候复制会漏掉末尾几位。local proxy failed。这个报错通常出现在 Playwright 启动浏览器或发起请求时提示本地代理失败。原因是环境里配置了代理但代理服务没启动或者地址不对。排查方式检查环境变量HTTP_PROXY、HTTPS_PROXY是否被设置如果不需要代理直接unset掉如果确实需要确认代理地址和端口正确。在 Playwright 里可以在launch时显式传proxy参数或者用context的proxy配置。注意不要在代码里硬编码代理地址用环境变量管理。reading choices。这个报错出现在解析模型返回时提示读取choices字段失败。原因是返回的 JSON 结构不符合预期可能是请求失败返回了错误对象也可能是模型返回格式不同。排查方式先把原始resp.text打印出来看看实际返回了什么。如果是错误信息按错误码处理如果是正常返回但没有choices检查请求体里的model字段是否正确有些模型 ID 写错会返回空结构。另外流式返回和非流式返回的结构不同如果你开了streamTrue就不能直接读choices要按 SSE 格式逐行解析。OAuth 相关报错。如果你用的是需要 OAuth 授权的工具报错可能提示 token 过期或授权失败。排查方式检查授权流程是否走完token 是否保存到正确位置。对于 Claude Code 这类工具OAuth 配置和 API Key 配置是两条路径不要混用。如果你用的是 API Key 模式就不需要走 OAuth如果工具强制要求 OAuth按官方文档重新授权一次。注意 token 有有效期过期后需要刷新自动化脚本里要处理刷新逻辑或者改用长期有效的 API Key。Playwright 超时。报错信息通常是TimeoutError: page.goto: Timeout 60000ms exceeded。原因是页面加载太慢或者wait_until条件太严格。解决方式把wait_until从networkidle改成domcontentloaded减少等待时间或者增大timeout值或者在goto之后加page.wait_for_selector等待特定元素出现。如果页面有大量异步请求networkidle可能永远等不到这时候用domcontentloaded加显式等待更稳。PPT 占位符未替换。这个不算报错但结果不对。原因是模板里的占位符文本和代码里的匹配字符串不一致。排查方式写个脚本遍历模板所有 shape打印shape.text_frame.text看看实际文本是什么。常见问题是占位符被拆成多个 runtext_frame.text读出来是完整的但替换时如果按 run 操作就会漏。建议统一用text_frame.text整体替换替换后再写回。图片插入位置偏移。python-pptx 的add_picture用Inches指定位置如果模板本身有缩放或者幻灯片尺寸不是标准 16:9图片位置会偏。排查方式打印prs.slide_width和prs.slide_height确认幻灯片尺寸然后按比例计算位置。标准 16:9 的宽度是 13.333 英寸高度 7.5 英寸。如果你不确定先用一个明显的坐标测试比如Inches(0), Inches(0)看图片是不是在左上角。Pyecharts 图表空白。生成的 HTML 打开后图表区域是白的。原因可能是数据为空、数据格式不对、或者主题配置冲突。排查方式先确认传给add_yaxis的列表非空且元素是数字再检查init_opts里的width和height是否合理100%在某些容器里可能算不出实际像素改成固定值如800px试试最后确认render的路径有写权限。定时任务不执行。cron 或任务计划程序配好了但没跑。原因是环境变量在定时任务里不生效或者工作目录不对。排查方式在脚本开头打印os.getcwd()和os.getenv(TAOTOKEN_API_KEY)看输出是否符合预期。cron 的环境变量和登录 shell 不同建议在脚本里显式加载环境变量文件或者用绝对路径。另外cron 的 PATH 可能不包含虚拟环境的 python用绝对路径调用。把这些报错对照表整理一下方便你快速定位报错/现象可能原因解决方向401 UnauthorizedKey 错误、Base URL 错误、三件套缺失检查环境变量和配置文件local proxy failed代理环境变量干扰unset 代理或显式配置reading choices返回结构不符、流式未解析打印原始返回检查 model 字段OAuth 报错token 过期、授权未完成重新授权或改用 API KeyPlaywright 超时页面加载慢、等待条件严格改 wait_until 或加显式等待占位符未替换文本不匹配、run 拆分遍历 shape 打印实际文本图片位置偏移幻灯片尺寸非标准按 slide_width 计算坐标图表空白数据为空、尺寸百分比用固定尺寸检查数据定时任务不跑环境变量、工作目录脚本内打印路径和环境排查的核心思路是先看报错信息定位到具体环节再打印中间结果确认数据流最后对照配置检查参数。不要一上来就改代码先确认输入和输出大部分问题出在配置而不是逻辑。6. 把周报链路用起来从手动到自动的落地建议整条链路跑通之后落地时还有几个细节值得注意。这些不是代码问题而是使用习惯问题但直接影响你能不能长期坚持用下去。第一模板设计要留足占位符。PPT 模板不要做得太满留出标题、正文、图表三个区域每个区域用{{}}占位。模板越简单替换逻辑越稳定。如果你需要多种版式可以准备多个模板文件按周次或月份切换。模板文件放在项目目录下用相对路径引用避免换电脑后路径失效。第二数据源要可配置。抓取的目标 URL、选择器、指标名称不要写死在代码里放到一个 YAML 或 JSON 配置文件里。这样页面结构变了你只改配置不改代码。配置文件示例targets: - name: dashboard url: https://example.com/dashboard selectors: revenue: .metric-revenue .value orders: .metric-orders .value conversion: .metric-conversion .value读取配置用yaml.safe_load简单直接。配置和代码分离之后非开发同事也能帮你维护数据源。第三日志要留痕。每次运行把关键步骤和结果写到日志文件包括抓取时间、抓到的值、图表生成路径、PPT 输出路径、模型调用状态。出问题的时候翻日志比重新跑一遍快得多。日志用 Python 的logging模块设置FileHandler和StreamHandler同时输出到文件和控制台。第四异常要通知。定时任务失败时如果没人知道等于没跑。可以接一个 webhook把失败信息推到团队协作工具。实现方式很简单在try/except里捕获异常然后发一个 HTTP POST 到 webhook 地址。注意 webhook 地址也要放环境变量不要硬编码。第五逐步迭代不要一次求全。第一周先跑通抓取加图表PPT 手动填第二周加上 PPT 自动替换第三周接入模型生成结论第四周做定时任务和异常通知。每一步都验证通过再往下走比一次性写完再调试要快。我见过太多人想一步到位结果卡在某个环节就放弃了。关于模型调用的接入时机我的建议是先跑通纯本地版本确认抓取、图表、PPT 三段都稳定再考虑用模型处理非结构化内容。模型不是必需品它解决的是“页面结构频繁变化”和“文本总结”这两类问题。如果你的数据源稳定、结论固定纯本地版本完全够用还省去了 Key 管理和调用成本。如果你需要长期跑编码类或 Agent 类任务比如让模型自动分析抓下来的数据并生成多页报告可以考虑 Coding Plan 这类长期方案按周期使用比单次调用更划算。模型对话入口适合临时验证模型效果接入文档里有完整的参数说明和示例。API Keys 页面用来管理你的 Key建议定期轮换尤其是团队协作场景。最后说一个实际经验周报自动化的价值不在于省下那一个小时而在于把“周五下午必须手动做”这件事从你的待办里彻底移除。你可以在周四晚上就把数据抓下来周五早上自动生成留出时间检查内容而不是搬运数据。链路跑顺之后你甚至可以扩展到月报、季报换一个模板和数据源就行。真正花时间的是第一次搭建后面都是复用。