㊗️本期内容已收录至专栏《Python爬虫实战》持续完善知识体系与项目实战建议先订阅收藏后续查阅更方便㊙️本期爬虫难度指数⭐⭐ (中级)福利一次订阅后专栏内的所有文章可永久免费看持续更新中保底1000(篇)硬核实战内容。全文目录 开篇语0️⃣ 前言Preface1️⃣ 摘要Abstract2️⃣ 背景与需求Why3️⃣ 合规与注意事项必写4️⃣ 技术选型与整体流程What/How5️⃣ 环境准备与依赖安装可复现6️⃣ 核心实现请求层Fetcher与建模Schema7️⃣ 核心实现解析层Parser- 异构数据归一化8️⃣ 数据存储与导出Storage9️⃣ 运行方式与结果展示必写 常见问题与排错强烈建议写1️⃣1️⃣ 进阶优化可选但加分1️⃣2️⃣ 总结与延伸阅读 文末✅ 专栏持续更新中建议收藏 订阅✅ 互动征集✅ 免责声明 开篇语哈喽各位小伙伴们你们好呀我是【喵手】。运营社区 C站 / 掘金 / 腾讯云 / 阿里云 / 华为云 / 51CTO欢迎大家常来逛逛一起学习一起进步我长期专注Python 爬虫工程化实战主理专栏 《Python爬虫实战》从采集策略到反爬对抗从数据清洗到分布式调度持续输出可复用的方法论与可落地案例。内容主打一个“能跑、能用、能扩展”让数据价值真正做到——抓得到、洗得净、用得上。专栏食用指南建议收藏✅ 入门基础环境搭建 / 请求与解析 / 数据落库✅ 进阶提升登录鉴权 / 动态渲染 / 反爬对抗✅ 工程实战异步并发 / 分布式调度 / 监控与容错✅ 项目落地数据治理 / 可视化分析 / 场景化应用专栏推广时间如果你想系统学爬虫而不是碎片化东拼西凑欢迎订阅专栏《Python爬虫实战》一次订阅后专栏内的所有文章可永久免费阅读持续更新中。订阅后更新会优先推送按目录学习更高效0️⃣ 前言Preface不管你是在用 Ant Design、Material UI 还是你们公司内部自研的设计系统文档总是人看的但机器比如自动化脚本、Figma 插件看不懂。今天我们要写一个高级爬虫穿梭在设计系统文档的各个子模块中把形态各异的 UI 元素全部抓取下来并强制映射到一个**统一的 Schema数据模式**中。最终你将得到一份结构完美的design_system_elements.json字典。读完这篇你能获得大一统建模思维学会使用 Python 的dataclasses或面向对象思维将非标准化数据转化为标准 Schema。️异构数据解析掌握如何分别处理网格Grid、表格Table和列表List三类最常见的 HTML 结构。⚙️前端自动化基石收获一份可以随时喂给 CLI 工具或大模型的代码用于生成代码片段或进行 UI 一致性审计。1️⃣ 摘要Abstract目标对象现代设计系统文档覆盖 Components 组件页、Icons 图标库、Tokens 变量表。核心工具requests(网络请求),BeautifulSoup4(异构 DOM 解析), Pythondataclasses(统一字段建模)。最终产出一份统一格式的英文命名文件design_system_elements.csv和对应的 JSON。核心价值实现跨页面的多态数据采集为“设计-研发”协同工具提供高质量的底层数据库。2️⃣ 背景与需求Why为什么要爬Figma 插件同步我想写个插件让设计师在 Figma 里直接搜索并拖拽最新版的组件和图标。代码生成器基石写一个 CLI 工具输入组件名自动拉取文档中的说明和示例代码。 统一字段清单Unified Schema无论它是按钮Button、主色调Primary Color还是放大镜图标Search Icon我们都强制映射为以下字段Element_Name: 元素名称如 “Button” / “colorPrimary” / “IconSearch”Element_Type: 元素类型枚举值Component|Token|IconCategory: 分类如 “Data Display” / “Color” / “Action”Description: 说明文本Preview: 预览图片 URL或 Token 的色值/代码Doc_Link: 文档溯源链接3️⃣ 合规与注意事项必写Robots.txt开源组件库的文档通常完全开放但同样要遵守爬虫的基本礼仪。静态资源保护对于预览图Preview我们只抓取 URL绝不海量下载图片去消耗对方的 CDN 流量。频率控制加入合理的休眠时间time.sleep防止触发站点的 DDoS 防护如 Cloudflare。4️⃣ 技术选型与整体流程What/How技术栈大多数现代设计文档如基于 Docusaurus 或 Nextra在首次加载时会渲染静态 HTML这正是requests bs4的强项。核心策略多态解析器Polymorphic Parsers。主程序调度不同的解析函数但所有的解析函数必须返回同一个类的实例。流程图5️⃣ 环境准备与依赖安装可复现Python 版本推荐 Python 3.9 为了完美支持 Data Classes依赖安装pipinstallrequests beautifulsoup4 pandas推荐目录结构design_system_crawler/ ├── core_schema.py # 统一数据模型定义 ├── crawler_main.py # 爬虫主逻辑与调度 └── output/ ├── design_system_elements.json └── design_system_elements.csv6️⃣ 核心实现请求层Fetcher与建模Schema在发请求之前我们先用 Python 的dataclass把我们的“大一统”数据模型建好这就是本项目的灵魂。# core_schema.pyfromdataclassesimportdataclass,asdictfromtypingimportOptionaldataclassclassDesignElement: 设计系统统一数据模型 (Unified Schema)element_name:strelement_type:str# Component, Token, Iconcategory:strdescription:strpreview:str# 图片URL 或 Token的Hex色值doc_link:strdefto_dict(self):returnasdict(self)然后我们写一个带防封禁机制的请求器# crawler_main.py (部分)importrequestsimporttimeimportrandomfrombs4importBeautifulSoupdeffetch_html(url):带礼貌休眠的静态 HTML 请求器headers{User-Agent:Design-System-Scanner/1.0 (Integration Project),}try:# 随机休眠 1~2 秒time.sleep(random.uniform(1.0,2.0))responserequests.get(url,headersheaders,timeout10)response.raise_for_status()returnresponse.textexceptExceptionase:print(f❌ 请求失败 [{url}]:{e})returnNone7️⃣ 核心实现解析层Parser- 异构数据归一化这里我们将模拟解析三个完全不同的页面结构并把它们强行“扭”成DesignElement形状# crawler_main.py (继续)fromcore_schemaimportDesignElement# ---------------------------------------------------------# 策略 1: 解析 Tokens (通常是 HTML 表格)# ---------------------------------------------------------defparse_tokens(html,base_url):soupBeautifulSoup(html,html.parser)elements[]# 假设 Token 都放在一个带有 classtoken-table 的表格里tablessoup.select(table.token-table)fortableintables:# 表格通常会有前置的 h2 或 h3 作为分类category_tagtable.find_previous_sibling([h2,h3])categorycategory_tag.get_text(stripTrue)ifcategory_tagelseGlobal Tokensforrowintable.select(tbody tr):colsrow.find_all(td)iflen(cols)3:namecols[0].get_text(stripTrue)valuecols[1].get_text(stripTrue)# 可能是 #FFFFFFdesccols[2].get_text(stripTrue)# 强转为统一 SchemaelementDesignElement(element_namename,element_typeToken,categorycategory,descriptiondesc,previewvalue,# Token 的预览直接用它的值doc_linkbase_url)elements.append(element)returnelements# ---------------------------------------------------------# 策略 2: 解析 Icons (通常是 Flex/Grid 网格排列)# ---------------------------------------------------------defparse_icons(html,base_url):soupBeautifulSoup(html,html.parser)elements[]# 假设 Icon 是存在一个 ul classicon-grid 的列表里iconssoup.select(.icon-grid li.icon-item)foriconinicons:nameicon.get(data-name)oricon.get_text(stripTrue)# 很多文档里 Icon 的预览是一个 SVG 字符串或图片的 urlimg_tagicon.find(img)preview_urlimg_tag[src]ifimg_tagelsesvg_placeholderelementDesignElement(element_namename,element_typeIcon,categorySystem Icons,descriptionfSystem icon for{name},previewpreview_url,doc_linkf{base_url}#{name})elements.append(element)returnelements# ---------------------------------------------------------# 策略 3: 解析 Components (通常是左侧导航栏 详情页结构)# ---------------------------------------------------------defparse_component_links(html,base_url):组件比较复杂通常需要先抓取目录再分别进入详情页soupBeautifulSoup(html,html.parser)links[]# 假设左侧导航菜单nav_linkssoup.select(nav.sidebar a.component-link)forainnav_links:categorya.find_previous(div,class_menu-group).get_text(stripTrue)hrefa[href]links.append({url:f{base_url.rsplit(/,1)[0]}{href},category:category})returnlinksdefparse_single_component(html,url,category):soupBeautifulSoup(html,html.parser)name_tagsoup.find(h1)namename_tag.get_text(stripTrue)ifname_tagelseUnknowndesc_tagsoup.find(p,class_component-desc)descdesc_tag.get_text(stripTrue)ifdesc_tagelseNo description# 预览通常是第一个演示案例的截图或者 iframepreview_tagsoup.find(img,class_component-preview-img)preview_urlpreview_tag[src]ifpreview_tagelseNo visual previewreturnDesignElement(element_namename,element_typeComponent,categorycategory,descriptiondesc,previewpreview_url,doc_linkurl)8️⃣ 数据存储与导出Storage由于我们已经统一了数据模型导出变得前所未有地简单。我们将分别导出结构化的 JSON 和扁平化的 CSV 文件并严格使用英文文件名。importpandasaspdimportjsonimportosdefexport_data(elements:list[DesignElement],output_diroutput):ifnotelements:print(⚠️ 没有任何数据可供导出。)returnos.makedirs(output_dir,exist_okTrue)# 1. 转换为字典列表dict_list[el.to_dict()forelinelements]# 2. 导出为 JSON (前端和配置系统最喜欢)json_pathos.path.join(output_dir,design_system_elements.json)withopen(json_path,w,encodingutf-8)asf:json.dump(dict_list,f,ensure_asciiFalse,indent2)# 3. 导出为 CSV (数据分析、审查最喜欢)csv_pathos.path.join(output_dir,design_system_elements.csv)dfpd.DataFrame(dict_list)df.to_csv(csv_path,indexFalse,encodingutf-8-sig)print(f 导出成功共{len(elements)}个元素。)print(f JSON:{json_path})print(f CSV:{csv_path})9️⃣ 运行方式与结果展示必写这是我们将所有齿轮拼接在一起的中央调度器。# crawler_main.py (入口点)defmain():print( 设计系统全息扫描仪启动...)all_elements[]# ⚠️ 这里的 URL 仅作架构演示实际请替换为您目标设计系统的真实 URLbase_domainhttps://example-design-system.com# --- 阶段 1: 扫荡 Tokens ---print(\n 阶段 1/3: 提取 Design Tokens...)token_htmlfetch_html(f{base_domain}/tokens)iftoken_html:tokensparse_tokens(token_html,f{base_domain}/tokens)all_elements.extend(tokens)print(f └── 发现{len(tokens)}个 Tokens)# --- 阶段 2: 扫荡 Icons ---print(\n 阶段 2/3: 提取 Icons库...)icon_htmlfetch_html(f{base_domain}/icons)ificon_html:iconsparse_icons(icon_html,f{base_domain}/icons)all_elements.extend(icons)print(f └── 发现{len(icons)}个 Icons)# --- 阶段 3: 扫荡 Components ---print(\n 阶段 3/3: 提取 Components...)comp_index_htmlfetch_html(f{base_domain}/components)ifcomp_index_html:comp_linksparse_component_links(comp_index_html,f{base_domain}/components)print(f └── 发现{len(comp_links)}个组件页面准备深入提取...)foridx,iteminenumerate(comp_links[:3]):# 演示仅跑前 3 个print(f ⏳ [{idx1}/{len(comp_links)}] 提取:{item[url].split(/)[-1]},end\r)comp_htmlfetch_html(item[url])ifcomp_html:compparse_single_component(comp_html,item[url],item[category])all_elements.append(comp)# 统一导出print(\n)export_data(all_elements)if__name____main__:main() 结果展示Sample CSV OutputElement_NameElement_TypeCategoryDescriptionPreviewDoc_LinkcolorPrimaryTokenBrand ColorsThe main brand color used for primary actions.#1890ffhttps://.../tokensIconSearchIconSystem IconsSystem icon for Searchhttps://.../search.svghttps://.../icons#IconSearchButtonComponentGeneralTo trigger an operation.https://.../btn.pnghttps://.../button(注如果后续需要基于此数据生成报表可视化请记得在代码中将图表的标题、坐标轴等全部使用英文以保持项目的国际化标准) 常见问题与排错强烈建议写在爬取现代化的设计系统如基于 React/Vue 的文档时你绝对会遇到以下硬骨头HTML 抓到空壳SPA 痛点现象返回状态码 200但soup里只有div idroot/div没有表格和列表。终极解法不要硬刚 HTML右键检查网页源代码寻找类似script id__NEXT_DATA__ typeapplication/json的标签。文档的数据往往以完整 JSON 的形式藏在这里。你可以用re提取出来后直接json.loads()比解析 HTML 爽 100 倍动态 CSS Class 混淆现象你写的.component-desc变成了.css-1hxg12。解法放弃类名依赖。改用相对位置定位。比如寻找h1标签后面的第一个p标签作为描述。SVG 图标拿不到 URL现象图标是内联的svg代码没有图片链接。解法在Preview字段中将整个str(svg_tag)转换为字符串存进去。现代前端工具如 Storybook是可以直接渲染内联 SVG 字符串的。1️⃣1️⃣ 进阶优化可选但加分接入 Pydantic 进行严格验证虽然我们用了dataclasses但在生产级项目中把core_schema.py升级为Pydantic Model是更好的选择。它能自动帮你做类型转换并拦截缺失必填字段的脏数据。Figma API 联动闭环拿到这份 JSON 后你可以直接调用 Figma REST API。比对 JSON 里的Token和 Figma 文件中的Local Styles是否一致如果不一致就发企微告警。这就是大厂目前在做的**“设计一致性监控”**✨1️⃣2️⃣ 总结与延伸阅读复盘时刻今天我们完成了一个极具工程美学的项目。我们面对的是散落的、非结构化的“网页 UI 垃圾”但通过设计一层Unified Schema (大一统数据模型)结合 Python 面向对象的威力成功将它们变废为宝淬炼成了设计系统的高质量基石数据如果你所在的团队正在推行 Design Token 或者设计研发一体化这份代码将成为你最强有力的自动化利器。 文末好啦以上就是本期的全部内容啦如果你在实践过程中遇到任何疑问欢迎在评论区留言交流我看到都会尽量回复咱们下期见小伙伴们在批阅的过程中如果觉得文章不错欢迎点赞、收藏、关注哦三连就是对我写作道路上最好的鼓励与支持❤️✅ 专栏持续更新中建议收藏 订阅墙裂推荐订阅专栏 《Python爬虫实战》本专栏秉承着以“入门 → 进阶 → 工程化 → 项目落地”的路线持续更新争取让每一期内容都做到✅ 讲得清楚原理✅ 跑得起来代码✅ 用得上场景✅ 扛得住工程化想系统提升的小伙伴强烈建议先订阅专栏 《Python爬虫实战》再按目录大纲顺序学习效率十倍上升✅ 互动征集想让我把【某站点/某反爬/某验证码/某分布式方案】等写成某期实战评论区留言告诉我你的需求我会优先安排实现(更新)哒~⭐️ 若喜欢我就请关注我叭更新不迷路⭐️ 若对你有用就请点赞支持一下叭给我一点点动力⭐️ 若有疑问就请评论留言告诉我叭我会补坑 更新迭代✅ 免责声明本文爬虫思路、相关技术和代码仅用于学习参考对阅读本文后的进行爬虫行为的用户本作者不承担任何法律责任。使用或者参考本项目即表示您已阅读并同意以下条款合法使用 不得将本项目用于任何违法、违规或侵犯他人权益的行为包括但不限于网络攻击、诈骗、绕过身份验证、未经授权的数据抓取等。风险自负 任何因使用本项目而产生的法律责任、技术风险或经济损失由使用者自行承担项目作者不承担任何形式的责任。禁止滥用 不得将本项目用于违法牟利、黑产活动或其他不当商业用途。使用或者参考本项目即视为同意上述条款,即 “谁使用谁负责” 。如不同意请立即停止使用并删除本项目。
Python爬虫实战:手把手教你如何设计系统元数据“大一统”建模与抓取!
㊗️本期内容已收录至专栏《Python爬虫实战》持续完善知识体系与项目实战建议先订阅收藏后续查阅更方便㊙️本期爬虫难度指数⭐⭐ (中级)福利一次订阅后专栏内的所有文章可永久免费看持续更新中保底1000(篇)硬核实战内容。全文目录 开篇语0️⃣ 前言Preface1️⃣ 摘要Abstract2️⃣ 背景与需求Why3️⃣ 合规与注意事项必写4️⃣ 技术选型与整体流程What/How5️⃣ 环境准备与依赖安装可复现6️⃣ 核心实现请求层Fetcher与建模Schema7️⃣ 核心实现解析层Parser- 异构数据归一化8️⃣ 数据存储与导出Storage9️⃣ 运行方式与结果展示必写 常见问题与排错强烈建议写1️⃣1️⃣ 进阶优化可选但加分1️⃣2️⃣ 总结与延伸阅读 文末✅ 专栏持续更新中建议收藏 订阅✅ 互动征集✅ 免责声明 开篇语哈喽各位小伙伴们你们好呀我是【喵手】。运营社区 C站 / 掘金 / 腾讯云 / 阿里云 / 华为云 / 51CTO欢迎大家常来逛逛一起学习一起进步我长期专注Python 爬虫工程化实战主理专栏 《Python爬虫实战》从采集策略到反爬对抗从数据清洗到分布式调度持续输出可复用的方法论与可落地案例。内容主打一个“能跑、能用、能扩展”让数据价值真正做到——抓得到、洗得净、用得上。专栏食用指南建议收藏✅ 入门基础环境搭建 / 请求与解析 / 数据落库✅ 进阶提升登录鉴权 / 动态渲染 / 反爬对抗✅ 工程实战异步并发 / 分布式调度 / 监控与容错✅ 项目落地数据治理 / 可视化分析 / 场景化应用专栏推广时间如果你想系统学爬虫而不是碎片化东拼西凑欢迎订阅专栏《Python爬虫实战》一次订阅后专栏内的所有文章可永久免费阅读持续更新中。订阅后更新会优先推送按目录学习更高效0️⃣ 前言Preface不管你是在用 Ant Design、Material UI 还是你们公司内部自研的设计系统文档总是人看的但机器比如自动化脚本、Figma 插件看不懂。今天我们要写一个高级爬虫穿梭在设计系统文档的各个子模块中把形态各异的 UI 元素全部抓取下来并强制映射到一个**统一的 Schema数据模式**中。最终你将得到一份结构完美的design_system_elements.json字典。读完这篇你能获得大一统建模思维学会使用 Python 的dataclasses或面向对象思维将非标准化数据转化为标准 Schema。️异构数据解析掌握如何分别处理网格Grid、表格Table和列表List三类最常见的 HTML 结构。⚙️前端自动化基石收获一份可以随时喂给 CLI 工具或大模型的代码用于生成代码片段或进行 UI 一致性审计。1️⃣ 摘要Abstract目标对象现代设计系统文档覆盖 Components 组件页、Icons 图标库、Tokens 变量表。核心工具requests(网络请求),BeautifulSoup4(异构 DOM 解析), Pythondataclasses(统一字段建模)。最终产出一份统一格式的英文命名文件design_system_elements.csv和对应的 JSON。核心价值实现跨页面的多态数据采集为“设计-研发”协同工具提供高质量的底层数据库。2️⃣ 背景与需求Why为什么要爬Figma 插件同步我想写个插件让设计师在 Figma 里直接搜索并拖拽最新版的组件和图标。代码生成器基石写一个 CLI 工具输入组件名自动拉取文档中的说明和示例代码。 统一字段清单Unified Schema无论它是按钮Button、主色调Primary Color还是放大镜图标Search Icon我们都强制映射为以下字段Element_Name: 元素名称如 “Button” / “colorPrimary” / “IconSearch”Element_Type: 元素类型枚举值Component|Token|IconCategory: 分类如 “Data Display” / “Color” / “Action”Description: 说明文本Preview: 预览图片 URL或 Token 的色值/代码Doc_Link: 文档溯源链接3️⃣ 合规与注意事项必写Robots.txt开源组件库的文档通常完全开放但同样要遵守爬虫的基本礼仪。静态资源保护对于预览图Preview我们只抓取 URL绝不海量下载图片去消耗对方的 CDN 流量。频率控制加入合理的休眠时间time.sleep防止触发站点的 DDoS 防护如 Cloudflare。4️⃣ 技术选型与整体流程What/How技术栈大多数现代设计文档如基于 Docusaurus 或 Nextra在首次加载时会渲染静态 HTML这正是requests bs4的强项。核心策略多态解析器Polymorphic Parsers。主程序调度不同的解析函数但所有的解析函数必须返回同一个类的实例。流程图5️⃣ 环境准备与依赖安装可复现Python 版本推荐 Python 3.9 为了完美支持 Data Classes依赖安装pipinstallrequests beautifulsoup4 pandas推荐目录结构design_system_crawler/ ├── core_schema.py # 统一数据模型定义 ├── crawler_main.py # 爬虫主逻辑与调度 └── output/ ├── design_system_elements.json └── design_system_elements.csv6️⃣ 核心实现请求层Fetcher与建模Schema在发请求之前我们先用 Python 的dataclass把我们的“大一统”数据模型建好这就是本项目的灵魂。# core_schema.pyfromdataclassesimportdataclass,asdictfromtypingimportOptionaldataclassclassDesignElement: 设计系统统一数据模型 (Unified Schema)element_name:strelement_type:str# Component, Token, Iconcategory:strdescription:strpreview:str# 图片URL 或 Token的Hex色值doc_link:strdefto_dict(self):returnasdict(self)然后我们写一个带防封禁机制的请求器# crawler_main.py (部分)importrequestsimporttimeimportrandomfrombs4importBeautifulSoupdeffetch_html(url):带礼貌休眠的静态 HTML 请求器headers{User-Agent:Design-System-Scanner/1.0 (Integration Project),}try:# 随机休眠 1~2 秒time.sleep(random.uniform(1.0,2.0))responserequests.get(url,headersheaders,timeout10)response.raise_for_status()returnresponse.textexceptExceptionase:print(f❌ 请求失败 [{url}]:{e})returnNone7️⃣ 核心实现解析层Parser- 异构数据归一化这里我们将模拟解析三个完全不同的页面结构并把它们强行“扭”成DesignElement形状# crawler_main.py (继续)fromcore_schemaimportDesignElement# ---------------------------------------------------------# 策略 1: 解析 Tokens (通常是 HTML 表格)# ---------------------------------------------------------defparse_tokens(html,base_url):soupBeautifulSoup(html,html.parser)elements[]# 假设 Token 都放在一个带有 classtoken-table 的表格里tablessoup.select(table.token-table)fortableintables:# 表格通常会有前置的 h2 或 h3 作为分类category_tagtable.find_previous_sibling([h2,h3])categorycategory_tag.get_text(stripTrue)ifcategory_tagelseGlobal Tokensforrowintable.select(tbody tr):colsrow.find_all(td)iflen(cols)3:namecols[0].get_text(stripTrue)valuecols[1].get_text(stripTrue)# 可能是 #FFFFFFdesccols[2].get_text(stripTrue)# 强转为统一 SchemaelementDesignElement(element_namename,element_typeToken,categorycategory,descriptiondesc,previewvalue,# Token 的预览直接用它的值doc_linkbase_url)elements.append(element)returnelements# ---------------------------------------------------------# 策略 2: 解析 Icons (通常是 Flex/Grid 网格排列)# ---------------------------------------------------------defparse_icons(html,base_url):soupBeautifulSoup(html,html.parser)elements[]# 假设 Icon 是存在一个 ul classicon-grid 的列表里iconssoup.select(.icon-grid li.icon-item)foriconinicons:nameicon.get(data-name)oricon.get_text(stripTrue)# 很多文档里 Icon 的预览是一个 SVG 字符串或图片的 urlimg_tagicon.find(img)preview_urlimg_tag[src]ifimg_tagelsesvg_placeholderelementDesignElement(element_namename,element_typeIcon,categorySystem Icons,descriptionfSystem icon for{name},previewpreview_url,doc_linkf{base_url}#{name})elements.append(element)returnelements# ---------------------------------------------------------# 策略 3: 解析 Components (通常是左侧导航栏 详情页结构)# ---------------------------------------------------------defparse_component_links(html,base_url):组件比较复杂通常需要先抓取目录再分别进入详情页soupBeautifulSoup(html,html.parser)links[]# 假设左侧导航菜单nav_linkssoup.select(nav.sidebar a.component-link)forainnav_links:categorya.find_previous(div,class_menu-group).get_text(stripTrue)hrefa[href]links.append({url:f{base_url.rsplit(/,1)[0]}{href},category:category})returnlinksdefparse_single_component(html,url,category):soupBeautifulSoup(html,html.parser)name_tagsoup.find(h1)namename_tag.get_text(stripTrue)ifname_tagelseUnknowndesc_tagsoup.find(p,class_component-desc)descdesc_tag.get_text(stripTrue)ifdesc_tagelseNo description# 预览通常是第一个演示案例的截图或者 iframepreview_tagsoup.find(img,class_component-preview-img)preview_urlpreview_tag[src]ifpreview_tagelseNo visual previewreturnDesignElement(element_namename,element_typeComponent,categorycategory,descriptiondesc,previewpreview_url,doc_linkurl)8️⃣ 数据存储与导出Storage由于我们已经统一了数据模型导出变得前所未有地简单。我们将分别导出结构化的 JSON 和扁平化的 CSV 文件并严格使用英文文件名。importpandasaspdimportjsonimportosdefexport_data(elements:list[DesignElement],output_diroutput):ifnotelements:print(⚠️ 没有任何数据可供导出。)returnos.makedirs(output_dir,exist_okTrue)# 1. 转换为字典列表dict_list[el.to_dict()forelinelements]# 2. 导出为 JSON (前端和配置系统最喜欢)json_pathos.path.join(output_dir,design_system_elements.json)withopen(json_path,w,encodingutf-8)asf:json.dump(dict_list,f,ensure_asciiFalse,indent2)# 3. 导出为 CSV (数据分析、审查最喜欢)csv_pathos.path.join(output_dir,design_system_elements.csv)dfpd.DataFrame(dict_list)df.to_csv(csv_path,indexFalse,encodingutf-8-sig)print(f 导出成功共{len(elements)}个元素。)print(f JSON:{json_path})print(f CSV:{csv_path})9️⃣ 运行方式与结果展示必写这是我们将所有齿轮拼接在一起的中央调度器。# crawler_main.py (入口点)defmain():print( 设计系统全息扫描仪启动...)all_elements[]# ⚠️ 这里的 URL 仅作架构演示实际请替换为您目标设计系统的真实 URLbase_domainhttps://example-design-system.com# --- 阶段 1: 扫荡 Tokens ---print(\n 阶段 1/3: 提取 Design Tokens...)token_htmlfetch_html(f{base_domain}/tokens)iftoken_html:tokensparse_tokens(token_html,f{base_domain}/tokens)all_elements.extend(tokens)print(f └── 发现{len(tokens)}个 Tokens)# --- 阶段 2: 扫荡 Icons ---print(\n 阶段 2/3: 提取 Icons库...)icon_htmlfetch_html(f{base_domain}/icons)ificon_html:iconsparse_icons(icon_html,f{base_domain}/icons)all_elements.extend(icons)print(f └── 发现{len(icons)}个 Icons)# --- 阶段 3: 扫荡 Components ---print(\n 阶段 3/3: 提取 Components...)comp_index_htmlfetch_html(f{base_domain}/components)ifcomp_index_html:comp_linksparse_component_links(comp_index_html,f{base_domain}/components)print(f └── 发现{len(comp_links)}个组件页面准备深入提取...)foridx,iteminenumerate(comp_links[:3]):# 演示仅跑前 3 个print(f ⏳ [{idx1}/{len(comp_links)}] 提取:{item[url].split(/)[-1]},end\r)comp_htmlfetch_html(item[url])ifcomp_html:compparse_single_component(comp_html,item[url],item[category])all_elements.append(comp)# 统一导出print(\n)export_data(all_elements)if__name____main__:main() 结果展示Sample CSV OutputElement_NameElement_TypeCategoryDescriptionPreviewDoc_LinkcolorPrimaryTokenBrand ColorsThe main brand color used for primary actions.#1890ffhttps://.../tokensIconSearchIconSystem IconsSystem icon for Searchhttps://.../search.svghttps://.../icons#IconSearchButtonComponentGeneralTo trigger an operation.https://.../btn.pnghttps://.../button(注如果后续需要基于此数据生成报表可视化请记得在代码中将图表的标题、坐标轴等全部使用英文以保持项目的国际化标准) 常见问题与排错强烈建议写在爬取现代化的设计系统如基于 React/Vue 的文档时你绝对会遇到以下硬骨头HTML 抓到空壳SPA 痛点现象返回状态码 200但soup里只有div idroot/div没有表格和列表。终极解法不要硬刚 HTML右键检查网页源代码寻找类似script id__NEXT_DATA__ typeapplication/json的标签。文档的数据往往以完整 JSON 的形式藏在这里。你可以用re提取出来后直接json.loads()比解析 HTML 爽 100 倍动态 CSS Class 混淆现象你写的.component-desc变成了.css-1hxg12。解法放弃类名依赖。改用相对位置定位。比如寻找h1标签后面的第一个p标签作为描述。SVG 图标拿不到 URL现象图标是内联的svg代码没有图片链接。解法在Preview字段中将整个str(svg_tag)转换为字符串存进去。现代前端工具如 Storybook是可以直接渲染内联 SVG 字符串的。1️⃣1️⃣ 进阶优化可选但加分接入 Pydantic 进行严格验证虽然我们用了dataclasses但在生产级项目中把core_schema.py升级为Pydantic Model是更好的选择。它能自动帮你做类型转换并拦截缺失必填字段的脏数据。Figma API 联动闭环拿到这份 JSON 后你可以直接调用 Figma REST API。比对 JSON 里的Token和 Figma 文件中的Local Styles是否一致如果不一致就发企微告警。这就是大厂目前在做的**“设计一致性监控”**✨1️⃣2️⃣ 总结与延伸阅读复盘时刻今天我们完成了一个极具工程美学的项目。我们面对的是散落的、非结构化的“网页 UI 垃圾”但通过设计一层Unified Schema (大一统数据模型)结合 Python 面向对象的威力成功将它们变废为宝淬炼成了设计系统的高质量基石数据如果你所在的团队正在推行 Design Token 或者设计研发一体化这份代码将成为你最强有力的自动化利器。 文末好啦以上就是本期的全部内容啦如果你在实践过程中遇到任何疑问欢迎在评论区留言交流我看到都会尽量回复咱们下期见小伙伴们在批阅的过程中如果觉得文章不错欢迎点赞、收藏、关注哦三连就是对我写作道路上最好的鼓励与支持❤️✅ 专栏持续更新中建议收藏 订阅墙裂推荐订阅专栏 《Python爬虫实战》本专栏秉承着以“入门 → 进阶 → 工程化 → 项目落地”的路线持续更新争取让每一期内容都做到✅ 讲得清楚原理✅ 跑得起来代码✅ 用得上场景✅ 扛得住工程化想系统提升的小伙伴强烈建议先订阅专栏 《Python爬虫实战》再按目录大纲顺序学习效率十倍上升✅ 互动征集想让我把【某站点/某反爬/某验证码/某分布式方案】等写成某期实战评论区留言告诉我你的需求我会优先安排实现(更新)哒~⭐️ 若喜欢我就请关注我叭更新不迷路⭐️ 若对你有用就请点赞支持一下叭给我一点点动力⭐️ 若有疑问就请评论留言告诉我叭我会补坑 更新迭代✅ 免责声明本文爬虫思路、相关技术和代码仅用于学习参考对阅读本文后的进行爬虫行为的用户本作者不承担任何法律责任。使用或者参考本项目即表示您已阅读并同意以下条款合法使用 不得将本项目用于任何违法、违规或侵犯他人权益的行为包括但不限于网络攻击、诈骗、绕过身份验证、未经授权的数据抓取等。风险自负 任何因使用本项目而产生的法律责任、技术风险或经济损失由使用者自行承担项目作者不承担任何形式的责任。禁止滥用 不得将本项目用于违法牟利、黑产活动或其他不当商业用途。使用或者参考本项目即视为同意上述条款,即 “谁使用谁负责” 。如不同意请立即停止使用并删除本项目。