当前位置: 首页 > news >正文

集成Scrapy与异步库:Scrapy+Playwright自动化爬取动态内容

一、 为什么选择Scrapy + Playwright?

在技术选型时,我们有必要理解这套组合拳的优势所在:

  1. 强强联合的异步架构:Scrapy基于Twisted,是原生的异步框架;Playwright也提供了完整的异步API。二者的结合天衣无缝,能最大限度地发挥硬件性能,实现高并发爬取。
  2. 无与伦比的浏览器兼容性:Playwright支持Chromium、Firefox和WebKit(Safari),能够精准模拟不同浏览器环境,大大降低了因客户端差异导致爬取失败的风险。
  3. 强大的自动化能力:不仅仅是等待加载,Playwright可以模拟所有用户行为:点击、填写表单、滚动、悬停等,从而触发那些需要用户交互才会显示的数据。
  4. Scrapy的完整生态:我们无需放弃Scrapy的任何核心优势,如灵活的中间件、Item Pipeline、数据导出、请求调度等,仅仅是增强了其下载页面的能力。

二、 环境搭建与项目初始化

首先,我们需要安装必要的Python包。

# 安装Scrapy和Playwright
pip install scrapy playwright# 安装Playwright的浏览器驱动(这一步会下载Chromium, Firefox和WebKit)
playwright install

接下来,创建一个新的Scrapy项目。

scrapy startproject scrapy_playwright_demo
cd scrapy_playwright_demo
scrapy genspider dynamic_example example.com

三、 核心配置:启用Scrapy Playwright中间件

要让Scrapy使用Playwright,核心在于配置下载器中间件。修改项目下的 <font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">settings.py</font> 文件。

# settings.py# 启用Scrapy的默认下载器中间件
DOWNLOADER_MIDDLEWARES = {# 禁用Scrapy默认的RetryMiddleware,以避免与Playwright的重复尝试冲突(非必须)# 'scrapy.downloadermiddlewares.retry.RetryMiddleware': None,
}# 启用Playwright相关的下载处理器和中间件
DOWNLOAD_HANDLERS = {"http": "scrapy_playwright.handler.ScrapyPlaywrightDownloadHandler","https": "scrapy_playwright.handler.ScrapyPlaywrightDownloadHandler",
}# 启用Playwright的上下文处理器(非常重要)
TWISTED_REACTOR = "twisted.internet.asyncioreactor.AsyncioSelectorReactor"# Playwright相关设置
PLAYWRIGHT_BROWSER_TYPE = "chromium"  # 可选 "firefox", "webkit"
PLAYWRIGHT_LAUNCH_OPTIONS = {"headless": True,  # 设置为False可在调试时看到浏览器界面"timeout": 20 * 1000,  # 浏览器启动超时时间(毫秒)
}# 可选:配置每个Scrapy作业的浏览器上下文数量
# PLAYWRIGHT_MAX_CONTEXTS = 8

四、 构建爬虫:从静态到动态的跨越

现在,我们来修改生成的 <font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">dynamic_example.py</font> 爬虫文件。我们将以一个需要JavaScript渲染才能显示内容的假设网站为例。

   # spiders/dynamic_example.py
import scrapy
from scrapy_playwright.page import PageCoroutine# 代理配置信息
proxyHost = "www.16yun.cn"
proxyPort = "5445"
proxyUser = "16QMSOML"
proxyPass = "280651"# 构建代理服务器URL
proxy_url = f"http://{proxyUser}:{proxyPass}@{proxyHost}:{proxyPort}"class DynamicExampleSpider(scrapy.Spider):name = "dynamic_example"# 假设这个页面需要JS加载数据start_urls = ["https://quotes.toscrape.com/scroll"] def start_requests(self):for url in self.start_urls:# 关键:使用 `meta` 字典中的 `playwright` 键来启用Playwright处理yield scrapy.Request(url,meta={"playwright": True,# 可以指定使用不同的浏览器,覆盖全局设置# "playwright_browser_type": "firefox",# Playwright代理配置"playwright_context_kwargs": {"proxy": {"server": proxy_url,# 可选:设置代理认证方式# "username": proxyUser,# "password": proxyPass,}},# 最重要的一部分:定义页面加载后需要执行的Playwright操作"playwright_page_coroutines": [# 向下滚动到页面底部,触发无限加载PageCoroutine("wait_for_selector", "div.quote"), # 先等待首个元素出现PageCoroutine("evaluate", "window.scrollBy(0, document.body.scrollHeight)"),# 等待可能的网络请求或新内容出现,可以重复多次PageCoroutine("wait_for_timeout", 2000), # 等待2秒PageCoroutine("evaluate", "window.scrollBy(0, document.body.scrollHeight)"),PageCoroutine("wait_for_timeout", 2000),],# 可选:为这个请求单独设置一个上下文# "playwright_context": "my_context",},callback=self.parse,errback=self.errback_close_page, # 错误处理)async def parse(self, response):"""解析页面,提取数据"""self.logger.info(f"Parsing page: {response.url}")# 此时,response.body包含了由Playwright渲染后的完整HTMLquotes = response.css('div.quote')for quote in quotes:yield {'text': quote.css('span.text::text').get(),'author': quote.css('small.author::text').get(),'tags': quote.css('div.tags a.tag::text').getall(),}# 示例:如何点击"下一页"并继续用Playwright处理# next_page = response.css('li.next a::attr(href)').get()# if next_page is not None:#     next_page_url = response.urljoin(next_page)#     yield scrapy.Request(#         next_page_url,#         meta={#             "playwright": True,#             "playwright_context_kwargs": {#                 "proxy": {#                     "server": proxy_url,#                 }#             },#             "playwright_page_coroutines": [#                 PageCoroutine("wait_for_selector", "div.quote"),#             ],#         },#         callback=self.parse#     )async def errback_close_page(self, failure):"""错误回调函数,确保发生错误时页面被关闭"""page = failure.request.meta.get("playwright_page")if page:await page.close()self.logger.error(f"Request failed: {failure.request.url} - {failure.value}")

