ARTICLE DETAIL

资讯详情

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

Python自动化报表生成:从手工复制粘贴到一键搞定

Python自动化报表生成:从手工复制粘贴到一键搞定 先说个背景吧。我接到的任务本身不复杂但特别磨人每天上班第一件事登进内部系统按业务线逐张导报表导完以后打开Excel手工复制粘贴把七八个sheet合并成一张总表再做去重、补空值、统一时间格式最后手动生成几个统计数字塞进周报里给领导发出去。一开始数据量小忍忍也就过去了等业务跑起来之后一天光是对数、改格式就能耗掉快一个小时还老担心哪一列拷错了、哪一行漏掉了。那段时间连续加班有一回半夜导出报表后发现自己把两个相似sheet搞混了站在项目室差点没笑出来。于是我很认真地坐下来用两个晚上做了一个自动化脚本把整套流程从“人肉流水线”改成了“Python一条命令搞定”。这次做的东西就是典型的Python自动化开发。底层逻辑并不神秘无非是让脚本去替代那些重复度高、规则明确、需要按固定格式反复执行的操作。整个过程涉及环境安装、库的选择、代码设计、异常处理、后期优化最后还把脚本打包成了能定时运行的独立任务。这篇就完整复盘一下从需求梳理到最终落地把当时选型和踩坑的细节都写出来给以后做类似工作留个存档也供有同样困惑的朋友抄作业。1. 需求场景与项目目标1.1 这个自动化任务到底在解决什么很多刚接触自动化的人第一反应是“这玩意儿是不是得上很高深的技术”其实真不是。自动化开发的第一步永远是搞清楚你每天手动做的事到底是什么规则能不能被程序描述。我的任务看起来是“拉表、合并、统计、写报告”真正拆开后其实是四件事定时登录内部系统按固定条件取数据把不同来源的数据合并到一个结构里清洗脏数据去空行、去重、统一字段类型和日期格式按模板生成Excel报表附上统计数字和趋势图。这四件事全部是确定性规则不涉及太多主观判断天然适合用脚本跑。我当时最想省掉的不是拉数动作本身而是“合并表时总担心出错”的心理成本——毕竟人手操作的错误率在小样本时看不出来一旦数据量上了几百行任何一列错位都会让整个周报失真。自动化最核心的价值不是快是稳定可复现同样的输入永远得到同样的输出这对数据类工作来说比什么都重要。1.2 为什么选Python而不是现成工具可能有人问现在的BI工具、报表系统不是都能自动拉数和生成图表吗确实可以但我这边的限制比较现实内部系统只给了浏览页面导出Excel都要靠手工点按钮BI工具权限申请流程长而且我要做的不是一张看板是一份带很多手工调整痕迹的月度汇总表。换到Python这边requests、pandas、openpyxl这些库一组合就把“页面操作”直接跳过了数据从接口拿处理和输出全部本地完成从入口到出口都是自己控制。Python的另一个优势是生态成熟网上现成代码多几乎你会遇到的每个小问题都有人踩过。哪怕是我这种平时不常写技术代码的人只要会定义函数、会用列表和字典、能看明白异常提示就能把自动化工具搭起来。后来的实际情况也验证了这点整个项目核心代码量不到六百行真正的难点反倒是环境安装和依赖管理——这部分我会在下一节展开。2. 环境搭建与基础配置2.1 Python安装与版本选择这次我选的Python版本是3.10。为什么不是最新的3.12或3.13理由其实很现实pandas、openpyxl、requests这些库在3.10上全部有稳定轮子不用担心某个依赖还没适配新版本。另一个原因是公司的另一台Linux服务器上已经把3.10当成默认Python版本本地开发和服务器部署保持一致能少踩很多环境差异的坑。安装路径上Windows用户我建议直接去官网下安装包注意勾选“Add Python to PATH”。这个勾选很重要很多人装完以后在命令行敲python提示找不到命令基本都是因为它没勾上。Linux环境则要小心系统自带的Python版本不可乱动许多系统工具依赖它所以我更推荐用pyenv或miniconda来管理独立环境而不是直接替换系统默认python。当时我在一台Ubuntu服务器上跑定时任务就直接用docker拉了个python:3.10-slim镜像把脚本和依赖打包进去既不会污染宿主机也方便迁移。还有一个容易踩的细节装完以后命令行输入python --version看到的版本和你实际运行脚本的版本可能不是同一个。尤其是Windows里如果装了多个Python或者用过AnacondaPATH的顺序会决定到底调用哪个。我建议在项目根目录用python -c import sys; print(sys.executable)确认当前解释器的绝对路径这一步的成本极低却能在后面省掉大量查“为什么库装了我却import不进来”的时间。2.2 VSCode里的Python环境配置编辑器我用的VSCode配合Python和Pylance插件。很多新手容易忽略的关键点是VSCode里右下角要手动选择解释器。如果你没选VSCode大概率会用某个全局默认解释器而你的依赖装在虚拟环境里结果就是编辑器无脑报“导入requests失败”可你在终端运行脚本又一切正常——这个问题我当时排查了好一会儿。具体的配置流程很简单。先创建一个项目文件夹在终端执行python -m venv .venv创建虚拟环境然后CtrlShiftP调出命令面板输入“Python: Select Interpreter”选到.venv\Scripts\python.exe。之后所有终端的激活命令也不要忘了Windows是.venv\Scripts\activateLinux和Mac是source .venv/bin/activate。激活成功后命令行前面会多一个.venv的标识看到它你才知道当前确实用的是虚拟环境。VSCode还有一个值得开的选项是文件保存时启用的格式化建议在settings里把format on save设成true配上默认的black或autopep8。自动化脚本经常要反复改代码格式统一之后看diff和改bug都舒服很多。我不是那种代码洁癖很严重的人但这次靠着格式化省掉了很多低级缩进错误——Python的缩进就是语法的一部分一个看不见的Tab混空格就能让整段代码罢工。2.3 依赖库和虚拟环境管理依赖管理我自己用的是最朴素的requirements.txt。把需要的库写进去锁一下版本别人拿到项目后只需要执行pip install -r requirements.txt就能把环境复现出来。这次我用的核心库如下库名用途安装时的注意点requests请求内部系统接口保持登录会话新版一般不用额外依赖装完可直接用pandas数据读入、合并、去重、字段处理依赖numpy安装慢时建议用国内镜像源numpypandas底层数值运算尽量和pandas版本匹配避免二进制不兼容openpyxl生成和美化Excel文件独立库专门处理xlsx格式matplotlib绘制趋势图画中文时注意字体设置schedule实现定时调度轻量适合单机任务这里有个很常见的坑直接用pip install pandas可能会因为墙外的源慢到怀疑人生甚至超时失败。我当时的做法是加上阿里云镜像pip install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple/。装库失败的时候搞清楚是网络问题还是版本冲突最容易判断的办法是单独装其中一个库看报错信息而别在那一长串依赖里瞎猜。还有一点我始终没有把账号密码写进代码。把敏感信息放在环境变量或单独的config.ini文件里然后让代码读取。这既是安全习惯也是为了方便换环境迁移——万一脚本要部署到服务器总不能因为密码变了就去改代码。3. 脚本结构与处理流程设计3.1 先把手工流程翻译成程序流程真正动手写代码之前我花了大概一小时画了一张“人工操作流程图”。所谓画图不是用那些专业工具就是拿纸笔一步步写打开系统→登录→点查询→导出Excel→打开汇总表→全选复制→粘贴→删重复→改日期格式……写完以后再把每一个手工动作换成对应的代码动作。这一步看似笨但特别管用它能让你一上来就看到哪些步骤可以合并、哪些步骤可以省略、哪些步骤其实是重复劳动。比如我原来手动操作时要先把数据从Excel里复制出来再插到总表里。而代码里根本不需要这个中间落地直接从接口拿到JSON数据解析成DataFrame再合并到总表DataFrame最后一次性写Excel。少了一个中间文件就少了很多“文件没保存”“格式错乱”之类的意外。程序流程的逻辑线是数据获取requests请求→ 数据解析JSON转DataFrame→ 数据清洗去空、类型转换、去重→ 数据聚合groupby统计→ 报表生成openpyxl写Excelmatplotlib画图→ 本地保存与日志输出。这条流水线设计成单向的每一段的输入输出都很明确。好处是任何一个环节出了问题都能很快定位到出错的函数不用在一个大脚本里上下翻找。3.2 模块划分与函数定义我见过很多初学自动化的人喜欢把几百行代码写在一个文件里短时间能跑通但稍微改点需求就得小心翼翼一不小心就把别处弄崩了。这次我一开始就按功能模块拆了文件目录结构大概是auto_report/ ├── config.ini # 连接参数、账号信息、路径配置 ├── requirements.txt ├── main.py # 程序入口调度各模块 ├── api_client.py # 登录、拉取数据的封装 ├── data_clean.py # 清洗、去重、类型转换 ├── report_writer.py # 生成Excel和图表的封装 └── logger.py # 日志记录main.py的代码很短核心逻辑就是读取配置依次调用各模块。下面是我当时的大致写法import configparser from api_client import ApiClient from data_clean import clean_data from report_writer import write_report from logger import setup_logger def main(): logger setup_logger() cfg configparser.ConfigParser() cfg.read(config.ini, encodingutf-8) client ApiClient(cfg[server]) raw_data client.fetch_reports(cfg[query]) df clean_data(raw_data) logger.info(f清洗完成剩余 {len(df)} 行数据) write_report(df, cfg[output]) logger.info(报表生成完毕) if __name__ __main__: main()这样的好处非常直接看main.py就能知道整个程序做了什么想改哪块就进哪个文件。定义函数这件事在自动化开发里不是什么高深技巧但它是保证代码可维护性的底线。每个函数只做一件事名字起得直白一点比如fetch_reports就是拉数据clean_data就是清洗数据哪怕过两周回头再看也能一眼get到思路。3.3 数据清洗类型转换与数组切片清洗阶段是我自定义的流程中花费时间最长的一环。业务数据从接口下来后往往存在各种“脏”情况空值、字符串里的多余空格、日期字段有的是字符串有的是datetime对象、数字列里混着“未统计”这样的文本。这时候pandas提供了很多特别省事的方法但如果你是刚接触一定要养成先看字段类型的习惯。DataFrame.dtypes能告诉你每一列的类型。然后你可能会发现数字列被读成了object时间列被读成了字符串。处理方式我用得比较密集的有两个import pandas as pd df[amount] pd.to_numeric(df[amount], errorscoerce) df[report_date] pd.to_datetime(df[report_date], format%Y-%m-%d, errorscoerce)to_numeric后面的errorscoerce表示转换不了的置成缺失值避免因为一个异常字符导致整个转换失败。to_datetime里的format参数非常推荐显式指定不指定虽然也能猜但猜错的概率不低一旦日期格式有天差地别后面排序和分组就全乱了。再说数组切片。Python的列表、NumPy数组和DataFrame都支持切片我这次用得频繁的是df.iloc[:, 2:5]这种按位置取列以及df.loc[df[status] 已完成]这种按条件取行。切片看着简单但有一个新手特别容易犯的错直接用df df[df[amount] 0]能正常过滤可如果只是取一部分列赋值给新变量没有用.copy()后续修改新变量时可能连同原DataFrame一起改掉。我当时就踩过这个坑统计完准备写报告发现原数据被意外改了排查下来是视图和副本的引用问题。所以只要你想对切片后的结果做修改最好养成加.copy()的习惯。4. 核心功能实现与代码4.1 登录内部系统并自动拉取数据项目里最关键也最容易被低估的一步是“让代码像人一样登录系统并拿到数据”。如果系统有正规开放的API那最好直接用requests.post把用户名密码发过去换一个token就行。但我这边系统的接口文档不公开只能自己分析网页的登录请求用浏览器开发者工具查看提交的参数和Cookie策略。我封装的ApiClient大概是这个样子import requests import time class ApiClient: def __init__(self, server_cfg): self.base_url server_cfg[base_url] self.session requests.Session() self.session.headers.update({User-Agent: Mozilla/5.0}) def login(self, username, password): login_url f{self.base_url}/api/login resp self.session.post(login_url, json{ username: username, password: password }, timeout10) resp.raise_for_status() return resp.json() def fetch_reports(self, query): url f{self.base_url}/api/reports params {date_from: query[start], date_to: query[end]} for attempt in range(3): try: resp self.session.get(url, paramsparams, timeout30) resp.raise_for_status() return resp.json() except requests.RequestException as e: print(f第 {attempt 1} 次请求失败: {e}) time.sleep(2 * (attempt 1)) raise RuntimeError(连续三次请求失败请检查服务状态)用requests.Session而不是每次都新建请求最大的好处是它能自动维持登录后的Cookie。我加了一个简单的重试机制处理网络抖动或系统偶发超时。这里有两个细节值得说一timeout参数一定要设置否则请求挂死会让整个定时任务卡住二异常时不要马上重试用指数退避也就是第一次等2秒、第二次等4秒。这种小技巧在很多现成教程里不会讲但生产环境里特别实用。如果你要自动化拉取的是不开放接口的系统绕不开登录鉴权时可以在代码里加入明文密码的警示不要写死在源码里优先读环境变量或者用系统级的凭据管理工具。我在config.ini里只是留了一个占位符真正常用的是os.environ.get(AUTO_REPORT_PWD)。安全习惯这种东西一开始嫌麻烦后期遇到问题就后悔没早养成。4.2 数据清洗与去重逻辑拿到原始数据后我习惯先看一眼形状和字段列表df.shape、df.columns。数据量大时不要直接打印全部内容用df.head()看前几行就够了否则控制台刷屏不说还容易卡死编辑器。去重逻辑上不是简单调用df.drop_duplicates()就完事。我这次的需求是“同一个订单号只保留最新状态的一条记录”那就要先按订单号分组再按时间排序取最后一条。代码是df df.sort_values(update_time) df df.drop_duplicates(subset[order_no], keeplast)keeplast配合排序后的顺序能准确实现“保留最新状态”。如果直接用默认去重保留的是第一次出现的记录很可能不是你要的版本。这个细节特别值得注意业务上的“去重”极少是无脑删重多半带着“保留哪一条”的隐含规则。清洗阶段我还会删掉全空的行和列df df.dropna(howall) df df.dropna(axis1, howall)dropna同样有很多参数howall表示整行或整列全是空值才删除。千万别一不小心写成dropna()默认形式那会把任何带空值的行全删了数据量瞬间少一大块你还没察觉。4.3 生成Excel报表和趋势图写Excel这一步我用的是openpyxl因为它能直接控制单元格样式比如列宽、字体、颜色、冻结窗格、自动筛选生成出来的报表和人手做的观感差距不大。pandas本身有to_excel方法但它更适合快速导出数据样式控制相对弱一些。我的做法是用pandas先计算好所有要展示的数据再用openpyxl逐项写入并美化。核心代码大概是from openpyxl import Workbook from openpyxl.styles import Font, PatternFill from openpyxl.utils.dataframe import dataframe_to_rows def write_report(df, output_path): wb Workbook() ws wb.active ws.title 汇总 header_font Font(boldTrue, colorFFFFFF) header_fill PatternFill(start_color4F81BD, end_color4F81BD, fill_typesolid) for c_idx, col in enumerate(df.columns, start1): cell ws.cell(row1, columnc_idx, valuestr(col)) cell.font header_font cell.fill header_fill for r_idx, row in enumerate(df.itertuples(indexFalse), start2): for c_idx, value in enumerate(row, start1): ws.cell(rowr_idx, columnc_idx, valuevalue) ws.column_dimensions[A].width 20 ws.freeze_panes A2 ws.auto_filter.ref ws.dimensions wb.save(output_path)这里用dataframe_to_rows会省很多事但需要注意中文列名和数值类型别让Excel把长数字变成科学计数法。那次自动化报表里有一列是订单编号纯数字有十几位直接写入会显示成1.23E12。解决办法是写入前先把该列转成字符串或者设置单元格格式为文本。我用的方案是统一转字符串df[order_no] df[order_no].astype(str)趋势图方面matplotlib常规操作是先画图再插入Excel。有个小坑必须提醒日期横坐标如果太密集标签会全挤成一团根本看不清。我当时一周一张图还好后来同事让我生成按天三十天的趋势直接把X轴标签挤成了黑坨。解决方法是主动设置间距import matplotlib.pyplot as plt import matplotlib.dates as mdates fig, ax plt.subplots(figsize(10, 4)) ax.plot(df[report_date], df[amount]) ax.xaxis.set_major_locator(mdates.DayLocator(interval5)) ax.xaxis.set_major_formatter(mdates.DateFormatter(%m-%d)) plt.xticks(rotation45) plt.tight_layout() plt.savefig(trend.png, dpi150)DayLocator(interval5)的意思是每隔5天显示一个刻度旋转45度是防止最后的标签重叠。再加一个tight_layout图表四周留白就不会被裁掉。这个坑后来同事也遇到过所以我把它单独拎出来算是自动化报表里高频出现的“小毛病”。4.4 补充自动化脚本的拓展封装做完第一版能用的脚本后我发现它只能“手动在命令行里运行”还不够自动化。于是我加了两层能力。第一层是用Python标准库subprocess调用系统命令来完成一些周边操作。比如生成报表后需要把最新文件拷贝到共享目录或者压缩成zip归档。人工做这些很烦但我可以让脚本自己调用命令import subprocess result subprocess.run( [zip, -r, report_archive.zip, output/], capture_outputTrue, textTrue ) if result.returncode ! 0: print(result.stderr)这个模块的本质就是让Python替你在新进程里执行原本要手敲的命令非常契合自动化的场景。但有一点要注意能用Python库完成的事尽量别绕道去调系统命令比如压缩文件我更推荐直接用zipfile库因为这样代码在不同操作系统上表现更一致。subprocess更多是用来调那些没有Python替代方案的专用工具。第二层是定时调度。我的脚本最终部署在服务器上用Linux的crontab跑最简单30 9 * * * cd /opt/auto_report /opt/auto_report/.venv/bin/python main.py report.log 21这行的含义是每天9点30分执行脚本并把输出写入日志。如果你在Windows环境可以用“任务计划程序”或直接加一个轻量的schedule库到代码里import schedule import time schedule.every().day.at(09:30).do(main) while True: schedule.run_pending() time.sleep(60)定时任务有个天然坑脚本运行过程中一旦卡住后续任务就会堆叠阻塞。所以我在脚本里加了超时控制在拉数循环里做最大次数限制还会把执行结果写进日志文件。日志是排查一切问题的基础千万别嫌麻烦省掉否则线上出bug你连从哪下手都不知道。5. 调试与优化实录5.1 处理“整型、字符串来回打架”的报错开发过程中我遇到最多的异常就是类型不匹配。最典型的一次程序报ufunc multiply cannot use operands with types dtype(M8[ns]) and dtype(float64)。当时我立刻懵了盯着报错看了半天最后发现问题出在我把一个含日期列的DataFrame和一个含金额的Series直接相乘逻辑上完全不对纯粹是自己写错了需求。这个经历给我的教训是面对报错第一件事不是去搜错误信息而是回看自己要对数据做什么操作。类型转换不是靠猜的而是要清楚知道每一列应该是什么类型。用pd.to_datetime转换日期用pd.to_numeric转换数值用astype(str)转换ID字符。关键是要在你需要做计算之前就完成转换而不是等到运算报错才回头补。另一个经验是尽量用errorscoerce。它的好处前面说过转换不了的部分变成缺失值而不会让整个操作崩掉。但注意这会导致一部分数据静静地变成空值所以转换完必须检查一下空值比例。如果空值比例异常高说明原始数据格式和你预想的不一致需要回头核对接口返回字段。5.2 依赖冲突和爬取环节超时中间有一个版本问题是让我印象很深的我一开始随手装了最新版的pandas结果它同时把一个新版的numpy也带上来了。另一个旧项目里固定使用numpy旧接口两个项目共享同一个Python环境后旧项目直接跑不起来了。这个问题的根源就是没有隔离环境。解决办法也很简单不同项目建不同虚拟环境依赖版本全部锁在requirements.txt里。如果服务器上已经一团乱最省事的方案是用Docker重新跑一个干净容器我当时在Ubuntu上就是这么干的写一个Dockerfile里面FROM python:3.10-slimCOPY requirements.txt然后RUN pip install这样宿主机Python再怎么乱都不影响自动化任务。超时问题更常见。我写定时任务后有一天下载数据比平时慢了一倍所有环节都在等requests返回。我之前加的3次重试机制能兜底但如果每次都等到30秒超时才重试效率太低。更合理的做法是把超时时间设成一个配置项在系统慢的时段适当调大同时把请求改为流式处理避免一次性把所有数据都载入内存。对于数据量特别大的接口分页拉取是标准解法每次只拿几百条翻页循环最后合并。虽然代码多一点但内存占用和单次请求成功率都明显改善。5.3 性能优化减少无效计算和频繁调用脚本上线后跑了几周运行时间越来越长。我一度怀疑是不是服务器负载问题后来用cProfile跑了一次性能分析才发现有一半时间花在反复调用一个用途不大的OCR接口上。事情是这样的最初为了兼容某些扫描件数据我引入了一个OCR识别库用它识别截图里的文字。但实际业务里绝大多数数据都来自结构化接口OCR是纯兜底场景而且那个库在CPU上跑起来资源占用很夸张一张图就要吃掉不少计算资源批量环境下直接就卡住了。我最后做的优化策略是“优先走结构化接口OCR只在完全拿不到数据时才启用”并且把OCR调用放成独立子进程设置超时后自动杀掉。这个改动让整体耗时从三分钟降到了四十秒。自动化开发里一个非常重要的原则是能用接口拿到的数据绝不靠解析页面能解析页面就绝不靠OCR层级越靠前的方案越稳定、越快。很多工具看着炫但未必适合你的高频主流程。优化还体现在代码细节循环里不要反复调用df.loc去查数据能用向量化操作就用向量化写Excel时不要一行一行cell.value 去设置尽量整列赋值日志里也不要输出太庞大的DataFrame内容否则全是IO开销。这一块只要做到“数据往内存里少倒腾几趟”效率就能提升一个量级。6. 常见问题排查速查与避坑技巧6.1 问题排查速查表我把这次开发和上线过程中遇到过的典型问题整理成了表格方便以后快速对照。现象可能原因解决思路pip安装库失败网络慢或镜像源不稳定换用阿里云、清华等镜像源或设置代理合规网络环境下配置命令行敲python没反应未添加PATH或解释器冲突安装时勾选Add to PATH用sys.executable确认解释器路径编辑器报错但命令行运行正常VSCode选错解释器选择虚拟环境对应的Python解释器df过滤后修改影响原数据未使用.copy()导致视图引用切片结果要修改时主动加.copy()日期列转成时间后全是NaT原始日期格式不匹配显式指定format参数常见格式要事先整理好大数字变成科学计数法Excel默认格式问题写入前转为字符串或改单元格数字格式定时任务卡死请求未设timeout为所有网络请求设置超时上限和重试次数脚本运行占用内存过大一次性加载全量数据分页拉取处理完的数据及时释放引用这个表格是我踩坑之后的真实汇总省得下次再重复翻文档。其实大多数自动化脚本的问题最后都能归到“环境不一致”和“数据格式不好”这两大类上提前在入口处做好检验比事后到处打补丁强一百倍。6.2 独家实操技巧有几个技巧不是教程里能学到的但实战中特别好用我单独说一下。第一日志要分文件写。不要把print当作日志用。我当时用Python自带的logging模块把INFO和ERROR分开输出到不同文件这样任务失败时只要看error.log就知道问题所在不用在几十MB的stdout里翻关键信息。日志格式里务必带上时间戳和函数名定位问题的速度完全不一样。第二写Excel之前先备份。脚本一旦跑起来覆盖文件是秒级的事。我经历过一次因为在测试环境跑了一遍完整脚本直接把生产汇总表覆盖了还好那个表是从历史数据重建的不然真会出事故。后来我在代码里加了自动备份逻辑凡是输出路径已存在就先重命名成带时间戳的备份文件再写新文件。第三开发阶段一定要先用一小份样本数据跑通全流程再上全量数据。我第一版代码去重逻辑写反了如果不是先用20行样本数据测试直接跑全量数据那天的报表全都会错。小样本验证的时间成本极低却能避免最贵的错误。第四代码里写好注释命名别偷懒。建议函数名和变量名都用完整的英文单词组合比如pending_orders、archived_files千万别用a、b、tmp这种。自动化脚本可能几个月后还要改到那时候你唯一能依赖的就是清晰的命名和注释。结尾一点个人体会这次Python自动化开发做下来我最深的感受是自动化真正的难度不在写代码而在“把你的工作语言翻译成程序语言”。翻译得越准确脚本就越可靠维护成本就越低。我后来把它扩展成了一个小工具集每天定时跑偶尔有异常也最多是重试几次就解决我再也没有为合并报表加班过。回想起来最值得的投入不是那两晚上的编码而是前面花掉的梳理流程和确认需求的时间。如果你也想复制这种“一劳永逸”的效果不妨就从你手头最烦的那件重复事开始像我一样把流程先写下来再一句一句让它变成Python代码。
返回列表