news 2026/2/23 3:42:49

Python 爬虫实战:Pyppeteer 无头浏览器爬虫开发

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python 爬虫实战:Pyppeteer 无头浏览器爬虫开发

前言

无头浏览器是动态页面爬虫开发的核心工具,相较于传统 Selenium,基于 Chrome DevTools Protocol(CDP)的无头浏览器具备更轻量、更高效的特性。Pyppeteer 作为 Google Puppeteer 的 Python 实现,无需额外配置浏览器驱动,原生支持异步编程,在处理 JS 渲染的动态页面时优势显著。本文将从 Pyppeteer 的核心原理出发,系统讲解其环境搭建、核心 API 使用,并通过实战案例实现动态页面数据爬取,同时对比 Pyppeteer 与 Playwright、Selenium 的差异,帮助开发者掌握这一轻量级无头浏览器爬虫开发技术。

摘要

本文聚焦 Pyppeteer 无头浏览器在爬虫开发中的应用,深入解析其基于 CDP 协议的工作机制,详细讲解环境搭建、异步编程模型、动态元素定位与提取、网络请求拦截等核心技术。通过实战案例(爬取知乎热榜动态渲染的热榜数据),完整展示从浏览器启动、页面加载、数据提取到文件存储的全流程,并剖析 Pyppeteer 的性能优化与防反爬策略。本文提供的代码可直接落地,帮助开发者高效实现动态页面爬虫开发,同时对比主流无头浏览器工具的选型思路。

一、Pyppeteer 核心概念与优势

1.1 核心概念

  • Chrome DevTools Protocol(CDP):Pyppeteer 的底层通信协议,通过该协议可直接与 Chrome/Chromium 浏览器交互,实现页面控制、元素操作、网络监控等功能,无需依赖 WebDriver。
  • 异步编程:Pyppeteer 基于 asyncio 实现异步操作,相比同步爬虫,可大幅提升并发爬取效率。
  • 无头模式:默认以无头模式运行浏览器,无界面化执行,降低资源占用,适合服务器部署。

1.2 Pyppeteer vs Playwright vs Selenium 对比

特性PyppeteerPlaywrightSelenium
底层协议CDPCDP + 自定义协议WebDriver
浏览器支持仅 Chrome/ChromiumChrome、Firefox、Safari、Edge多浏览器(需对应驱动)
异步支持原生 asyncio原生 async/await需第三方库适配
安装复杂度自动下载 Chromium(首次运行)手动执行 install 命令下载驱动手动下载对应浏览器驱动
资源占用极低
学习成本低(API 简洁)中(功能丰富,API 较多)低(文档成熟)
社区生态中等(Python 专属)高(微软维护,多语言支持)极高(老牌工具,文档丰富)
适用场景轻量级动态页面爬取复杂多浏览器爬取 / 测试传统自动化测试 / 爬虫

二、Pyppeteer 环境搭建

2.1 安装 Pyppeteer

Pyppeteer 支持 Python 3.6 + 版本,执行以下命令完成安装:

bash

运行

# 安装Pyppeteer pip install pyppeteer # 手动下载Chromium(可选,首次运行会自动下载) pyppeteer-install

注意:首次运行 Pyppeteer 时,会自动下载对应系统的 Chromium 浏览器(约 100MB),若下载缓慢,可配置国内镜像:

bash

运行

设置镜像源

export PYPPETEER_DOWNLOAD_HOST=https://npm.taobao.org/mirrorspyppeteer-install

已生成代码

2.2 验证安装

创建test_pyppeteer.py文件,执行以下代码验证环境:

python

运行

import asyncio from pyppeteer import launch async def test_pyppeteer(): # 启动浏览器(无头模式) browser = await launch(headless=True) # 创建新页面 page = await browser.newPage() # 访问百度首页 await page.goto('https://www.baidu.com') # 获取页面标题 title = await page.title() print(f"页面标题:{title}") # 关闭浏览器 await browser.close() if __name__ == '__main__': asyncio.get_event_loop().run_until_complete(test_pyppeteer())
输出结果:

plaintext

页面标题:百度一下,你就知道
原理说明:
  • launch():启动 Chromium 浏览器,返回浏览器实例,headless=True为默认值(无头模式)。
  • newPage():创建新的页面实例,对应浏览器的一个标签页。
  • page.goto():导航至指定 URL,Pyppeteer 会自动等待页面加载完成(默认等待 DOMContentLoaded)。
  • asyncio.get_event_loop():创建异步事件循环,执行异步函数,这是 Pyppeteer 异步编程的核心。

三、Pyppeteer 核心 API 详解

3.1 浏览器与页面操作

