Scrapy-Splash-爬虫

本文最后更新于:2021年2月5日 晚上

信息

Scrapy的Splash插件
github地址:https://github.com/scrapy-plugins/scrapy-splash
这个插件只是让Scrapy使用Splash服务而已
如果没人给你提供Splash服务,那么你需要自己弄

Splash-js渲染-爬虫

流程

安装

pip install scrapy-splash

配置

  1. settings.py中添加Splash地址

    1
    SPLASH_URL = 'http://192.168.59.103:8050'

    根据ip来,要是本地就localhost:8050

  2. settings.py中配置Downloader中间件

    1
    2
    3
    4
    DOWNLOADER_MIDDLEWARES = {
    'scrapy_splash.SplashCookiesMiddleware': 723,
    'scrapy_splash.SplashMiddleware': 725, 'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware': 810,
    }
  3. 启用Spider中间件SplashDeduplicateArgsMiddleware

    1
    2
    3
    SPIDER_MIDDLEWARES = {
    'scrapy_splash.SplashDeduplicateArgsMiddleware': 100,
    }

    这个功能需要cache_args支持。
    它能通过不保存 重复的Splash参数 节约磁盘空间
    若Splash版本2.1+,它能通过 不重复发送Splash参数 节约带宽

  4. 设置去重类DUPEFILTER_CLASS

    1
    DUPEFILTER_CLASS = 'scrapy_splash.SplashAwareDupeFilter'
  5. 如果你使用HTTP cache,那么要定义一个缓存后端

    scrapy-splash提供一个scrapy.contrib.httpcache.FilesystemCacheStorage子类

    1
    HTTPCACHE_STORAGE = 'scrapy_splash.SplashAwareFSCacheStorage'

    使用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    yield SplashRequest(url, self.parse_result, callback #任务完成之后对应的回调函数
    #args设置的是端点API的参数,关于API参数问题,请参考: `Splash HTTP API <./api.html>`_
    args={
    # 可选参数,表示spalsh在执行完成之后会等待一段时间后返回
    'wait': 0.5,
    #url是一个必须的参数,表明将要对哪个url进行请求
    'url' : "http://www.example.com",
    #http_method:表示Splash将向目标url发送何种请求
    'http_method': 'GET'
    # 'body' 用于POST请求,作为请求的请求体
    # 'lua_source' 如果需要执行lua脚本,那么这个参数表示对应lua脚本的字符串
    },
    endpoint='render.json', # optional; default is render.html
    splash_url='<url>', # optional; overrides SPLASH_URL
    slot_policy=scrapy_splash.SlotPolicy.PER_DOMAIN, # optional,
    # "meta" 是一个用来向回调函数传入参数的方式,在回调函数中的response.meta中可以取到这个地方传入的参数
    )

    如果在splash中使用lua脚本,那么args中的内容会通过main函数的 splash.args 参数传入,其余的内容会通过第二个 参数 args 传入。
    比如下面有一个简单的用户登录的例子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    lua_script= '''
    function main(splash, args)

    local ok, reason = splash:go(args.url)
    user_name = args.user_name
    user_passwd = args.user_passwd
    user_text = splash:select("#email")
    pass_text = splash:select("#pass")
    login_btn = splash:select("#loginbutton")
    if (user_text and pass_text and login_btn) then
    user_text:send_text(user_name)
    pass_text:send_text(user_passwd)
    login_btn:mouse_click({})
    end

    splash:wait(math.random(5, 10))
    return {
    url = splash:url(),
    cookies = splash:get_cookies(),
    headers = splash.args.headers,
    }
    end'''

    yield SplashRequest(
    url=self.login_url,
    endpoint="execute",
    args={
    "wait": 30,
    "lua_source": lua_script,
    "user_name": "xxxx", # 在Lua脚本中这个参数可用通过args.user_name取得
    "user_passwd": "xxxx",
    },
    meta = {"user_name" : "xxxx"},
    callback=self.after_login,
    errback=self.error_parse,
    )

    上述代码提交了一个Splash的请求,在脚本中首先获取用户名和密码的输入框元素和对应的提交按钮元素,接着填入用户名和 密码,最后点击提交并返回对应的cookie。 回调函数 after_login 的代码如下:

1
2
3
4
def after_login(self, response):
#首先根据一定条件判断登录是否成功
self.login_user = response.meta["user_name"] # 保存当前登录用户
self.cookie = response.data["cookies"] # 保存cookie

在回调函数中,可以通过response.data来获取lua脚本中返回的内容,而对应的HTML代码的获取方式与使用传统的Request方式 相同。

另外在回调函数中可以通过response.meta来获取Requestmeta传入的参数。

上述示例演示了如何使用SplashRequest来像Splash发送渲染请求,以及如何在回调函数中获取lua脚本中的返回、 以及如何在回调函数中获取lua脚本中的返回、如何向回调函数传递参数。

当然您也可以使用常规的scrapy.Request来向Splash发送请求,发送的示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
yield scrapy.Request(url, self.parse_result, meta={
'splash': {
'args': {
# 在此处设置端点API的参数
'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
}
})

splash 参数中的内容是用于splash的,使用这个参数表明我们希望向splash发送渲染请求。

最终它们会被组织成 request.meta[‘splash’] 。在scrapy处理这些请求的时候根据这个来确定是否创建spalsh的 中间件,最终请求会被中间件以HTTP API的方式转发到splash中

splash中各个参数的作用如下:

  • meta[‘splash’][‘args’] 是最终发送到splash HTTP API的参数

    • url 表示目标站点的url
    • http_method 表示向url发送的HTTP的请求方式
    • body 是采用POST方式发送请求时,请求体的内容
  • meta[‘splash’][‘cache_args’] 表示将要被作为缓冲的参数的列表字符串,以分号分隔

  • meta[‘splash’][‘endpoint’] 表示对应的端点

  • meta[‘splash’][‘splash_url’] 与settings文件中的 SPLASH_URL 作用相同,但是会优先采用这里的设置

  • meta[‘splash’][‘splash_headers’] 即将发送到splash服务器上的请求头信息,注意,这里它不是最终发送到对应站点的请求头信息