ARTICLE DETAIL

资讯详情

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

网页数据一键变可编辑Excel:Skill开发全流程拆解与避坑指南

网页数据一键变可编辑Excel:Skill开发全流程拆解与避坑指南 最近整理了一个新的 Skill名字很直白把网页数据直接变成一张能编辑的表格。给 Claude Code、Codex 这类编程代理丢一个链接它就能自动把页面里的数据抓下来整理成 Excel 或 CSV打开就能改。听起来就是“网页采集”四个字但真正要把稳定性和通用性做出来里面全是细节。今天把整个设计思路、脚本实现、调参过程和踩过的坑完整拆开给准备做 Skill 开发或者正在找网页采集方案的朋友一份能直接落地的参考。1. 这个 Skill 到底解决什么问题1.1 从“网页上有数据”到“表格里能编辑”很多人都有过这种经历看到一个网页上有表格第一反应是鼠标选中、复制、粘到 Excel。数据少的时候没问题但页面稍微复杂一点就原形毕露。我之前接过一个需求要整理某个公开页面里的成绩排名。页面上一共二十多行数据看起来很简单但复制到 Excel 后表头错位、合并单元格里的内容丢失、序号列带着一堆空格最麻烦的是页面里还混着几个广告块粘贴进来后全变成了垃圾行。最后只能手动清理原本十分钟能搞定的事硬是折腾了一个下午。这个 Skill 要解决的就是这个场景把“网页数据采集 表格化 可编辑”这条链路变成一个 Agent 能直接调用的技能包。用户只需要给一个 URLAgent 自动抓取、解析、清洗、导出最后生成一个能直接用 Excel、WPS 或者 Google Sheets 打开编辑的.xlsx文件。这里说的“可编辑”不是生成一张图片或者一段截图而是真正结构化后的数据文件每一列有表头每一行是一条记录金额、日期、超链接这种字段类型尽量保留打开后可以排序、筛选、修改、另存。1.2 为什么用 Skill而不是普通提示词先用一个比喻解释。普通提示词像是你每次都跟 Agent 说“帮我把这个网页里的表格整理出来”但没说怎么抓、用哪个库、遇到动态页面怎么办。Agent 每次都要现场猜效果全看模型的临场发挥。Skill 则像是一个工具箱你把抓取逻辑、解析规则、依赖清单、输出格式全部提前装好Agent 接到任务时只需要按图索骥地调用。Skill 和 Agent 的区别也在这里。Agent 是一个能规划、能决策、能调工具的执行主体Skill 是它手里一个高度封装的“技能包”。两者不是替代关系而是配合关系。一个 Agent 里通常可以装多个 Skill比如网页转表格、代码审查、数据处理、报告生成。每个 Skill 都负责一类相对固定的工作。很多人找“省 token 的 Skill”本质逻辑就是固定流程进了脚本和说明不再是靠对话轮次来回试探。这个思路在网页转表格这种任务上特别适用。抓网页、解析 HTML、清洗数据这一套流程完全可以确定性执行没必要让模型每一步都靠推理失败率低速度还快。2. 整体设计思路从网页 URL 到可编辑 Excel2.1 先定输出格式什么样的表格才算“能编辑”动手写代码前我纠结过输出格式。最后反复对比下来常见的选择有四种输出格式优点缺点适用场景CSV通用、体积小、任何表格软件都能打开不支持多 Sheet、样式、超链接简单数据交换XLSX支持多 Sheet、单元格格式、超链接、公式文件稍大依赖 openpyxl大多数业务场景推荐默认Markdown 表格轻量、方便贴进文档编辑能力弱不适合大数据量快速预览HTML 表格浏览器里就能编辑不通用数据交互弱内部临时页面我最终的方案是以.xlsx为默认输出同时保留--format csv选项。原因很简单.xlsx能承载的信息量最大打开体验最接近用户对“可编辑表格”的认知。多张表格还能放进不同的 Sheet而不是全部挤在一起。2.2 抓取链路拆解静态页面、动态渲染与数据清洗网页转表格的抓取链路本质上就三步拿 HTML、解析结构、导出数据。难点在于每一步都有很多分支。第一步“拿 HTML”有静态和动态之分。静态页面用 Python 的requests就能拿到完整 HTML速度最快。但今天很多页面是前端渲染的requests拿到的只是空壳真正的表格数据要等 JavaScript 执行完才出现在 DOM 里。这时候要么用 Playwright 模拟浏览器要么退而求其次找页面里是否暴露了 JSON 数据接口。第二步“解析结构”我的选择是 BeautifulSoup 加 pandas。BeautifulSoup 负责定位table节点pandas 的read_html负责把 HTML 表格转换成 DataFrame。为什么选这两个库因为它们是 Python 生态里最成熟、社区资料最多的组合遇到问题搜一下就有答案。解析不能只处理规整的表格还要处理嵌套标签、合并单元格、表头重复这些脏情况。第三步“导出数据”相对最简单但有一个关键点编码和格式。CSV 一定要用utf-8-sig不然 Excel 打开中文会乱码Excel 导出时尽量把表头字符串里的空白字符清理掉否则后面groupby、筛选都觉得别扭。2.3 Skill 的目录结构怎么设计主流的 Agent Skill 机制基本都遵循同一个约定一个目录里放一个SKILL.md作为入口然后按需放脚本和依赖文件。我这个 Skill 的工程结构是这样webpage-to-table/ ├── SKILL.md ├── requirements.txt ├── scripts/ │ └── page_to_table.py └── examples/ └── demo_result.xlsxSKILL.md是 Agent 的“使用说明书”里面要写清楚这个 Skill 什么时候触发、怎么调用、有哪些限制。requirements.txt一定要有很多 Agent 在装依赖时如果发现缺少依赖声明会直接拒绝执行这是我在实际使用中踩过的坑。scripts/放核心脚本examples/放一个生成好的示例文件方便别人一眼看懂输出长什么样。目录结构不要搞得太深。Skill 的核心价值在于快速复用文件太多、层级太深Agent 反而不容易正确引用。3. 手把手实现一个 Skill核心文件与脚本拆解3.1 准备环境与依赖建议先用虚拟环境隔离依赖python -m venv .venv source .venv/bin/activate # Windows 上执行 .venv\Scripts\activate然后安装依赖pip install requests beautifulsoup4 lxml pandas openpyxl如果你的目标页面是动态渲染的再补一个 Playwrightpip install playwright playwright install chromium依赖版本不需要追新。我自己的经验是pandas2.x 和requests2.31.x 组合已经非常稳定不需要每次升级都跟着改。3.2 SKILL.md 写什么才能让 Agent 准确触发SKILL.md的description是整个 Skill 里最重要的字段。写得太宽泛Agent 会在不合适的时候调用写得太具体Agent 又容易漏掉。以下是我实测后比较顺手的写法--- name: webpage-to-table description: 当用户给出网页链接并希望把网页中的表格、排名、清单或结构化数据导出成 Excel/CSV 等可编辑表格时使用。典型说法包括“把网页做成表格”“抓取这个页面的数据”“导出为 Excel”。 --- # 网页转表格 Skill ## 功能 - 根据 URL 抓取公开网页内容 - 自动识别页面中的表格节点并解析为 DataFrame - 清理表头空格、空列、重复行 - 默认输出 .xlsx支持 CSV ## 调用步骤 1. 先运行python scripts/page_to_table.py --url URL --output 输出文件路径 2. 脚本成功后把生成文件的位置告诉用户 3. 如果页面需要登录或动态渲染脚本输出会有提示不要强行承诺成功 ## 注意 - 默认请求超时 15 秒 - 只处理公开可访问的页面 - 遵守目标网站的访问规则和 robots.txt - 如果脚本返回 err_empty_response先重试或稍后再运行这里每一句都在给 Agent 传递边界信息哪些事能做哪些事不能做失败后怎么处理。3.3 核心脚本解析与导出page_to_table.py的核心逻辑可以分成三块抓取 HTML、解析表格、导出文件。#!/usr/bin/env python3 import argparse from pathlib import Path from io import StringIO import pandas as pd import requests from bs4 import BeautifulSoup DEFAULT_HEADERS { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0 Safari/537.36 } def fetch_html(url, timeout15): 抓取 HTML并尝试修正编码问题。 resp requests.get(url, headersDEFAULT_HEADERS, timeouttimeout) resp.raise_for_status() # 有些服务器没正确声明编码pandas 解析会出现乱码 if not resp.encoding or resp.encoding.lower() in (iso-8859-1, ascii): resp.encoding resp.apparent_encoding return resp.text def parse_tables(html): 从 HTML 中提取所有表格并做基础清洗。 soup BeautifulSoup(html, lxml) table_nodes soup.find_all(table) frames [] for table_node in table_nodes: df pd.read_html(StringIO(str(table_node)))[0] # 清掉整列为空、行重复、表头空格 df df.dropna(axis1, howall) df df.drop_duplicates() df.columns [str(c).strip() for c in df.columns] frames.append(df) return frames def save_output(frames, output_path, fmtxlsx, table_indexNone): 导出为 xlsx 或 csv。 if table_index is not None and table_index 0: frames [frames[table_index]] if fmt csv: frames[0].to_csv(output_path, indexFalse, encodingutf-8-sig) return with pd.ExcelWriter(output_path, engineopenpyxl) as writer: for idx, df in enumerate(frames): sheet_name fSheet{idx 1} df.to_excel(writer, sheet_namesheet_name, indexFalse) def main(): parser argparse.ArgumentParser(description网页数据转可编辑表格) parser.add_argument(--url, requiredTrue, help目标网页 URL) parser.add_argument(--output, requiredTrue, help输出文件路径) parser.add_argument(--format, defaultxlsx, choices[xlsx, csv]) parser.add_argument(--table-index, typeint, defaultNone, help指定导出第几张表默认全部导出) parser.add_argument(--timeout, typeint, default15) args parser.parse_args() html fetch_html(args.url, args.timeout) frames parse_tables(html) if not frames: raise SystemExit(未找到表格节点可能需要动态渲染或更换解析方式) output_path Path(args.output) output_path.parent.mkdir(parentsTrue, exist_okTrue) save_output(frames, output_path, args.format, args.table_index) print(f完成共导出 {len(frames)} 张表保存到 {output_path}) if __name__ __main__: main()这里的清洗逻辑是我反复调试后留下来的最小集合。dropna(axis1, howall)能干掉整列为空的干扰列drop_duplicates()处理页面中重复渲染的行df.columns清理表头空格避免后面用列名取值时踩坑。3.4 配置参数与 Agent 调用示例脚本支持的参数不多但每个都有实用价值参数作用使用建议--url目标页面地址必填--output输出文件路径建议带清晰文件名比如scores.xlsx--format输出格式默认 xlsx简单字段可用 csv--table-index指定第几张表页面有多张表时用从 0 开始--timeout请求超时时间默认 15 秒大页面可调大Agent 实际调用时的场景大概是这样用户说“帮我把这个公开页面的获奖名单整理成表格。”Agent 识别到需求匹配webpage-to-table先判断 URL再调用脚本最后把生成的获奖名单.xlsx路径返回给用户。如果用户只想导出其中一张表Agent 会先跑一次完整解析然后根据输出里列出的表索引补一个--table-index 1重新导出。整个过程用户不用管脚本是怎么跑的体验上就像是发了一个指令然后拿到一个文件。4. 实测中的坑网络异常、脏数据与 Agent 调用问题4.1 err_empty_response最常见的网络假故障我在测试过程中遇到过很典型的情况页面在浏览器里打开正常但脚本请求时抛错错误信息类似“未发送任何数据”或者err_empty_response。说实话这种错误很多时候不是代码问题。目标服务器在 TCP 连接建立后没有返回完整 HTTP 响应直接断开了连接。常见原因包括服务器临时过载、请求频率太高被限流、CDN 边缘节点不稳定、本地网络到目标服务器之间的链路抖动。我的排查顺序是先确认 URL 在浏览器里能正常打开再用脚本加长超时时间试一次然后换一个 User-Agent 试试最后在请求之间加一个短重试。不要在同一个请求上来回死磕往往等一段时间就恢复了。4.2 表格识别错乱与脏数据网页表格最麻烦的不是抓不到而是抓到之后结构是乱的。常见情况有三种第一种是页面里有多张表默认全部导出时用户发现多出来一堆不相关的 Sheet。解决办法就是--table-index参数按索引导出指定表。第二种是合并单元格。pandas 解析合并单元格后部分行会出现NaN不是真缺失只是因为合并导致父行的值没被重复填充。处理时要先fillna(methodffill)再去掉重复行。第三种是表头不固定。有的页面第一行是页面标题第二行才是真正的表头。我一般会加一步判断如果第一列都是中文长文本且后续行看起来像数据就用下一行做表头。这个判断虽然简单但在真实页面上非常管用。4.3 Agent 调用 Skill 失败或效果不稳定代码本身没问题但 Agent 就是不调用或者调用出错这类问题也很常见。我在开发初期踩过的坑主要集中在三个方面。第一SKILL.md的description写得太抽象。Agent 判断是否调用 Skill主要就看描述和相关关键词。如果写的是“网页数据处理”这种泛泛的说法Agent 可能把它用在完全不相干的场景上。正确做法是写清楚触发场景、典型用户说法和输出结果。第二依赖缺失。很多 Agent 在准备执行 Skill 时会先看有没有requirements.txt或依赖声明。如果脚本里import pandas但没有任何依赖文件Agent 可能直接报错或者花很长时间现场装环境。我的习惯是把依赖声明得越明确越好。第三脚本路径问题。Agent 的当前工作目录不一定和 Skill 目录一致在SKILL.md里写调用命令时最好用相对 Skill 根目录的路径或者在命令里明确cd到 Skill 目录。4.4 常见问题速查表现象可能原因处理方式err_empty_response服务器断开连接、链路问题等待重试、加长超时、换 UA请求超时目标页面响应慢调大--timeout配合重试403 Forbidden被目标站拦截检查访问规则降低频率不要硬闯中文乱码编码声明缺失或错误用resp.apparent_encoding修正导出的表为空页面是动态渲染改用 Playwright 方案或查找接口多导出了无关表页面包含多个 table用--table-index指定Agent 不调用 Skilldescription 不够具体重写描述增加触发关键词提示缺少依赖没有声明 requirements补全依赖文件5. 发布与扩展让你的网页转表格 Skill 更值钱5.1 不只抓表格扩展到列表、卡片和 JSON 数据很多页面没有table标签数据是卡片或者列表布局。这个 Skill 其实可以扩展成更通用的“网页结构化数据提取”。一个思路是优先查页面里的 JSON-LD 数据。很多站点会在script typeapplication/ldjson里输出结构化数据解析出来本身就是干净的 JSON转换成 DataFrame 非常容易。另一个思路是配合 CSS Selector 提取重复的卡片节点比如div.product-item这种再逐字段解析。我自己后期加了一个--selector参数允许用户指定提取区域。这样即使页面再乱也能限定在某个模块里找表格误报率下降很多。5.2 值得做的几个增强功能如果你打算长期维护这个 Skill下面几个增强方向优先级比较高动态渲染降级脚本先用 requests 抓如果发现表格数量为 0自动切换到 Playwright。多页合并很多列表数据分了好几十页可以加一个--pages 5参数自动翻页并合并结果。输出预览先打印前几行数据让用户确认字段对不对再导出完整文件。增量更新适合周期性数据比如每日排名可以在脚本里对比旧文件只追加新的行。这些功能不用一次做完按实际遇到的需求往里面加就行。好的 Skill 不是一上来就大而全而是能在一个职责边界内不断长出来的。5.3 发布到社区时要注意的细节Skill 这东西自己做出来只是个半成品真正让它发挥价值的是别人能不能顺利复现。发布到社区时我一般会在包里额外放三样东西一个写完的README.md、一个真实可跑的示例 URL 和对应的输出文件。README.md里一定要写清楚“这个 Skill 能做什么、不能做什么、需要哪些依赖、调用示例是什么”。不要默认别人知道你的目录结构和使用意图。示例 URL 尽量选稳定、公开、不需要登录的页面避免给使用者添堵。还有个安全提醒Skill 本质上是可执行代码网络上找来的第三方 Skill 一定要检查脚本内容再运行。尤其是那种要你输入账号、Cookie、Token 的 Skill更需要多留个心眼。自己在发布时也不要往脚本里写任何私密信息。最后再分享一个很实际的技巧当你准备发布或者更新 Skill 时先拿一段最朴素的用户话术去测一遍比如“把这个网页里的数据做成表”看 Agent 能不能准确触发并完成任务。如果连这种最直接的调用都顺畅那这个 Skill 的可用性就基本合格了。后续再慢慢打磨边界情况比一开始憋大招要靠谱得多。
返回列表