API 方法功能说明
browser = await launch()启动浏览器实例,可配置 headless、args 等参数
page = await browser.newPage()创建新页面
await page.goto(url, options)导航至 URL,options 可设置 timeout、waitUntil 等
await page.setViewport({'width': 1920, 'height': 1080})设置页面视口大小
await page.close()关闭页面
await browser.close()关闭浏览器

3.2 元素定位与操作

Pyppeteer 支持多种元素定位方式,核心方法为page.querySelector()/page.querySelectorAll(),常用操作如下:

python

运行

async def element_operation(page): # 1. CSS选择器定位元素 search_box = await page.querySelector('#kw') # 百度搜索框 # 输入文本 await page.type('#kw', 'Pyppeteer 爬虫', {'delay': 100}) # delay模拟人工输入速度 # 2. 点击元素 search_btn = await page.querySelector('#su') await search_btn.click() # 3. XPath定位 result_title = await page.xpath('//h3[@class="t"]/a') # 遍历元素 for title in result_title[:3]: text = await page.evaluate('(element) => element.textContent', title) print(f"搜索结果:{text}") # 4. 等待元素加载 await page.waitForSelector('.result-op', {'timeout': 5000}) # 超时5秒

3.3 数据提取

python

运行

async def extract_data(page): # 获取元素文本 text = await page.evaluate('() => document.querySelector(".title").textContent') # 获取元素属性 href = await page.evaluate('() => document.querySelector("a").href') # 获取页面HTML html = await page.content() # 获取页面Cookies cookies = await page.cookies() # 执行自定义JS代码 scroll_height = await page.evaluate('() => document.body.scrollHeight') print(f"页面滚动高度:{scroll_height}") return text, href, html, cookies

3.4 网络请求拦截

Pyppeteer 可拦截页面的网络请求,实现请求过滤、响应修改等功能:

python

运行

async def intercept_request(page): # 启用请求拦截 await page.setRequestInterception(True) # 定义拦截逻辑 async def handle_request(request): # 过滤图片、视频请求,提升爬取速度 if request.resourceType in ['image', 'video', 'stylesheet']: await request.abort() else: await request.continue_() # 绑定拦截事件 page.on('request', handle_request)

四、实战:爬取知乎热榜动态页面

4.1 需求分析

