当前位置:  首页>> 技术小册>> Python3网络爬虫开发实战(下)

15.10 Scrapy 对接 Splash

在网络爬虫的开发过程中,经常会遇到需要处理JavaScript渲染的网页内容。传统的HTTP请求库(如requests、urllib等)无法直接执行JavaScript代码,因此无法获取由JavaScript动态生成的数据。为了解决这个问题,我们可以使用Scrapy框架结合Splash工具来实现对JavaScript渲染页面的爬取。

15.10.1 Splash 简介

Splash是一个JavaScript渲染服务,它使用WebKit浏览器引擎(类似于Chrome和Safari的浏览器引擎)来执行JavaScript,并能够将渲染后的HTML、PNG、JPEG等格式的内容返回给客户端。Splash特别适用于需要抓取动态网页内容的场景,如单页应用(SPA)或需要JavaScript才能显示的数据。

Splash可以作为一个独立的HTTP服务运行,支持多种编程语言的接口调用,包括Python。Scrapy作为一个功能强大的网络爬虫框架,通过中间件(Middleware)和扩展(Extensions)机制,可以很方便地与Splash集成,实现JavaScript渲染页面的爬取。

15.10.2 安装与配置

1. 安装Splash

Splash的安装可以通过Docker来简化过程,因为Docker容器提供了运行Splash所需的所有依赖项。首先,确保你的系统上安装了Docker。然后,通过以下命令拉取Splash的Docker镜像并启动服务:

  1. docker pull scrapinghub/splash
  2. docker run -p 8050:8050 scrapinghub/splash

这条命令会启动Splash服务,并将其映射到宿主机的8050端口上。

2. 配置Scrapy

要在Scrapy中使用Splash,你需要在Scrapy项目中配置Splash的相关设置。这通常包括在settings.py文件中添加Splash的URL和必要的中间件。

  1. # settings.py
  2. # Splash服务URL
  3. SPLASH_URL = 'http://localhost:8050'
  4. # 启用Splash中间件
  5. DOWNLOADER_MIDDLEWARES = {
  6. 'scrapy_splash.SplashCookiesMiddleware': 723,
  7. 'scrapy_splash.SplashMiddleware': 725,
  8. 'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware': 810,
  9. }
  10. # 设置Splash的DUPEFILTER_CLASS(如果需要)
  11. DUPEFILTER_CLASS = 'scrapy_splash.SplashAwareDupeFilter'
  12. # Splash请求设置
  13. SPIDER_MIDDLEWARES = {
  14. 'scrapy_splash.SplashDeduplicateArgsMiddleware': 100,
  15. }
  16. # 启用HTTP缓存
  17. HTTPCACHE_STORAGE = 'scrapy_splash.SplashAwareFSCacheStorage'

注意:以上配置可能需要根据你的具体需求进行调整。

15.10.3 编写Splash请求

在Scrapy中,当你想要通过Splash发送请求时,你需要在请求(Request)对象中添加一些特殊的参数,以指示Scrapy通过Splash发送该请求。这些参数包括splash_url(Splash服务的URL,通常与SPLASH_URL相同,但可以在请求级别覆盖)、endpoint(Splash的API端点,如'render.html')、args(传递给Splash的额外参数,如JavaScript等待时间wait)。

  1. import scrapy
  2. from scrapy_splash import SplashRequest
  3. class MySpider(scrapy.Spider):
  4. name = 'my_splash_spider'
  5. def start_requests(self):
  6. url = 'http://example.com/javascript_rendered_page'
  7. yield SplashRequest(url=url,
  8. endpoint='render.html',
  9. args={'wait': 0.5},
  10. callback=self.parse)
  11. def parse(self, response):
  12. # 这里处理渲染后的HTML
  13. print(response.text)
  14. # 提取数据...

在上面的例子中,SplashRequest类被用来创建一个请求,该请求通过Splash的'render.html'端点发送,并设置了一个0.5秒的等待时间,以确保JavaScript有足够的时间来渲染页面。渲染后的HTML内容将通过Scrapy的响应对象传递给parse回调函数进行处理。

15.10.4 处理JavaScript生成的动态内容

一旦页面通过Splash渲染,你就可以像处理普通HTML页面一样,使用Scrapy的选择器(Selectors)或XPath、CSS选择器来提取数据了。由于Splash已经处理了JavaScript的渲染,所以你现在可以看到并提取那些原本被JavaScript动态生成的内容。

  1. from scrapy.selector import Selector
  2. def parse(self, response):
  3. # 使用Selector或response.css/response.xpath来提取数据
  4. selector = Selector(response)
  5. dynamic_content = selector.css('div.dynamic-content::text').get()
  6. print(dynamic_content)
  7. # 还可以继续发送其他请求或进行其他处理...

15.10.5 注意事项与优化

  • 性能考虑:Splash渲染JavaScript页面比直接下载HTML要慢,因为它需要等待JavaScript执行完毕。因此,在设计爬虫时应考虑减少不必要的Splash请求,或优化Splash服务的性能。
  • 资源消耗:Splash服务会消耗较多的CPU和内存资源,尤其是在高并发请求的情况下。确保你的服务器或Docker容器有足够的资源来支持Splash的运行。
  • 错误处理:在使用Splash时,可能会遇到各种JavaScript错误或渲染问题。确保你的爬虫能够妥善处理这些错误,例如通过重试机制或记录错误日志。
  • Splash参数调整:Splash提供了许多参数来调整渲染过程,如等待时间、视口大小、浏览器代理等。根据你的具体需求调整这些参数,以优化渲染效果和性能。

15.10.6 结论

Scrapy与Splash的集成为网络爬虫开发者提供了一种强大的方式来处理JavaScript渲染的网页内容。通过合理配置Scrapy项目和编写适当的Splash请求,你可以轻松地从动态网页中提取所需的数据。然而,也需要注意到Splash渲染过程的性能开销和资源消耗,并采取相应的优化措施来确保爬虫的稳定运行。