Python爬虫高阶:用 Playwright “监听” Figma 社区热门插件数据!

㊗️本期内容已收录至专栏《Python爬虫实战》,持续完善知识体系与项目实战,建议先订阅收藏,后续查阅更方便~

㊙️本期爬虫难度指数:⭐⭐⭐

🉐福利: 一次订阅后,专栏内的所有文章可永久免费看,持续更新中,保底1000+(篇)硬核实战内容。

全文目录:

      • [🌟 开篇语](#🌟 开篇语)
      • [0️⃣ 前言(Preface)](#0️⃣ 前言(Preface))
      • [1️⃣ 摘要(Abstract)](#1️⃣ 摘要(Abstract))
      • [2️⃣ 背景与需求(Why)](#2️⃣ 背景与需求(Why))
      • [3️⃣ 合规与注意事项(必写)⚠️](#3️⃣ 合规与注意事项(必写)⚠️)
      • [4️⃣ 技术选型与整体流程(What/How)](#4️⃣ 技术选型与整体流程(What/How))
      • [5️⃣ 环境准备与依赖安装(可复现)](#5️⃣ 环境准备与依赖安装(可复现))
      • [6️⃣ 核心实现:请求层(监听器 Fetcher)](#6️⃣ 核心实现:请求层(监听器 Fetcher))
      • [7️⃣ 核心实现:解析层(Parser)](#7️⃣ 核心实现:解析层(Parser))
      • [8️⃣ 数据存储与导出(Storage)](#8️⃣ 数据存储与导出(Storage))
      • [9️⃣ 运行方式与结果展示(必写)](#9️⃣ 运行方式与结果展示(必写))
      • [🔟 常见问题与排错(Troubleshooting)](#🔟 常见问题与排错(Troubleshooting))
      • [1️⃣1️⃣ 进阶优化(可选)🚀](#1️⃣1️⃣ 进阶优化(可选)🚀)
      • [1️⃣2️⃣ 总结与延伸阅读](#1️⃣2️⃣ 总结与延伸阅读)
      • [🌟 文末](#🌟 文末)
        • [✅ 专栏持续更新中|建议收藏 + 订阅](#✅ 专栏持续更新中|建议收藏 + 订阅)
        • [✅ 互动征集](#✅ 互动征集)
        • [✅ 免责声明](#✅ 免责声明)

🌟 开篇语

哈喽,各位小伙伴们你们好呀~我是【喵手】。

运营社区: C站 / 掘金 / 腾讯云 / 阿里云 / 华为云 / 51CTO

欢迎大家常来逛逛,一起学习,一起进步~🌟

我长期专注 Python 爬虫工程化实战 ,主理专栏 《Python爬虫实战》:从采集策略反爬对抗 ,从数据清洗分布式调度 ,持续输出可复用的方法论与可落地案例。内容主打一个"能跑、能用、能扩展 ",让数据价值真正做到------抓得到、洗得净、用得上

📌 专栏食用指南(建议收藏)

  • ✅ 入门基础:环境搭建 / 请求与解析 / 数据落库
  • ✅ 进阶提升:登录鉴权 / 动态渲染 / 反爬对抗
  • ✅ 工程实战:异步并发 / 分布式调度 / 监控与容错
  • ✅ 项目落地:数据治理 / 可视化分析 / 场景化应用

📣 专栏推广时间 :如果你想系统学爬虫,而不是碎片化东拼西凑,欢迎订阅专栏👉《Python爬虫实战》👈,一次订阅后,专栏内的所有文章可永久免费阅读,持续更新中。

💕订阅后更新会优先推送,按目录学习更高效💯~

0️⃣ 前言(Preface)

👋 大家好!今天我们要攻克的是 Figma Community

如果你尝试过右键查看 Figma 社区的源代码,你会发现里面全是复杂的 React 组件和随机 Class 名。传统的 HTML 解析在这里寸步难行。

今天我们将使用 Playwright 的网络拦截功能 。我们不解析网页,而是让 Playwright 启动浏览器,像真实用户一样访问,然后在后台静默监听网页发起的数据请求(XHR/Fetch),直接截获原始的 JSON 数据包。这是爬虫界"四两拨千斤"的顶级技巧!

读完这篇你将获得:

  1. 网络拦截技能 :学会使用 page.on('response', ...) 监听并捕获后台数据。
  2. 混合开发模式:结合浏览器的自动化操作与 API 的数据纯度。
  3. 清洗复杂的嵌套数据:从原始 JSON 中提取插件元数据。

1️⃣ 摘要(Abstract)

本文介绍了一种基于 Playwright 的网络监听爬虫方案。针对 Figma 社区高度动态化的特点,我们放弃 DOM 解析,转而通过拦截 api/community_search 等核心接口的响应,直接获取结构化的 JSON 数据。这种方法既避开了复杂的反爬验证(由浏览器自动处理),又保证了数据的完整性和准确性。

2️⃣ 背景与需求(Why)

🔍 为什么要爬:

Figma 插件生态爆发式增长。开发者想知道:"现在做什么类型的插件最容易火?"、"同类插件的下载量天花板是多少?"。我们需要一份精确的榜单数据来辅助决策。

🎯 目标站点: https://www.figma.com/community/plugins

📋 目标字段清单:

  • Plugin Name (插件名)
  • Author/Publisher (作者/发布者)
  • Install Count (安装量 - 核心指标)
  • Like/Love Count (点赞/评分)
  • Description (简介)

3️⃣ 合规与注意事项(必写)⚠️

  1. 数据边界 :我们只采集公开的社区索引数据,严禁尝试爬取用户的私有设计文件(Figma Files),这不仅违规而且技术上很难实现(需要鉴权)。
  2. 请求频率:虽然我们是监听浏览器请求,但滚屏加载过快依然会触发 Figma 的限流(429)。保持"像人一样"的操作节奏。
  3. 版权声明:Figma 社区内容归原作者所有,采集的数据仅供分析,不可用于复制抄袭。

4️⃣ 技术选型与整体流程(What/How)

🛠 技术选型:

  • Request/BS4:❌ 页面是空的,且 API 有复杂的签名(Signature),逆向难度极大。
  • Playwright (DOM 模式):⚠️ 可以,但提取数字(如 "1.5k")不精确,且 DOM 结构常变。
  • Playwright (Network 模式) :✅ 完美。浏览器帮我们搞定签名和 Cookie,我们只负责"捡"回来的数据。

⚙️ 流程图:
[ 启动浏览器 ] ➡️ [ 注册 Response 监听器 ] ➡️ [ 打开 Figma 社区 ] ➡️ [ 模拟滚动 ] ➡️ [ 触发 API 响应 ] ➡️ [ 拦截并保存 JSON ] ➡️ [ 清洗入库 ]

5️⃣ 环境准备与依赖安装(可复现)

💻 Python 版本:3.8+

📦 依赖安装

bash 复制代码
pip install playwright pandas
playwright install chromium

📂 项目结构

text 复制代码
figma_interceptor/
├── main.py
└── data/
    └── figma_plugins.csv

6️⃣ 核心实现:请求层(监听器 Fetcher)

这是本篇的核心!我们需要编写一个回调函数,当浏览器接收到特定 URL 的响应时,自动把数据存下来。

python 复制代码
import asyncio
from playwright.async_api import async_playwright
import json
import random

# 用于在内存中暂存拦截到的数据
captured_plugins = []

async def handle_response(response):
    """
    这是我们的'窃听器'函数。
    当浏览器收到任何响应时,都会经过这里。
    """
    # 1. 过滤 URL:我们只关心包含 'search' 或 'feed' 的接口
    # 经过 F12 观察,Figma 社区主要接口类似:https://www.figma.com/api/community_search/...
    if "api/community_search" in response.url and response.status == 200:
        print(f"🕵️‍♂️ Intercepted API: {response.url[:60]}...")
        
        try:
            # 2. 获取 JSON 数据
            data = await response.json()
            
            # 3. 解析数据结构 (Figma 的结构非常深)
            # 通常在 meta -> resources 或者 result -> meta 里面
            # 这里需要根据实际抓包结果调整路径,以下是基于经验的通用路径
            resources = data.get('meta', {}).get('resources', [])
            
            for resource in resources:
                # 只要插件 (resource_type == 'plugin')
                if resource.get('resource_type') == 'plugin':
                    plugin_info = {
                        'id': resource.get('id'),
                        'name': resource.get('name'),
                        'author': resource.get('publisher', {}).get('name', 'Unknown'),
                        'install_count': resource.get('install_count', 0),
                        'like_count': resource.get('like_count', 0),
                        'created_at': resource.get('created_at')
                    }
                    captured_plugins.append(plugin_info)
                    
            print(f"   ✅ Captured {len(resources)} items from this packet.")
            
        except Exception as e:
            # 忽略非 JSON 响应或解析错误
            pass

async def run_scraper():
    async with async_playwright() as p:
        browser = await p.chromium.launch(headless=False) # 有头模式,方便看效果
        context = await browser.new_context()
        page = await context.new_page()

        # 🔥 核心:注册监听器
        # 只要发生网络响应,就调用 handle_response
        page.on("response", handle_response)

        print("🌍 Navigating to Figma Community...")
        # 访问热门插件页
        await page.goto("https://www.figma.com/community/plugins?sort_by=popular", timeout=60000)
        
        # 等待首屏加载
        await page.wait_for_timeout(5000)

        # --- 模拟滚动加载 (Pagination) ---
        # Figma 是无限滚动,我们滚它个 5-10 次
        for i in range(5):
            print(f"📜 Scrolling page... ({i+1}/5)")
            await page.keyboard.press("End")
            
            # 随机等待,让 API 有时间响应
            await page.wait_for_timeout(random.randint(3000, 5000))
            
        print("🏁 Scraping finished.")
        await browser.close()

7️⃣ 核心实现:解析层(Parser)

在上面的代码中,解析逻辑已经融合在 handle_response 里了。
为什么不分开写?

因为在拦截模式下,数据是流式进来的,拿到响应的瞬间解析是最简单的。

不过,我们可以补一个数据清洗函数 ,把内存里的 captured_plugins 整理成最终格式。

python 复制代码
import pandas as pd

def process_data(raw_data):
    """
    清洗、去重、格式化
    """
    if not raw_data:
        print("⚠️ No data captured.")
        return pd.DataFrame()

    df = pd.DataFrame(raw_data)
    
    # 1. 去重 (因为滚动时API可能会返回重复数据)
    df.drop_duplicates(subset=['id'], inplace=True)
    
    # 2. 格式化数字 (Figma API 返回的是整数,不需要去 'k',非常爽!)
    # 我们可以加一个 'Formatted Installs' 方便阅读
    df['install_fmt'] = df['install_count'].apply(lambda x: f"{x/1000:.1f}k" if x > 1000 else str(x))
    
    # 3. 排序
    df.sort_values(by='install_count', ascending=False, inplace=True)
    
    return df

8️⃣ 数据存储与导出(Storage)

python 复制代码
import os

def save_to_csv(df, filename="figma_plugins.csv"):
    if df.empty:
        return
        
    os.makedirs('data', exist_ok=True)
    filepath = os.path.join('data', filename)
    
    df.to_csv(filepath, index=False, encoding='utf-8-sig')
    print(f"💾 Saved {len(df)} plugins to {filepath}")
    
    # 打印前 5 名
    print("\n🏆 Top 5 Popular Figma Plugins:")
    print(df[['name', 'author', 'install_count']].head(5).to_markdown(index=False))

9️⃣ 运行方式与结果展示(必写)

启动脚本 (main.py):

python 复制代码
# 整合入口
if __name__ == "__main__":
    # 1. 运行爬虫
    asyncio.run(run_scraper())
    
    # 2. 处理数据
    print(f"📊 Total items intercepted: {len(captured_plugins)}")
    df_clean = process_data(captured_plugins)
    
    # 3. 保存
    save_to_csv(df_clean)

示例运行结果 (Console):

text 复制代码
🌍 Navigating to Figma Community...
🕵️‍♂️ Intercepted API: https://www.figma.com/api/community_search/search_results...
   ✅ Captured 48 items from this packet.
📜 Scrolling page... (1/5)
🕵️‍♂️ Intercepted API: https://www.figma.com/api/community_search/search_results...
   ✅ Captured 24 items from this packet.
...
🏁 Scraping finished.
📊 Total items intercepted: 144
💾 Saved 120 plugins to data/figma_plugins.csv

🏆 Top 5 Popular Figma Plugins:
| name | author | install_count |
| :--- | :--- | :--- |
| Unsplash | Unsplash | 1500000 |
| Iconify | Iconify | 1200000 |
| Content Reel | Microsoft | 980000 |
| Lorem Ipsum | David | 850000 |
| Remove BG | Aaron | 720000 |

🔟 常见问题与排错(Troubleshooting)

  1. 没有拦截到数据 (API URL 变了)

    • 原因 :Figma 更新了 API 路径,比如从 community_search 变成了 search_v2
    • 解决 :打开浏览器 F12 -> Network -> XHR,手动滚动一下,看那个最大的 JSON 响应是谁,把它的 URL 关键词填进 handle_responseif 判断里。
  2. 数据字段报错 (KeyError)

    • 原因:JSON 结构嵌套很深,容易取空。
    • 解决 :一定要用 .get() 方法,比如 data.get('meta', {}).get('resources', []),千万别直接用 data['meta']['resources'],否则一个空包就让程序挂了。
  3. 浏览器卡死

    • 原因:Figma 页面非常吃内存(Canvas 渲染)。
    • 解决 :在 launch 时添加参数 args=['--disable-gl-drawing-for-tests'] 可以禁用一部分图形渲染,减轻负担。

1️⃣1️⃣ 进阶优化(可选)🚀

  • 全量搜索

    • 通过 page.goto(".../search?query=icon") 配合关键词字典,可以按类别把所有插件都扫一遍。
  • 数据库入库

    • 数据量如果很大,建议用 SQLite 替代 CSV。Playwright 拦截的数据直接 INSERT OR IGNORE 进数据库,实现实时持久化,防止程序跑了一半崩溃数据全丢。
  • 无头模式 (Headless)

    • 调试完成后,把 headless=False 改为 True,部署到服务器上每天定时跑一次,监控"新晋黑马插件"。

1️⃣2️⃣ 总结与延伸阅读

🎉 复盘:

今天我们展示了爬虫技术的"第三条路":Playwright 网络拦截

相比于笨拙的 DOM 解析和极难的 API 逆向,这种方法是目前应对现代 SPA(单页应用)性价比最高的方案。我们利用浏览器作为"代理人",轻松拿到了 Figma 官方最纯净的源数据。

👀 下一步:

这项技术在爬取 Twitter/XInstagramAirbnb 等无限滚动且高度动态的网站时同样威力无穷。只要你能看到数据在加载,你就能用这个方法拦截下来!

去试试拦截你喜欢的网站吧,记得看 F12 的 Network 标签页,那里藏着金矿!💰

🌟 文末

好啦~以上就是本期的全部内容啦!如果你在实践过程中遇到任何疑问,欢迎在评论区留言交流,我看到都会尽量回复~咱们下期见!

小伙伴们在批阅的过程中,如果觉得文章不错,欢迎点赞、收藏、关注哦~
三连就是对我写作道路上最好的鼓励与支持! ❤️🔥

✅ 专栏持续更新中|建议收藏 + 订阅

墙裂推荐订阅专栏 👉 《Python爬虫实战》,本专栏秉承着以"入门 → 进阶 → 工程化 → 项目落地"的路线持续更新,争取让每一期内容都做到:

✅ 讲得清楚(原理)|✅ 跑得起来(代码)|✅ 用得上(场景)|✅ 扛得住(工程化)

📣 想系统提升的小伙伴 :强烈建议先订阅专栏 《Python爬虫实战》,再按目录大纲顺序学习,效率十倍上升~

✅ 互动征集

想让我把【某站点/某反爬/某验证码/某分布式方案】等写成某期实战?

评论区留言告诉我你的需求,我会优先安排实现(更新)哒~


⭐️ 若喜欢我,就请关注我叭~(更新不迷路)

⭐️ 若对你有用,就请点赞支持一下叭~(给我一点点动力)

⭐️ 若有疑问,就请评论留言告诉我叭~(我会补坑 & 更新迭代)


✅ 免责声明

本文爬虫思路、相关技术和代码仅用于学习参考,对阅读本文后的进行爬虫行为的用户本作者不承担任何法律责任。

使用或者参考本项目即表示您已阅读并同意以下条款:

  • 合法使用: 不得将本项目用于任何违法、违规或侵犯他人权益的行为,包括但不限于网络攻击、诈骗、绕过身份验证、未经授权的数据抓取等。
  • 风险自负: 任何因使用本项目而产生的法律责任、技术风险或经济损失,由使用者自行承担,项目作者不承担任何形式的责任。
  • 禁止滥用: 不得将本项目用于违法牟利、黑产活动或其他不当商业用途。
  • 使用或者参考本项目即视为同意上述条款,即 "谁使用,谁负责" 。如不同意,请立即停止使用并删除本项目。!!!
相关推荐
MoRanzhi12032 小时前
Pillow 图像滤波、卷积与边缘处理
图像处理·python·计算机视觉·pillow·卷积·边缘检测·图像滤波
怪侠_岭南一只猿2 小时前
爬虫学习阶段三:动态网页爬取(完整学习文档)
爬虫·python·学习
南 阳2 小时前
Python从入门到精通day48
开发语言·python
虎大猫猫2 小时前
JupyterLab的安装与使用完全指南
ide·python·jupyter
web3.08889992 小时前
如何确保1688商品数据API接口的安全性
python
<-->2 小时前
SGLang 相比 vLLM 的主要优势
人工智能·pytorch·python·transformer
夫唯不争,故无尤也2 小时前
Agent 开发者如何快速上手 SQL:从表设计到 Python 交互的一篇实战入门
python·sql·交互
小张的博客之旅2 小时前
2026第十届“楚慧杯”湖北省网络与数据安全实践能力竞赛 (全Writeup)
python·网络安全·openclaw