我为什么放弃Scrapy转投Playwright?爬虫框架选择的真相
一个让我损失48小时的教训上个月接了个爬虫单子对方要爬一个教育类网站页面结构不复杂但所有核心数据都通过JavaScript动态渲染。我第一反应Scrapy嘛老本行了。结果一跑全乱码频繁被ban忙活两天没产出。最后换成Playwright6小时搞定。48小时的代价让我重新审视爬虫框架的选择——选错了后面全是坑。Scrapy是被高估的Scrapy在2024年仍然是最流行的Python爬虫框架之一但它的问题同样明显。异步处理存粹是噩梦。Scrapy基于Twisted回调地狱式写法。你看一段Scrapy代码往往要追踪parse函数里层层嵌套的yield。# Scrapy的典型回调写法# 注意解析一个页面要三个回调人脑很难跟踪classMySpider(scrapy.Spider):nameexamplestart_urls[http://example.com]defparse(self,response):# 提取详情页链接后交给下一个回调urlsresponse.css(a::attr(href)).getall()forurlinurls:yieldscrapy.Request(url,callbackself.parse_detail)defparse_detail(self,response):# 再处理二次请求item_urlresponse.css(.next-link).attrib[href]yieldscrapy.Request(item_url,callbackself.parse_final)defparse_final(self,response):# 最终提取数据yield{data:response.text}这种写法在三个以上回调时就变成面条。而Playwright用async/await逻辑平铺# Playwright的异步写法——线性、直观asyncdefrun_scraper():asyncwithasync_playwright()asp:browserawaitp.chromium.launch()pageawaitbrowser.new_page()# 打开首页awaitpage.goto(http://example.com)# 获取所有详情页链接urlsawaitpage.eval_on_selector_all(a,elements elements.map(e e.href))# 直接循环处理每个详情页forurlinurls[:5]:# 前5个awaitpage.goto(url)# 再点击一个按钮获取更多数据awaitpage.click(.next-link)# 提取最终数据dataawaitpage.text_content(body)print(data)awaitbrowser.close()动态内容支持是Scrapy的硬伤。Scrapy原生只拿HTML对于JS渲染的数据你需要额外集成Splash或Selenium。这不只是多装个包的问题调试Splash中间件写个配置要折腾一整天。而Playwright天生就是浏览器自动执行JS。我指出的踩坑点Scrapy的Downloader中间件顺序经常搞错。新手总以为中间件是按代码顺序执行实际上是按优先级数字排序默认一个中间件550-1000你自定义中间件如果不设置优先级就会在默认中间件之后执行这点坑过至少5个朋友。scrapy.Request传cookie时直接用cookies参数会导致请求头重复正确做法是用headers里的Cookie字段。# 错误写法Scrapy的cookies参数容易出问题yieldscrapy.Request(url,cookies{sessionid:abc123})# 正确写法直接塞headersyieldscrapy.Request(url,headers{Cookie:sessionidabc123})默认并发16个请求但很多网站防火墙会封快速连续请求。别指望自动限速你得手动设置CONCURRENT_REQUESTS_PER_DOMAIN 2。为什么Playwright是2024年更好的选择坦白讲如果今天让我从零开始选爬虫框架我会直接上Playwright。三个理由第一天然处理JS动态页面。现在90%的风控网站都不简单返回HTML而是先返回空壳再通过XHR或fetch加载数据。Scrapy需要手动监听网络请求Playwright可以直接等网络空闲# Playwright等待所有网络请求完成awaitpage.goto(https://example.com,wait_untilnetworkidle)# 此时页面已经完全渲染包括所有异步加载的数据dataawaitpage.content()第二反爬能力更强。Playwright可以模拟真实浏览器指纹、操作鼠标移动、甚至随机等待时间。我在一个项目中同时用ScrapySplash和PlaywrightPlaywright的通过率比Scrapy高3倍。具体说Scrapy抓政务网站如社保查询基本秒封Playwright却能稳定运行超过48小时。第三调试体验碾压。Playwright有官方Playwright Inspector可以一步步回放每一步操作。Scrapy调试要么打印response.text要么用scrapy shell体验糟糕。但Playwright也不是万能药。它更重资源每个浏览器实例吃几百兆内存。如果只是爬静态API接口用Playwright就是杀鸡用牛刀。轻量方案RequestsBeautifulSoup的适用边界很多人觉得Scrapy很重就转向RequestsBeautifulSoup。这套组合确实轻快但只适用于两个场景目标页面是静态HTML服务端渲染只需要单页面抓取不需要爬取整站链路我曾用Requests爬一个博客站十几行代码搞定importrequestsfrombs4importBeautifulSoup# 直接请求没有回调没有中间件resprequests.get(https://blog.example.com)soupBeautifulSoup(resp.text,lxml)titlessoup.select(h2.article-title)fortintitles:print(t.text.strip())但一遇到翻页、登录、验证码这套方案就废了。你需要手动管理cookie构造多步请求。Scrapy至少帮你处理了cookie自动管理、重试、去重。所以当需要爬5个以上页面且有登录需求时直接上Playwright更省事。我和一个同事做过测试同样爬取一个包含1000个详情页的电商网站Scrapy爬虫代码写了300行含中间件、管道、item定义Playwright只用了150行。性能上Playwright慢20%-30%但代码可维护性差距巨大。别被Scrapy的生态忽悠Scrapy有大量第三方组件scrapy-splash、scrapy-selenium、scrapy-redis等。但这些组件质量参差不齐。比如scrapy-redis在2023年就停止维护了最新版Scrapy 2.112024年6月发布与scrapy-redis存在兼容问题。你花时间研究这些组件不如直接学Playwright。还有Scrapy的回调模型对函数式编程不熟悉的人就是折磨。我曾在一个项目里需要嵌套5层回调调试到怀疑人生。后来重构为Playwright的async/await模式逻辑清晰了bug减少80%。2024年6月的Stack Overflow调研显示Playwright在自动化领域的关注度首次超过Scrapy。这不是偶然而是趋势。踩坑总结Scrapy的日志系统默认INFO级别打印大量信息生产环境建议设为WARNINGLOG_LEVEL WARNINGPlaywright的浏览器生命周期不要重复launch browser应该复用BrowserContext。每个Context相当于一个独立的浏览器实例但开销小得多。# 错误每次请求都打开一个新浏览器asyncdefscrape_all():forurlinurls:asyncwithasync_playwright()asp:browserawaitp.chromium.launch()pageawaitbrowser.new_page()awaitpage.goto(url)awaitbrowser.close()# 正确复用浏览器实例asyncdefscrape_all():asyncwithasync_playwright()asp:browserawaitp.chromium.launch()contextawaitbrowser.new_context()forurlinurls:pageawaitcontext.new_page()awaitpage.goto(url)awaitpage.close()awaitbrowser.close()反爬优先级别依赖User-Agent随机化现在网站更多通过TLS指纹、WebDriver检测来封你。Playwright可以用--disable-blink-featuresAutomationControlled参数关闭自动化标记。我的最终建议如果你的爬虫目标网站超过50%需要JS渲染或者需要处理登录、验证码直接选Playwright。如果只是抓几个静态页面RequestsBeautifulSoup足够了。Scrapy只适合那种需要大规模、纯静态内容的爬虫比如爬取整个Wikipedia数据——但2024年这类场景越来越少。你可能会说Scrapy性能比Playwright好确实纯数据抓取场景Scrapy每秒能处理上千请求Playwright只能处理几十个。但现实是大多数网站都不允许你每秒发一千个请求。你把并发降到2-5时两者的差距微不足道。有人问我为什么不用ScrapyPlaywright混合试过最后发现光调度两种工具的内存和异常处理就累死人。不如只选一个精通它。我想听听你踩过哪些爬虫框架的坑特别是那些看起来很美、用起来很脏的框架欢迎在评论区开喷。