Python 爬虫实战:利用 Playwright 攻克 Canva 动态设计模板库

㊗️本期内容已收录至专栏《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)

👋 大家好!今天我们要挑战的是设计界的霸主------Canva。

很多设计师想知道:"现在最火的 Instagram 帖子模板是什么风格?"、"哪种配色方案用的最多?"。

由于 Canva 的网页全是动态生成的(React),且 Class 名全是随机乱码(如 _1QoxDw),传统的爬虫手段在这里统统失效。

今天,我们将使用 Playwright 模拟真实浏览器,实现**"滚动翻页"**,抓取模板元数据,并统计出当下的设计流行趋势。

读完这篇你将获得:

  1. Playwright 实战能力:学会处理无限滚动(Infinite Scroll)页面。
  2. 抗混淆技巧:在 CSS Class 随机变动的情况下,如何用 XPath/CSS 选择器精准定位元素。
  3. 视觉化数据:从单纯的代码到可视化的热门关键词分析。

1️⃣ 摘要(Abstract)

本文针对 Canva 模板库的高动态特性,采用 Python 的 playwright 库驱动 Chromium 浏览器进行自动化采集。通过模拟鼠标滚动触发数据加载,抓取模板的标题、链接及付费状态(Pro/Free)。最终,我们将清洗数据并统计高频出现的关键词,洞察当前的设计热门标签。

2️⃣ 背景与需求(Why)

🔍 为什么要爬:

设计趋势瞬息万变。通过分析 Canva 首页推荐或特定分类下的"热门"模板,我们可以量化设计趋势(例如:现在是"极简主义"流行还是"复古风"流行?)。

🎯 目标站点: https://www.canva.com/templates/ (或特定的搜索结果页)

📋 目标字段清单:

  • Template Name (模板名称/标题)
  • Creator (创作者 - 若可见)
  • Is Pro (是否为付费 Pro 版)
  • Keywords (从标题中提取的推荐标签)
  • Rank (在热门列表中的位置,作为"流行度"的替代指标)

(注:Canva 前端界面通常隐藏了具体的"使用次数",我们将用"热门排序下的位置"来代表流行度。)

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

Canva 的反爬非常严格,请务必遵守:

  1. 频率控制极度重要! 不要开多线程并发!Playwright 模拟的是真实用户,请保持单线程并加上随机等待。
  2. Cloudflare 验证 :Canva 前置了 Cloudflare 盾。如果脚本启动时遇到验证码,请在"有头模式"(headless=False)下手动点一下。
  3. 数据隐私:我们只采集公开的模板元数据,不涉及任何用户个人设计草稿。

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

🛠 技术选型:

  • Requests:❌ 无法处理,页面全是 JS。
  • Selenium:⚠️ 可以,但速度慢,驱动配置麻烦。
  • Playwright:✅ 完美。原生支持异步,无需手动下载 Driver,且对现代 SPA 网页支持极好。

⚙️ 流程图:
[ 启动浏览器 ] ➡️ [ 打开 Canva 模板页 ] ➡️ [ 模拟鼠标滚动(加载更多) ] ➡️ [ 提取 DOM 元素 ] ➡️ [ 解析清洗 ] ➡️ [ 统计关键词 ]

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

💻 Python 版本:3.8+

📦 依赖安装

我们需要安装 playwright 库以及 pandas。

bash 复制代码
pip install playwright pandas
# 安装完成后,必须运行下面这就话来安装浏览器内核
playwright install chromium

📂 项目结构

text 复制代码
canva_scraper/
├── main.py
└── data/
    └── canva_trends.csv

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

我们将编写一个异步函数,启动浏览器并加载页面。为了防止被识别为机器人,我们需要设置一些特殊的 context 参数。

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

async def fetch_templates(keyword="instagram-post"):
    """
    使用 Playwright 启动浏览器并抓取
    """
    async with async_playwright() as p:
        # ⚠️ 关键点:headless=False 让你可以看到浏览器运行,
        # 如果遇到 Cloudflare 验证码,你可以手动点一下!
        browser = await p.chromium.launch(headless=False, slow_mo=500)
        
        # 伪装 User-Agent
        context = await browser.new_context(
            user_agent='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
            viewport={'width': 1920, 'height': 1080}
        )
        
        page = await context.new_page()
        
        # 访问 Canva 模板搜索页(按热门排序)
        target_url = f"https://www.canva.com/templates/?query={keyword}"
        print(f"🌍 Navigating to: {target_url}")
        
        try:
            await page.goto(target_url, timeout=60000, wait_until="networkidle")
        except Exception as e:
            print(f"⚠️ Page load timeout (common for heavy sites), continuing anyway... Error: {e}")

        # --- 模拟滚动加载 (Infinite Scroll) ---
        # 我们要抓取热门的前 100 个,大概需要滚动 3-5 次
        for i in range(5):
            print(f"📜 Scrolling page... ({i+1}/5)")
            await page.keyboard.press("End") # 模拟按下 End 键到底部
            await asyncio.sleep(random.uniform(2, 4)) # 等待新内容加载
            
        # 返回页面内容供解析
        content = await page.content()
        
        # 在这里直接解析 DOM 元素,比把 HTML 传出去解析更稳,因为元素依然在内存中
        # 我们将在下一步实现具体的提取逻辑
        
        return page, browser # 返回 page 对象以便后续操作

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

