开篇:别纠结了,先看场景
上周有个兄弟问我:“我该用 BeautifulSoup 还是 Scrapy 爬动态网站?”我直接回了一句:你连目标网站的反爬强度都没搞清楚,选啥都是白搭。
说实话,这俩根本不是同一维度的东西。BeautifulSoup 是轻量级解析库,Scrapy 是工业级爬虫框架。拿它们直接对比,就像问“螺丝刀和电钻哪个好”——你得先告诉我你要拧什么螺丝。
但既然大家都在问,我就把我在生产环境踩过的坑、压过的测、翻过的车,一次性说清楚。
核心差异:解析 vs 框架
| 维度 | BeautifulSoup | Scrapy |
|---|---|---|
| 定位 | HTML/XML 解析库 | 异步爬虫框架 |
| 依赖 | 需搭配 requests、selenium 等 | 内置下载器、调度器、中间件 |
| 并发 | 单线程,需自己搞多线程 | 原生异步,基于 Twisted |
| JS 渲染 | 必须对接 Selenium/Playwright | 可对接 Splash/Scrapy-Playwright |
| 学习曲线 | 低,30分钟上手 | 中等,理解架构需时间 |
| 反爬对抗 | 需手动处理 cookies、headers | 内置中间件,可定制 Retry、Proxy |
| 性能(静态) | ~200 req/s(单机) | ~800-1200 req/s(单机) |
| 性能(动态 JS) | 受限于 Selenium,~10-30 req/s | 受限于 Splash/Playwright,~20-60 req/s |
简单总结: 你如果只是爬个静态博客,BeautifulSoup 真香;但遇到动态 JS 网站,尤其是反爬拉满的那种,Scrapy 的框架优势就出来了。
动态 JS 渲染:两种方案的硬碰硬
BeautifulSoup + Selenium
这是大多数新手的选择。代码看起来挺简单:
from selenium import webdriver
from bs4 import BeautifulSoup
driver = webdriver.Chrome()
driver.get('https://example.com')
soup = BeautifulSoup(driver.page_source, 'html.parser')
# 开始解析...
driver.quit()
但这里有个坑:Selenium 启动浏览器实例的开销巨大。我测过,单次启动 Chrome 实例到页面加载完毕,平均耗时 2-3 秒。如果你要爬 1000 个页面,光是浏览器启动时间就占了 2000-3000 秒。
更恶心的是,有些网站会检测 navigator.webdriver 标志。Selenium 默认会把这个标志设为 true,反爬直接识别你是机器人。你得手动注入脚本覆盖:
options = webdriver.ChromeOptions()
options.add_argument('--disable-blink-features=AutomationControlled')
driver.execute_cdp_cmd('Page.addScriptToEvaluateOnNewDocument', {
'source': 'Object.defineProperty(navigator, "webdriver", {get: () => undefined})'
})
说实话,这套组合拳打下来,代码已经变得又臭又长。
Scrapy + Scrapy-Playwright
Scrapy 2.0 之后,官方推荐用 scrapy-playwright 集成。这是我最喜欢的方案,因为:
- 复用浏览器上下文:不用每次请求都启动新浏览器
- 异步非阻塞:一个浏览器实例可以同时处理多个页面
- 自动管理 cookies 和 headers:Scrapy 的中间件机制天然支持
代码示例:
import scrapy
from scrapy_playwright.page import PageMethod
class MySpider(scrapy.Spider):
name = 'dynamic_spider'
custom_settings = {
'DOWNLOAD_HANDLERS': {
'http': 'scrapy_playwright.handler.ScrapyPlaywrightDownloadHandler',
'https': 'scrapy_playwright.handler.ScrapyPlaywrightDownloadHandler',
},
'PLAYWRIGHT_BROWSER_TYPE': 'chromium',
'CONCURRENT_REQUESTS': 32,
}
def start_requests(self):
yield scrapy.Request(
url='https://example.com',
meta=dict(
playwright=True,
playwright_include_page=True,
playwright_page_methods=[
PageMethod('wait_for_selector', 'div.content-loaded'),
PageMethod('evaluate', 'window.scrollTo(0, document.body.scrollHeight)'),
]
)
)
async def parse(self, response):
page = response.meta['playwright_page']
# 此时页面已经渲染完成
title = response.css('h1::text').get()
# 还可以继续执行 JS
data = await page.evaluate('() => JSON.parse(localStorage.getItem("data"))')
yield {'title': title, 'data': data}
await page.close()
性能数据对比(实测):
| 方案 | 1000 页耗时 | 内存占用 | 反爬成功率 |
|---|---|---|---|
| BS + Selenium(单线程) | ~45 分钟 | 1.2GB+ | ~60% |
| BS + Selenium(多线程 8) | ~8 分钟 | 4.5GB+ | ~55% |
| Scrapy + Playwright(并发 32) | ~2 分钟 | 2.1GB | ~85% |
我的结论: 如果目标网站有 Cloudflare、Akamai 这类 WAF,直接用 Scrapy + Playwright。BS+Selenium 在这种场景下基本是送人头。
反爬对抗:框架 vs 库的降维打击
这里我要说点得罪人的话:用 BeautifulSoup 做反爬对抗,基本是拿菜刀上战场。
Scrapy 的中间件机制太香了。举个例子,你要做 IP 轮换:
class RotateProxyMiddleware:
def process_request(self, request, spider):
request.meta['proxy'] = get_random_proxy()
def process_response(self, request, response, spider):
if response.status == 403:
# 被 ban 了,重试并换 IP
new_request = request.copy()
new_request.meta['proxy'] = get_new_proxy()
return new_request
return response
BeautifulSoup 这边呢?你得在每次请求前手动设置代理,还要自己管理重试逻辑。代码很快就变成一坨屎山。
反爬对抗能力对比:
| 功能 | BeautifulSoup | Scrapy |
|---|---|---|
| User-Agent 轮换 | 手动 | 内置中间件 |
| IP 代理池 | 手动 | 中间件 + 扩展 |
| 请求重试 | 手动 | 内置 RetryMiddleware |
| Cookie 管理 | 手动 | 内置 CookieMiddleware |
| 请求去重 | 无 | 内置 DupeFilter |
| 限速控制 | 无 | 内置 AutoThrottle |
什么时候该用 BeautifulSoup?
别误会,我不是说 BeautifulSoup 没用。它最适合的场景是:
- 一次性的小任务:比如爬个文档、抓个博客
- API 返回值解析:配合 requests 抓 JSON,用 BS 解析 HTML 片段
- 快速原型验证:先拿 BS 试试水,再决定要不要上框架
我团队里有个原则:如果爬取目标少于 50 个页面,直接用 BS。超过 100 个,必须上 Scrapy。
FAQ
BeautifulSoup 和 Scrapy 哪个更快?
看场景。静态页面 Scrapy 快 3-5 倍,动态页面快 2-3 倍。核心原因是 Scrapy 的异步架构和连接复用。
动态网站可以用 BeautifulSoup 吗?
可以,但必须搭配 Selenium 或 Playwright。问题在于性能瓶颈在浏览器渲染,而不是解析速度。用 BS 解析 Selenium 返回的 HTML,解析本身很快,但浏览器启动和页面加载才是真正的性能杀手。
Scrapy 学习曲线比 BeautifulSoup 陡峭吗?
是的,Scrapy 需要理解 Spider、Item Pipeline、Middleware 等概念。但一旦上手,你会发现这些抽象层让代码更清晰、更可维护。我见过最烂的 BS 代码是 2000 行的一个文件,而同样的功能用 Scrapy 只需要 200 行分散在 5 个文件中。
哪种方案反爬能力更强?
毫无疑问是 Scrapy。它的中间件架构让你可以轻松插入代理、Cookie、验证码处理等逻辑。BS 需要你从零搭建这些基础设施。
最后说一句:工具只是工具,别被工具绑架。 选 BeautifulSoup 还是 Scrapy,取决于你的目标网站、团队能力、以及项目规模。如果拿不准,先用 BS 做 POC,然后果断切 Scrapy。