结合Splash与Scrapy:高效爬取动态JavaScript网站

在当今的Web开发中,JavaScript的广泛应用使得许多网站的内容无法通过传统的请求-响应模式直接获取。为了解决这个问题,Scrapy开发者经常需要集成像Splash这样的JavaScript渲染引擎。本文将详细介绍Splash JS引擎的工作原理,并探讨如何将其与Scrapy框架无缝结合使用。

什么是Splash?

Splash是一个轻量级的浏览器服务,专门为Python爬虫设计,用于渲染JavaScript内容。它基于WebKit引擎,提供了简单的HTTP API,使开发者能够通过发送请求来获取已渲染的页面内容。

Splash的主要特点

  1. JavaScript渲染:能够执行页面中的JavaScript代码,加载动态内容
  2. HTTP API:通过简单的RESTful接口控制浏览器行为
  3. Lua脚本支持:可以使用Lua编写复杂的抓取逻辑
  4. 多进程架构:支持并行渲染请求
  5. Scrapy集成:提供官方的Scrapy-Splash插件,方便与Scrapy集成

为什么Scrapy需要Splash?

Scrapy作为强大的爬虫框架,对于静态网站有极好的处理能力,但对于动态JavaScript渲染的网站则显得力不从心。传统Scrapy只能获取初始HTML,无法处理:

  • 无限滚动内容
  • 单页应用(SPA)
  • 需要点击或交互才能显示的内容
  • 基于AJAX动态加载的数据

安装Splash

首先需要安装Splash服务。有几种方式可以选择:

Docker方式(推荐)

docker run -p 8050:8050 scrapinghub/splash

这将在本地的8050端口启动Splash服务。

手动安装

也可以从Splash官方仓库下载源码编译安装。

Scrapy集成Splash

Scrapy官方提供了scrapy-splash包来简化集成过程。

在这里插入图片描述

安装依赖

pip install scrapy-splash

配置Splash

在Scrapy项目的settings.py中添加以下配置:

# 启用Splash下载器中间件
DOWNLOADER_MIDDLEWARES = {'scrapy_splash.SplashCookiesMiddleware': 723,'scrapy_splash.SplashMiddleware': 725,'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware': 810,
}# 启用Splash的DUPEFILTER_CLASS
DUPEFILTER_CLASS = 'scrapy_splash.SplashAwareDupeFilter'# 使用Splash的HTTPCache
HTTPCACHE_STORAGE = 'scrapy_splash.SplashAwareFSCacheStorage'# Splash服务器设置
SPLASH_URL = 'http://localhost:8050'

使用SplashRequest

在Spider中,使用SplashRequest替代普通的Request