五、 高级技巧:处理复杂交互与上下文管理

对于更复杂的场景,例如需要登录、处理弹窗或管理多个独立会话,我们可以使用Playwright上下文。

# 在settings.py或自定义中间件中配置默认上下文
PLAYWRIGHT_DEFAULT_NAVIGATION_TIMEOUT = 30 * 1000
PLAYWRIGHT_CONTEXTS = {# 创建一个名为"persistent_context"的上下文,它会在整个爬虫过程中持续存在"persistent_context": {"context_args": {"ignore_https_errors": True,# 可以设置视口大小、User-Agent等"viewport": {"width": 1920, "height": 1080},"user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) ...",},"persistent": True, # 关键:使上下文持久化}
}# 在爬虫的请求中指定使用这个上下文
# yield scrapy.Request(
#     url,
#     meta={
#         "playwright": True,
#         "playwright_context": "persistent_context", # 使用持久化上下文
#         "playwright_page_coroutines": [
#             # 例如:先点击登录按钮,然后填写表单
#             PageCoroutine("click", "button#login-button"),
#             PageCoroutine("fill", "input#username", "my_username"),
#             PageCoroutine("fill", "input#password", "my_password"),
#             PageCoroutine("click", "button#submit-login"),
#             PageCoroutine("wait_for_navigation"), # 等待导航完成
#         ],
#     },
# )

六、 性能优化与最佳实践

  1. 控制并发:Playwright比较消耗资源。在 <font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">settings.py</font> 中合理设置 <font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">CONCURRENT_REQUESTS</font>,例如 <font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">8</font><font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">16</font>,避免内存溢出。
  2. 善用等待策略:优先使用 <font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">wait_for_selector</font><font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">wait_for_function</font> 等智能等待,而非固定的 <font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">wait_for_timeout</font>,这样能更快地继续执行。

及时清理:在 <font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">spider_closed</font> 信号中关闭所有浏览器上下文,确保资源被正确释放。

# 在爬虫类中添加
def closed(self, reason):from scrapy_playwright.utils import get_playwright_contextsfor context_name, context in get_playwright_contexts().items():self.logger.info(f"Closing context: {context_name}")context.close()
  1. 错误处理:网络不稳定、元素未找到等情况很常见,务必在协程和解析函数中做好异常捕获和处理。

七、 总结

通过将Scrapy与Playwright集成,我们构建的爬虫同时具备了Scrapy的工业级强度与Playwright的浏览器级模拟能力。这套方案能够应对当今Web开发中绝大多数复杂的动态内容加载场景,从简单的Ajax请求到复杂的单页应用,都不在话下。

http://www.dtcms.com/a/566030.html

相关文章:

  • Vue3 插件(可选独立模块复用)
  • 电容的 DC 偏压特性
  • 建网站支持设备是什么意思做网站界面尺寸
  • 什么是 webSocket?攻击面、安全风险与测试要点
  • 网站设计经典案例欣赏电商网站建设与运营
  • 【开题答辩全过程】以 废品回收小程序的设计与实现为例,包含答辩的问题和答案
  • Linux 日志查看与分析常用命令总结
  • 上海公司做网站专业网站制作的公司
  • MES系统精准集成,高效实现在线三维图模查看功能
  • 外贸网站建设哪家公司好制作app的免费软件
  • 营销网站建设大概费用忘记wordpress后台密码
  • 跨境电商如何防御价格爬虫?从 Nginx 防护到 AI 行为识别的实战方案
  • 做网站备案什么意思wordpress与微信教程
  • 关于外贸公司的网站定制网站开发公司生物医药
  • 自己的网站建设免费网站注册免费网站申请
  • 网站seo哪家好郑州定制网站开发
  • ubuntu24.04证书体系架构及证书有关配置文件、工具详细介绍
  • 国内房地产设计网站建设0453牡丹江信息网息网
  • 北辰做网站郑州seo怎么做
  • 轻量化美颜SDK特效功能开发方案:性能、功耗与体验的平衡实践
  • 做网站的图片房产西乡做网站
  • Milvus:向量字段-二进制向量、稀疏向量与密集向量(六)
  • 智能API测试工具SmartAPITester实现方案详解
  • 外贸视频网站开发网站的形式有哪些
  • 自己做的网站数据库怎么注册微信公众号
  • 智能云建站平台品牌策划师
  • QC-LDPC码的表示
  • 基于Java的智慧工地SaaS平台源码(含监管大屏与移动端)
  • 制冰机方案,家用制冰机MCU控制方案开发设计
  • MATLAB高效算法优化实战指南