难点 :Canva 的 Class 名字全是随机的(例如 class="A82_za")。我们不能依赖 class。
策略 :依赖属性选择器层级关系 。通常模板是一个链接 a 标签,里面包含图片和标题。

python 复制代码
async def parse_elements(page):
    """
    从当前页面提取模板信息
    """
    print("🕵️ Extracting template data...")
    
    # Canva 的模板通常包裹在 a 标签里,且 href 包含 '/templates/'
    # 我们使用 CSS 选择器定位所有包含 templates 路径的链接
    # 注意:这需要根据 Canva 当时的实际 DOM 结构微调,以下是通用策略
    
    # 查找所有可能是模板卡片的元素
    # 这里的选择器逻辑:找所有 href 里带有 '/templates/' 的 <a> 标签
    cards = await page.query_selector_all("a[href*='/templates/']")
    
    results = []
    seen_urls = set()

    for card in cards:
        try:
            # 1. 提取链接
            href = await card.get_attribute("href")
            full_url = f"https://www.canva.com{href}"
            
            # 去重:Canva 页面上可能有重复的推荐
            if full_url in seen_urls:
                continue
            seen_urls.add(full_url)

            # 2. 提取文本内容(包含标题)
            # Canva 的标题通常在 aria-label 或者内部的某个 div 文本里
            # 简单的做法是获取整个卡片的文本,然后清洗
            text_content = await card.inner_text()
            lines = text_content.split('\n')
            
            # 简单启发式清洗:通常最长的且不是 'Pro'/'Free' 的就是标题
            title = "Unknown"
            is_pro = False
            
            for line in lines:
                if "Pro" in line or "Paid" in line:
                    is_pro = True
                elif len(line) > 5 and title == "Unknown":
                    title = line.strip()

            # 3. 如果标题还是拿不到,尝试拿 aria-label
            if title == "Unknown":
                aria = await card.get_attribute("aria-label")
                if aria:
                    title = aria

            results.append({
                'Template Name': title,
                'Is Pro': is_pro,
                'URL': full_url,
                'Raw Tags': title # 我们把标题作为原始标签来源
            })
            
        except Exception as e:
            continue
            
    print(f"✅ Extracted {len(results)} templates.")
    return results

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

我们将数据存为 CSV,并做一个简单的"热门词频统计",把标题里的词拆开算作标签。

python 复制代码
import pandas as pd
import os
from collections import Counter
import re

def save_and_analyze(data_list):
    if not data_list:
        print("❌ No data to save.")
        return

    df = pd.DataFrame(data_list)
    
    # 1. 保存原始数据
    os.makedirs('data', exist_ok=True)
    df.to_csv('data/canva_trends.csv', index=False, encoding='utf-8-sig')
    print("💾 Raw data saved to data/canva_trends.csv")
    
    # 2. 热门标签分析 (简单 NLP)
    # 把所有标题拼起来,转小写,正则提取单词
    all_text = " ".join(df['Template Name'].astype(str).tolist()).lower()
    # 过滤掉无意义词汇
    stopwords = {'template', 'design', 'instagram', 'post', 'free', 'unknown', 'the', 'and', 'for', 'with'}
    words = re.findall(r'\b\w+\b', all_text)
    
    filtered_words = [w for w in words if w not in stopwords and len(w) > 2]
    
    # 统计前 10 个热词
    top_keywords = Counter(filtered_words).most_common(10)
    
    print("\n🔥 === HOT DESIGN TRENDS (Top Keywords) ===")
    for word, count in top_keywords:
        print(f"   #{word}: {count} occurrences")
        
    # 保存热词统计
    pd.DataFrame(top_keywords, columns=['Keyword', 'Count']).to_csv('data/trend_analysis.csv', index=False)

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

启动脚本 (main.py):

python 复制代码
# 整合上面的代码
async def main():
    # 假设我们想看 "Instagram Story" 的设计趋势
    page, browser = await fetch_templates(keyword="instagram-story")
    
    if page:
        data = await parse_elements(page)
        save_and_analyze(data)
        
        await browser.close()

