在之前的章节中, 爬取的都是静态页面中的信息, 随着越来越多的网站开始用 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'
三项目实战
放在下一章节讲解
来源: http://www.jianshu.com/p/e54a407c8a0a