专栏名称: 崔庆才丨静觅
工程师
目录
相关文章推荐
51好读  ›  专栏  ›  崔庆才丨静觅

Scrapy框架的使用之Scrapy对接Splash

崔庆才丨静觅  · 掘金  ·  · 2018-05-18 03:37

正文

Scrapy框架的使用之Scrapy对接Splash

在上一节我们实现了Scrapy对接Selenium抓取淘宝商品的过程,这是一种抓取JavaScript动态渲染页面的方式。除了Selenium,Splash也可以实现同样的功能。本节我们来了解Scrapy对接Splash来进行页面抓取的方式。

一、准备工作

请确保Splash已经正确安装并正常运行,同时安装好Scrapy-Splash库。

二、新建项目

首先新建一个项目,名为scrapysplashtest,命令如下所示:

scrapy startproject scrapysplashtest

新建一个 Spider,命令如下所示:

scrapy genspider taobao www.taobao.com

三、添加配置

可以参考Scrapy-Splash的配置说明进行一步步的配置,链接如下:https://github.com/scrapy-plugins/scrapy-splash#configuration。

修改settings.py,配置 SPLASH_URL 。在这里我们的Splash是在本地运行的,所以可以直接配置本地的地址:

SPLASH_URL = 'http://localhost:8050'

如果Splash是在远程服务器运行的,那此处就应该配置为远程的地址。例如运行在IP为120.27.34.25的服务器上,则此处应该配置为:

SPLASH_URL = 'http://120.27.34.25:8050'

还需要配置几个Middleware,代码如下所示:

DOWNLOADER_MIDDLEWARES = {
    'scrapy_splash.SplashCookiesMiddleware': 723,
    'scrapy_splash.SplashMiddleware': 725,
    'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware': 810,
}
SPIDER_MIDDLEWARES = {
    'scrapy_splash.SplashDeduplicateArgsMiddleware': 100,
}

这里配置了三个Downloader Middleware和一个Spider Middleware,这是Scrapy-Splash的核心部分。我们不再需要像对接Selenium那样实现一个Downloader Middleware,Scrapy-Splash库都为我们准备好了,直接配置即可。

还需要配置一个去重的类 DUPEFILTER_CLASS ,代码如下所示:

DUPEFILTER_CLASS = 'scrapy_splash.SplashAwareDupeFilter'

最后配置一个Cache存储 HTTPCACHE_STORAGE ,代码如下所示:

HTTPCACHE_STORAGE = 'scrapy_splash.SplashAwareFSCacheStorage'

四、新建请求

配置完成之后,我们就可以利用Splash来抓取页面了。我们可以直接生成一个 SplashRequest 对象并传递相应的参数,Scrapy会将此请求转发给Splash,Splash对页面进行渲染加载,然后再将渲染结果传递回来。此时Response的内容就是渲染完成的页面结果了,最后交给Spider解析即可。

我们来看一个示例,如下所示:

yield SplashRequest(url, self.parse_result,
    args={
        # optional; parameters passed to Splash HTTP API
        'wait': 0.5,
        # 'url' is prefilled from request url
        # 'http_method' is set to 'POST' for POST requests
        # 'body' is set to request body for POST requests
    },
    endpoint='render.json', # optional; default is render.html
    splash_url='<url>',     # optional; overrides SPLASH_URL
)

这里构造了一个 SplashRequest 对象,前两个参数依然是请求的URL和回调函数。另外我们还可以通过 args 传递一些渲染参数,例如等待时间 wait 等,还可以根据 endpoint 参数指定渲染接口。更多参数可以参考文档说明:https://github.com/scrapy-plugins/scrapy-splash#requests。

另外我们也可以生成Request对象,Splash的配置通过 meta 属性配置即可,代码如下:

yield scrapy.Request(url, self.parse_result, meta={
    'splash': {
        'args': {
            # set rendering arguments here
            'html': 1,
            'png': 1,
            # 'url' is prefilled from request url
            # 'http_method' is set to 'POST' for POST requests
            # 'body' is set to request body for POST requests
        },
        # optional parameters
        'endpoint': 'render.json',  # optional; default is render.json
        'splash_url': '<url>',      # optional; overrides SPLASH_URL
        'slot_policy': scrapy_splash.SlotPolicy.PER_DOMAIN,
        'splash_headers': {},       # optional; a dict with headers sent to Splash
        'dont_process_response': True, # optional, default is False
        'dont_send_headers': True,  # optional, default is False
        'magic_response': False,    # optional, default is True
    }
})

SplashRequest 对象通过 args 来配置和Request对象通过 meta 来配置,两种方式达到的效果是相同的。

本节我们要做的抓取是淘宝商品信息,涉及页面加载等待、模拟点击翻页等操作。我们可以首先定义一个Lua脚本,来实现页面加载、模拟点击翻页的功能,代码如下所示:

function main(splash, args)
  args = {
    url="https://s.taobao.com/search?q=iPad",
    wait=5,
    page=5
  }
  splash.images_enabled = false
  assert(splash:go(args.url))
  assert(splash:wait(args.wait))
  js = string.format("document.querySelector('#mainsrp-pager div.form > input').value=%d;document.querySelector('#mainsrp-pager div.form > span.btn.J_Submit').click()", args.page)
  splash:evaljs(js)
  assert(splash:wait(args.wait))
  return splash:png()
end

我们定义了三个参数:请求的链接 url 、等待时间 wait 、分页页码 page 。然后禁用图片加载,请求淘宝的商品列表页面,通过 evaljs() 方法调用JavaScript代码,实现页码填充和翻页点击,最后返回页面截图。我们将脚本放到Splash中运行,正常获取到页面截图,如下图所示。

翻页操作也成功实现,如下图所示即为当前页码,和我们传入的页码 page 参数是相同的。







请到「今天看啥」查看全文