知乎热榜(https://www.zhihu.com/hot)的热榜数据通过 JS 动态渲染,需模拟浏览器加载页面,提取热榜排名、标题、热度值、链接等信息,并将数据保存至 JSON 文件。

4.2 完整代码实现

python

运行

import asyncio import json from pyppeteer import launch from pyppeteer.errors import TimeoutError class ZhihuHotSpider: def __init__(self): self.base_url = "https://www.zhihu.com/hot" self.hot_data = [] # 存储热榜数据 self.browser = None self.page = None async def init_browser(self): """初始化浏览器""" self.browser = await launch( headless=True, args=[ '--no-sandbox', # 禁用沙箱(服务器环境必需) '--disable-dev-shm-usage', # 解决内存不足问题 '--disable-images', # 禁用图片加载 '--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36' ], # 禁用JS日志输出,减少干扰 dumpio=False ) self.page = await self.browser.newPage() # 设置视口大小 await self.page.setViewport({'width': 1920, 'height': 1080}) # 启用请求拦截,过滤非必要资源 await self.page.setRequestInterception(True) self.page.on('request', self.intercept_request) async def intercept_request(self, request): """拦截网络请求""" # 过滤图片、视频、样式、字体请求 blocked_types = ['image', 'video', 'stylesheet', 'font'] if request.resourceType in blocked_types: await request.abort() else: await request.continue_() async def crawl_hot_data(self): """爬取热榜数据""" try: # 访问知乎热榜页面,等待页面加载完成 await self.page.goto(self.base_url, {'waitUntil': 'networkidle2', 'timeout': 15000}) # 等待热榜列表加载 await self.page.waitForSelector('.HotList-list', {'timeout': 10000}) # 执行JS提取热榜数据 self.hot_data = await self.page.evaluate('''() => { const hotList = []; // 遍历热榜条目 document.querySelectorAll('.HotList-item').forEach((item, index) => { // 提取排名 const rank = index + 1; // 提取标题 const title = item.querySelector('.HotItem-title')?.textContent || ''; // 提取热度值 const heat = item.querySelector('.HotItem-metrics')?.textContent || ''; // 提取链接 const link = item.querySelector('.HotItem-title a')?.href || ''; // 提取简介 const desc = item.querySelector('.HotItem-excerpt')?.textContent || ''; hotList.push({ rank: rank, title: title.trim(), heat: heat.trim(), link: link, desc: desc.trim() }); }); return hotList; }''') print(f"成功爬取{len(self.hot_data)}条知乎热榜数据") # 打印前5条数据验证 for i in range(5): print(f"\n排名{i+1}:") print(f"标题:{self.hot_data[i]['title']}") print(f"热度:{self.hot_data[i]['heat']}") print(f"链接:{self.hot_data[i]['link']}") except TimeoutError: print("页面加载超时,请检查网络或重试") except Exception as e: print(f"爬取过程出错:{str(e)}") async def save_to_json(self): """保存数据到JSON文件""" if not self.hot_data: print("无数据可保存") return with open('zhihu_hot.json', 'w', encoding='utf-8') as f: json.dump(self.hot_data, f, ensure_ascii=False, indent=4) print("\n数据已保存至zhihu_hot.json") async def close_browser(self): """关闭浏览器""" if self.browser: await self.browser.close() async def run(self): """执行爬虫主流程""" # 初始化浏览器 await self.init_browser() # 爬取数据 await self.crawl_hot_data() # 保存数据 await self.save_to_json() # 关闭浏览器 await self.close_browser() if __name__ == '__main__': # 执行异步爬虫 spider = ZhihuHotSpider() asyncio.get_event_loop().run_until_complete(spider.run())

4.3 输出结果

控制台输出(部分):

plaintext

成功爬取50条知乎热榜数据 排名1: 标题:为什么现在的年轻人越来越反感「专家」? 热度:102.3万 链接:https://www.zhihu.com/question/6328xxxx 排名2: 标题:2025年一线城市房价会怎么走? 热度:98.7万 链接:https://www.zhihu.com/question/6329xxxx 排名3: 标题:普通人如何通过副业月入5000? 热度:89.5万 链接:https://www.zhihu.com/question/6330xxxx 数据已保存至zhihu_hot.json
JSON 文件输出(部分):

json

[ { "rank": 1, "title": "为什么现在的年轻人越来越反感「专家」?", "heat": "102.3万", "link": "https://www.zhihu.com/question/6328xxxx", "desc": "近期多个行业专家的言论引发网友热议,年轻人对专家的信任度似乎在持续下降..." }, { "rank": 2, "title": "2025年一线城市房价会怎么走?", "heat": "98.7万", "link": "https://www.zhihu.com/question/6329xxxx", "desc": "2025年开年,北上广深等一线城市房价出现小幅波动,业内人士对此看法不一..." } ]

4.4 核心原理剖析

  1. 请求拦截优化:通过page.setRequestInterception(True)启用请求拦截,过滤图片、视频等非必要资源,减少网络请求数量,提升页面加载速度(相比未拦截,加载速度提升 40% 以上)。

  2. 动态数据提取:利用page.evaluate()执行自定义 JS 代码,直接在浏览器上下文提取动态渲染的热榜数据。这种方式相比逐个定位元素,效率更高,尤其适合批量数据提取。

  3. 异常处理:捕获TimeoutError(页面加载超时)和通用异常,确保爬虫不会因单次错误崩溃,提升鲁棒性。

  4. 浏览器配置优化

    • --no-sandbox--disable-dev-shm-usage:解决 Linux 服务器环境下的运行问题;
    • --disable-images:禁用图片加载,进一步降低资源占用;
    • 自定义 User-Agent:模拟真实浏览器,降低反爬识别概率。

五、Pyppeteer 高级特性

5.1 页面滚动与懒加载处理

针对懒加载的页面(滚动后加载更多数据),可通过模拟滚动实现全量数据爬取:

python

运行

async def scroll_page(page): """模拟页面滚动""" # 滚动到底部 await page.evaluate('''async () => { await new Promise((resolve) => { let totalHeight = 0; const distance = 100; const timer = setInterval(() => { const scrollHeight = document.body.scrollHeight; window.scrollBy(0, distance); totalHeight += distance; // 滚动到底部或达到最大高度时停止 if (totalHeight >= scrollHeight - window.innerHeight) { clearInterval(timer); resolve(); } }, 100); }); }''')

5.2 页面截图与 PDF 导出

Pyppeteer 支持页面截图和 PDF 导出,可用于数据留存或可视化:

python

运行

async def screenshot_and_pdf(page): # 页面截图(全屏) await page.screenshot({'path': 'zhihu_hot.png', 'fullPage': True}) # 导出PDF await page.pdf({'path': 'zhihu_hot.pdf', 'format': 'A4'}) print("截图和PDF已生成")

5.3 多页面并发爬取

利用 asyncio 实现多页面并发爬取,提升爬取效率:

python

运行

async def crawl_multiple_pages(urls): """并发爬取多个页面""" browser = await launch(headless=True) async def crawl_single_url(url): """爬取单个URL""" page = await browser.newPage() try: await page.goto(url, {'waitUntil': 'networkidle2'}) title = await page.title() print(f"爬取完成:{url} - 标题:{title}") return title finally: await page.close() # 并发执行爬取任务 tasks = [crawl_single_url(url) for url in urls] results = await asyncio.gather(*tasks) await browser.close() return results # 测试并发爬取 if __name__ == '__main__': urls = [ 'https://www.zhihu.com/hot', 'https://www.zhihu.com/topic/19552832', 'https://www.zhihu.com/question/6328xxxx' ] asyncio.get_event_loop().run_until_complete(crawl_multiple_pages(urls))
原理说明:
  • asyncio.gather():并发执行多个异步任务,等待所有任务完成并返回结果。
  • 多页面并发爬取相比串行爬取,效率提升倍数约等于并发数(需合理控制并发数,避免触发反爬)。

六、防反爬策略与最佳实践

6.1 核心防反爬策略

  1. 添加随机延迟

    python

    运行

    import random # 在页面操作间添加随机延迟 await asyncio.sleep(random.uniform(1, 3))
  2. 设置 Cookie 与 Session

    python

    运行

    # 设置Cookie await page.setCookie({ 'name': 'zhihu_cookie', 'value': 'your_cookie_value', 'domain': '.zhihu.com' })
  3. 避免自动化特征检测

    python

    运行

    # 隐藏webdriver标识 await page.evaluate('''() => { Object.defineProperty(navigator, 'webdriver', { get: () => undefined }); }''')
  4. 使用代理 IP

    python

    运行

    # 配置代理(支持HTTP/HTTPS/SOCKS) browser = await launch( headless=True, args=['--proxy-server=http://127.0.0.1:7890'] # 替换为实际代理地址 )

6.2 最佳实践

  1. 资源释放:确保在爬虫结束时关闭页面和浏览器,避免内存泄漏。
  2. 日志记录:添加日志模块(如 logging),记录爬取过程中的关键信息,便于问题排查。
  3. 数据校验:爬取完成后校验数据完整性,避免因页面结构变化导致数据缺失。
  4. 调试技巧
    • 启动浏览器时设置headless=False,可视化调试;
    • 使用page.on('console', lambda msg: print(msg.text))捕获页面 JS 日志;
    • 配置slowMo=500(慢动作执行),观察页面操作流程。

七、总结

Pyppeteer 作为轻量级无头浏览器工具,凭借异步编程、无需驱动、资源占用低等优势,成为中小规模动态页面爬虫的理想选择。本文通过知乎热榜爬取案例,完整展示了 Pyppeteer 的核心功能与实战技巧,包括请求拦截、动态数据提取、并发爬取等关键技术。相较于 Playwright,Pyppeteer 更轻量、学习成本更低,适合快速开发轻量级爬虫;而 Playwright 则在多浏览器支持、功能丰富度上更具优势,开发者可根据实际场景选择。

在实际开发中,需结合防反爬策略与性能优化技巧,平衡爬取效率与稳定性。后续将讲解爬虫请求签名参数破解、JS 加密逆向等进阶技术,帮助开发者应对更复杂的反爬场景。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/2/16 12:46:27

39. UVM Factory Override

UVM Factory:验证平台的"智能生产线" 我们要学习UVM中最强大、最核心的特性之一:Factory机制。这就像是一个智能的生产线,可以根据需求动态更换生产的产品类型,而不需要修改生产线本身。 🎯 一句话理解UVM F…

作者头像 李华
网站建设 2026/2/19 9:21:13

毕设分享 基于单片机的红外热视仪(源码+硬件+论文)

文章目录 0 前言1 主要功能2 硬件设计3 核心软件设计4 实现效果5 最后 0 前言 🔥 这两年开始毕业设计和毕业答辩的要求和难度不断提升,传统的毕设题目缺少创新和亮点,往往达不到毕业答辩的要求,这两年不断有学弟学妹告诉学长自己…

作者头像 李华
网站建设 2026/2/7 4:06:54

vue和springboot框架开发的基于协同过滤算法的跳蚤市场商品推荐系统_9k725cw1_一口蛋黄苏

文章目录具体实现截图主要技术与实现手段关于我本系统开发思路java类核心代码部分展示结论源码lw获取/同行可拿货,招校园代理 :文章底部获取博主联系方式!具体实现截图 同行可拿货,招校园代理 vuesprivue和springboot框架开发的基于协同过滤算法的跳蚤…

作者头像 李华