在之前的章节中,爬取的都是静态页面中的信息,随着越来越多的网站开始用JS在客户端浏览器动态渲染网站,导致很多需要的数据并不能在原始的HTML中获取,再加上Scrapy本身并不提供JS渲染解析的功能,那么如何通过Scrapy爬取动态网站的数据呢?这一章节我们将学习这些知识。
通常对这类网站数据的爬取采用如下两种方法:
- 通过分析网站,找到对应数据的接口,模拟接口去获取需要的数据(一般也推荐这种方式,毕竟这种方式的效率最高),但是很多网站的接口隐藏的很深,或者接口的加密非常复杂,导致无法获取到它们的数据接口,此种方法很可能就行不通。
- 借助JS内核,将获取到的含有JS脚本的页面交由JS内核去渲染,最后将渲染后生成的HTML返回给Scrapy解析,Splash是Scrapy官方推荐的JS渲染引擎,它是使用Webkit开发的轻量级无界面浏览器,提供基于HTML接口的JS渲染服务。
一、搭建Splash服务
如何在Scrapy中调用Splash服务?Python库的scrapy-splash是一个非常好的选择,下面就来讲解如何使用scrapy-splash。
- 利用pip安装scrapy-splash库:
$ pip install scrapy-splash
- scrapy-splash使用的是Splash HTTP API,所以需要一个splash instance,一般采用docker运行splash,所以需要安装docker:
$ sudo apt-get install docker
如果是Mac的话需要使用brew安装,如下:
$ ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"`
$ brew install docker
- 拉取镜像:
$ sudo docker pull scrapinghub/splash
如果出现如下错误时,说明已确定Docker本身已经安装正常。
Using default tag: latest
Warning: failed to get default registry endpoint from daemon (Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?). Using system default: https://index.docker.io/v1/
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
问题原因是因为docker服务没有启动,在相应的/var/run/ 路径下找不到docker的进程。
执行service docker start
命令,启动docker服务。
- 使用docker开启Splash服务:
$ sudo docker run -p 8050:8050 scrapinghub/splash
- 在项目配置文件settings.py中配置splash服务:
1)添加splash服务器地址:
SPLASH_URL = 'http://localhost:8050'
2)将splash middleware添加到DOWNLOADER_MIDDLEWARE中:
DOWNLOADER_MIDDLEWARES = {
'scrapy_splash.SplashCookiesMiddleware': 723,
'scrapy_splash.SplashMiddleware': 725,
'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware': 810,
}
3)支持cache_args(可选):
SPIDER_MIDDLEWARES = {
'scrapy_splash.SplashDeduplicateArgsMiddleware': 100,
}
4)设置去重过滤器:
DUPEFILTER_CLASS = 'scrapy_splash.SplashAwareDupeFilter'
二、使用Splash服务
Splash功能丰富,包含多个服务端点,最常用的有两个端点:
- render.html
提供JS页面渲染服务。 - execute
执行用户自定义的渲染脚本,利用该端点可在页面中执行JS代码。
举一个简单的例子,使用scrapy_splash.SplashRequest渲染JS请求,如下:
import scrapy
from scrapy_splash import SplashRequest
class MySpider(scrapy.Spider):
# 假设这个请求的页面数据是需要执行JS才能爬取的
start_urls = ["http://example.com"]
def start_requests(self):
for url in self.start_urls:
yield SplashRequest(url, self.parse, args={'images':0,'timeout': 5})
def parse(self, response):
# ...
上述代码中,用户只需使用scrapy_splash.SplashRequest替代scrapy.Request提交请求即可完成JS渲染,并且在SplashRequest的构造器中无须传递endpoint参数,因为该参数默认值就是‘render.html’。
下面介绍下SplashRequest构造器方法中的一些常用参数。
- url
与scrapy.Request中的url相同,也就是待爬取页面的url。 - headers
与scrapy.Request中的headers相同。 - cookies
与scrapy.Request中的cookies相同。 - args
传递给Splash的参数,如wait(等待时间)、timeout(超时时间)、images(是否禁止加载图片,0禁止,1不禁止)等。 - endpoint
Splash服务端点,默认为‘render.html’,即JS页面渲染服务。 - splash_url
Splash服务器地址,默认为None,即使用settings.py配置文件中的SPLASH_URL = 'http://localhost:8050'
三、项目实战
放在下一章节讲解