import scrapy
from scrapy_splash import SplashRequestclass JavaScriptSpider(scrapy.Spider):name = 'javascript_spider'start_urls = ['https://example.com']def start_requests(self):for url in self.start_urls:yield SplashRequest(url,self.parse,endpoint='render.html',  # 使用Splash的渲染端点args={'wait': 2,  # 等待2秒让JS执行'timeout': 30,  # 超时设置'images': 0,  # 禁用图片加载提高速度})def parse(self, response):# 此处的response已包含渲染后的HTMLtitle = response.css('title::text').get()yield {'title': title}

使用Lua脚本

对于更复杂的场景,可以编写Lua脚本控制Splash行为:

-- 示例Lua脚本
function main(splash, args)assert(splash:go(args.url))assert(splash:wait(2))return {html = splash:html(),url = splash:url(),}
end

在Scrapy中使用:

yield SplashRequest(url,self.parse,endpoint='execute',  # 使用执行Lua的端点args={'lua_source': lua_script,'wait': 2,}
)

高级技巧

  1. 处理AJAX请求

    • 使用wait参数等待特定时间
    • 或者使用execute端点编写精确等待条件
  2. 模拟用户交互

    yield SplashRequest(url,args={'lua_source': '''function main(splash, args)assert(splash:go(args.url))assert(splash:wait(2))splash:runjs("document.querySelector('#search').value='scrapy';")assert(splash:wait(1))splash:mouse_click(100, 200)assert(splash:wait(2))return splash:html()end''','url': url,}
    )
    
  3. 表单提交

    yield SplashRequest(url,args={'lua_source': '''function main(splash, args)assert(splash:go(args.url))assert(splash:wait(2))splash:send_text('username', 'myuser')splash:send_text('password', 'mypassword')splash:runjs("document.querySelector('#login').click();")assert(splash:wait(3))return splash:html()end''','url': login_url,}
    )
    

性能优化

  1. 启用缓存
    • 配置HTTP缓存中间件
    • 设置合理的缓存过期时间
  2. 并行请求
    • 增加Splash的并发实例(通过Docker -p参数或手动配置)
    • 在Scrapy中增加并发请求数
  3. 选择性渲染
    • 对不需要JS的页面使用普通请求
    • 通过dont_filter参数避免重复渲染

常见问题解决

  1. Splash无法加载某些页面
    • 检查是否有反爬机制(如Cloudflare)
    • 尝试设置User-Agent或使用代理
  2. 性能问题
    • 减少不必要的wait时间
    • 禁用图片加载('images': 0
    • 增加Splash的内存和CPU资源
  3. Lua脚本错误
    • 使用Splash的日志功能调试
    • 逐步测试Lua脚本的每个部分

替代方案比较

虽然Splash是一个优秀的选择,但也可以考虑其他方案:

工具优点缺点
Splash轻量级,Scrapy集成好需要额外服务
Selenium功能强大资源消耗大,速度慢
Playwright现代API,多浏览器支持设置较复杂
Puppeteer性能好,Node.js方案需要非Python环境

结论

Splash为Scrapy提供了强大的JavaScript渲染能力,使得爬取动态网站变得可行甚至简单。虽然它需要额外的服务配置,但对于需要处理现代Web应用的爬虫项目来说,这是一个值得投资的工具。通过合理配置和优化,可以构建高效、稳定的动态网站爬虫系统。

对于需要处理大量动态内容的爬虫项目,建议采用Splash与Scrapy的组合方案,并根据具体需求调整Lua脚本和请求参数。随着Web技术的发展,掌握这样的动态爬取技术将成为爬虫工程师的重要技能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/82139.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

企业级可观测性实现:OpenObserve云原生平台的本地化部署与远程访问解析

文章目录 前言1. 安装Docker2. 创建并启动OpenObserve容器3. 本地访问测试4. 公网访问本地部署的OpenObserve4.1 内网穿透工具安装4.2 创建公网地址 5. 配置固定公网地址 前言 嘿,各位小伙伴们,今天要给大家揭秘一个在云原生领域里横扫千军的秘密法宝—…

将本地项目提交到新建的git仓库

方式一: # 登录git,新建git仓库和指定的分支,如master、dev# 下载代码,默认下载master分支 git clone http://10.*.*.67/performance_library/pfme-*.git # 切换到想要提交代码的dev分支 git checkout dev# 添加想要提交的文件 git add .#…

.NET平台用C#在PDF中创建可交互的表单域(Form Field)

在日常办公系统开发中,涉及 PDF 处理相关的开发时,生成可填写的 PDF 表单是一种常见需求,例如员工信息登记表、用户注册表、问卷调查或协议确认页等。与静态 PDF 不同,带有**表单域(Form Field)**的文档支持…

在macOS上安装windows系统

使用Boot Camp 1. 准备工作:确认Mac满足Boot Camp系统要求,准备好Windows安装光盘或ISO映像文件,以及一个至少8GB的空白USB闪存驱动器用于保存驱动程序。 2. 打开Boot Camp助理:在“应用程序”文件夹的“实用工具”中找到“Boot…

683SJBH基于J2EE的广州旅游管理系统

第1章  绪论 课题背景 自互联网internet成为一种革命性的大众媒体以来,其发展速度之快令人惊叹。而作为世界最大朝阳产业的旅游,当它与电子商务这一新兴模式相结合时,其潜藏的商业价值表露无遗。根据CNN(美国有线电视新闻网&…

前端面试每日三题 - Day 27

这是我为准备前端/全栈开发工程师面试整理的第27天每日三题练习,涵盖了: CSS选择器的优先级与权重计算机制Angular中的依赖注入(Dependency Injection)机制设计一个支持实时协作编辑(如Google Docs)的前端…

PostgreSQL数据库操作SQL

数据库操作SQL 创建 创建数据库 create database db_test;创建并指定相关参数 with owner : 所有者encoding : 编码connection limit :连接限制 create database db_test1 with owner postgresencoding utf-8connection limit 100;修改 修改数据库名称 renam…

JSP HTTP 状态码详解

JSP HTTP 状态码详解 引言 HTTP 状态码是 HTTP 协议的一部分,用于表示客户端与服务器之间请求与响应的状态。在 JavaServer Pages (JSP) 技术中,HTTP 状态码同样扮演着重要的角色。本文将详细解析 JSP 中的 HTTP 状态码,帮助开发者更好地理解和应用这些状态码。 HTTP 状态…

文件一键解密软件工具(支持pdf、word、excel、ppt、rar、zip格式文件)

一键解密解锁神器支持解密pdf、doc、docx、xls、xlsx、ppt、pptx、rar、zip格式文件,Excel表格、Word文档、PPT演示、RAR、ZIP压缩包、PDF文档一键轻松解密!简单/高效/安全。这款软件由密码帝官方提供,确保了其合法性和安全性,用户…

Banana Pi BPI-CM6 是一款八核 RISC-V 模块,兼容 Raspberry Pi CM 载板

Banana Pi BPI-CM6 是一款 SpacemIT K1 八核 RISC-V 系统级模块,遵循 Raspberry Pi CM5 的设计,并提供高达 16GB LPDDR4 RAM、高达 128GB eMMC 闪存、千兆以太网控制器和 WiFi 6 蓝牙 5.2 模块。 BPI-CM6 虽然与 Raspberry Pi CM5 基本兼容&#xff0c…

【项目篇之统一硬盘操作】仿照RabbitMQ模拟实现消息队列

统一硬盘操作 创建出实例封装交换机的操作封装队列的操作封装绑定的操作封装消息的操作总的完整代码: 我们之前已经使用了数据库去管理交换机,绑定,队列 还使用了数据文件去管理消息 此时我们就搞一个类去把上述两个部分都整合在一起&#…

快速上手SpringBoot开发指南

文章目录 1. 项目整体架构2. SpringBoot核心注解详解2.1 应用程序入口注解SpringBootApplication 2.2 控制器层注解RestControllerRequestMappingPostMappingRequestBody 2.3 服务层注解ServiceAutowired 2.4 数据访问层注解Repository 2.5 实体类注解JPA相关注解Lombok注解 3.…

Unity WebGL、js发布交互

官网参考 Unity3D开发之WebGL平台上 unity和js前端通信交互 WebFun.jslib mergeInto(LibraryManager.library, {JSLog: function (str) { var strsUTF8ToString(str); Log(str); Log(strs);}, Hello: function () {var strs"Hello, world!"; Log(strs); Log(UTF8ToS…

Spark 之 YarnCoarseGrainedExecutorBackend

YarnCoarseGrainedExecutorBackend executor ID , 在日志里也有体现。 25/05/06 12:41:58 INFO YarnCoarseGrainedExecutorBackend: Successfully registered with driver 25/05

[HOT 100] 2646. 最小化旅行的价格总和

文章目录 1. 题目链接2. 题目描述3. 题目示例4. 解题思路5. 题解代码6. 复杂度分析 1. 题目链接 2646. 最小化旅行的价格总和 - 力扣(LeetCode) 2. 题目描述 现有一棵无向、无根的树,树中有 n 个节点,按从 0 到 n - 1 编号。给你一…

分析 Docker 磁盘占用

以下是分析 Docker 磁盘占用的详细步骤和工具指南,帮助开发者快速定位和清理冗余数据: 1. 查看 Docker 磁盘使用概览 docker system df 输出说明: TYPE TOTAL ACTIVE SIZE RECLAIMABLE Images 15 …

聊一聊接口测试中的参数化测试

目录 一、核心概念 二、适用场景 三、参数化测试的核心目的 四、实现参数化测试的关键步骤 4.1 定义测试数据 4.2 使用测试框架参数化功能 4.3 执行测试与结果分析 五、最佳实践与注意事项 六、工具推荐 那参数化测试的目的是什么?应该是为了提高测试覆盖率…

Go语言——string、数组、切片以及map

一、string、数组、切片代码 package mainimport "fmt"// 定义结构体 type student struct {id intname stringage intscore float32 }func main() {// 使用var声明切片var slice1 []intslice1 append(slice1, 1)slice1 append(slice1, 2)slice1 append(sl…

Android 开发中JDK 的使用和配置详解

前些天发现了一个蛮有意思的人工智能学习网站,8个字形容一下"通俗易懂,风趣幽默",感觉非常有意思,忍不住分享一下给大家。 👉点击跳转到教程 在安卓开发中, 我们会使用到Java的JDK, JDK全程为(Java Development Kit)意思是:Java开发工具包。那么JDK 与我们的…

MPay码支付系统第四方聚合收款码多款支付插件个人免签支付源码TP8框架全开源

一、源码描述 这是一套码支付源码(MPay),基于TP8框架,前端layui2.9后端PearAdmin,专注于个人免签收款,通过个人的普通收款码,即可实现收款通知自动回调,支持绝大多数商城系统&#…