if __name__ == "__main__":
    asyncio.run(main())

示例运行结果 (Console):

text 复制代码
🌍 Navigating to: https://www.canva.com/templates/?query=instagram-story
📜 Scrolling page... (1/5)
📜 Scrolling page... (2/5)
...
✅ Extracted 120 templates.
💾 Raw data saved to data/canva_trends.csv

🔥 === HOT DESIGN TRENDS (Top Keywords) ===
   #minimalist: 45 occurrences
   #beige: 32 occurrences
   #aesthetic: 28 occurrences
   #business: 15 occurrences
   #fashion: 12 occurrences

📊 结果解读:

从输出可以看到,当前 Instagram Story 最火的设计风格是 Minimalist (极简)Beige (米色调)。如果你是设计师,现在做米色极简风的模板肯定好卖!这就是数据的价值!💰

🔟 常见问题与排错(Troubleshooting)

  1. 卡在 Cloudflare 验证页面

    • 现象:浏览器打开后一直转圈,或者出现"Verify you are human"。
    • 解决 :因为我们设置了 headless=False,请人工介入点一下验证框。或者尝试使用指纹浏览器插件(如 playwright_stealth)。
  2. 找不到元素 (Selector Error)

    • 现象Extracted 0 templates
    • 原因:Canva 改版了 HTML 结构。
    • 解决 :打开浏览器开发者工具 (F12),查看模板链接的特征。如果 href 规则变了,需要更新 parse_elements 里的选择器。
  3. Playwright 安装失败

    • 解决 :确保运行了 playwright install chromium

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

  • 图片色系分析

    • Playwright 可以对元素截图 element.screenshot()。你可以把每个模板截图下来,用 OpenCVPillow 分析图片的主色调(Dominant Color),做更深度的"色彩趋势报告"。
  • 自动化登录

    • 如果需要抓取"我的收藏"或特定付费内容,可以编写 Playwright 脚本自动填充账号密码登录(注意:这会增加封号风险)。
  • 无头模式优化

    • 调试通了之后,可以尝试把 headless=False 改为 True,并配合 playwright-stealth 库来尝试绕过检测,实现后台静默运行。

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

🎉 复盘:

今天我们完成了一个高难度的爬虫任务。面对 Canva 这种全动态、随机类名、强风控 的站点,传统的 requests 束手无策,但 Playwright 像一位全能特工,轻松模拟人类操作拿到了数据。

我们不仅抓取了数据,还通过简单的词频统计 ,把枯燥的列表变成了有价值的设计趋势报告

👀 下一步:

  • 试试用 Playwright 抓取 Pinterest?它和 Canva 一样也是瀑布流布局,非常适合练习。
  • 研究一下 Scrapy-Playwright 插件,将 Scrapy 的并发优势和 Playwright 的渲染能力结合起来。

保持对技术的热爱,你就是数据世界的探索者!🌟

🌟 文末

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

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

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

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

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

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

✅ 互动征集

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

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


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

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

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


✅ 免责声明

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

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

  • 合法使用: 不得将本项目用于任何违法、违规或侵犯他人权益的行为,包括但不限于网络攻击、诈骗、绕过身份验证、未经授权的数据抓取等。
  • 风险自负: 任何因使用本项目而产生的法律责任、技术风险或经济损失,由使用者自行承担,项目作者不承担任何形式的责任。
  • 禁止滥用: 不得将本项目用于违法牟利、黑产活动或其他不当商业用途。
  • 使用或者参考本项目即视为同意上述条款,即 "谁使用,谁负责" 。如不同意,请立即停止使用并删除本项目。!!!
相关推荐
进击的小头2 小时前
第4篇:二阶系统的时域响应分析
python·算法
赵谨言2 小时前
基于YOLOv5的火灾检测研究是当前计算机视觉和消防安全领域的重要研究方向
大数据·开发语言·经验分享·python
ZhengEnCi2 小时前
P1C-Python变量和数据类型详解
python
chushiyunen2 小时前
django venv虚拟环境
后端·python·django
GDAL2 小时前
qpip 教程:把 Python 包安装、项目脚本和虚拟环境统一到一个命令里
python·pip·venv
弈风千秋万古愁2 小时前
常见配置文件-AI辅助
开发语言·python
花间相见2 小时前
【JAVA基础01】——类和对象
java·开发语言·python
小鸡吃米…2 小时前
自然语言处理 ——Python 实现
人工智能·python·自然语言处理
Alex艾力的IT数字空间2 小时前
OCR 原理:从像素到文本的智能转换
数据结构·人工智能·python·神经网络·算法·cnn·ocr