跳转到主要内容

Splash的JavaScript支持,用于Scrapy

项目描述

https://travis-ci.org/scrapy-plugins/scrapy-splash.svg?branch=master

此库提供了使用ScrapySplash进行JavaScript集成的功能。许可证是BSD 3条款。

安装

使用pip安装ScrapyJS

$ pip install scrapyjs

ScrapyJS使用Splash HTTP API,因此您还需要一个Splash实例。通常安装和运行Splash,以下内容就足够了

$ docker run -p 8050:8050 scrapinghub/splash

检查 Splash 安装文档 获取更多信息。

配置

  1. 将 Splash 服务器地址添加到 Scrapy 项目的 settings.py 中,如下所示:

    SPLASH_URL = 'http://192.168.59.103:8050'
  2. 通过将其添加到 settings.py 文件中的 DOWNLOADER_MIDDLEWARES 来启用 Splash 中间件

    DOWNLOADER_MIDDLEWARES = {
        'scrapyjs.SplashMiddleware': 725,
    }
  1. 设置自定义 DUPEFILTER_CLASS

    DUPEFILTER_CLASS = 'scrapyjs.SplashAwareDupeFilter'
  2. 如果你使用 Scrapy HTTP 缓存,则需要自定义缓存存储后端。ScrapyJS 提供了 scrapy.contrib.httpcache.FilesystemCacheStorage 的子类。

    HTTPCACHE_STORAGE = 'scrapyjs.SplashAwareFSCacheStorage'

    如果你使用其他缓存存储,则需要将其子类化,并将所有 scrapy.util.request.request_fingerprint 调用替换为 scrapyjs.splash_request_fingerprint

使用方法

要使用 Splash 渲染请求,请使用 'splash' 请求 meta

yield Request(url, self.parse_result, meta={
    'splash': {
        'args': {
            # set rendering arguments here
            'html': 1,
            'png': 1,

            # 'url' is prefilled from request url
        },

        # optional parameters
        'endpoint': 'render.json',  # optional; default is render.json
        'splash_url': '<url>',      # overrides SPLASH_URL
        'slot_policy': scrapyjs.SlotPolicy.PER_DOMAIN,
    }
})
  • meta['splash']['args'] 包含发送给 Splash 的参数。ScrapyJS 会自动将请求的 url 添加到这些参数中。

    请注意,默认情况下 Scrapy 使用 AJAX 转义方案转义 URL 片段。如果你想将带有片段的 URL 传递给 Splash,请手动在 args 字典中设置 url

  • meta['splash']['endpoint'] 是要使用的 Splash 端点。默认情况下使用 render.json

    有关可用端点和参数的完整列表,请参阅 Splash HTTP API 文档

  • meta['splash']['splash_url'] 覆盖了在 settings.py 中设置的 Splash URL。

  • meta['splash']['slot_policy'] 用于自定义维护 Splash 请求的并发性和礼貌性的方式。

    目前有 3 种策略可用

    1. scrapyjs.SlotPolicy.PER_DOMAIN (默认) - 根据正在渲染的 URL 向下载器槽位发送 Splash 请求。如果你想保持每个域的礼貌性和并发设置,这很有用。

    2. scrapyjs.SlotPolicy.SINGLE_SLOT - 向单个下载器槽位发送所有 Splash 请求。如果你想限制对 Splash 的请求,这很有用。

    3. scrapyjs.SlotPolicy.SCRAPY_DEFAULT - 不对槽位做任何事情。这与 SINGLE_SLOT 策略类似,但如果您访问与 Splash 相同地址上的其他服务,则可能会有所不同。

示例

获取 HTML 内容

import scrapy

class MySpider(scrapy.Spider):
    start_urls = ["http://example.com", "http://example.com/foo"]

    def start_requests(self):
        for url in self.start_urls:
            yield scrapy.Request(url, self.parse, meta={
                'splash': {
                    'endpoint': 'render.html',
                    'args': {'wait': 0.5}
                }
            })

    def parse(self, response):
        # response.body is a result of render.html call; it
        # contains HTML processed by a browser.
        # ...

获取 HTML 内容和截图

import json
import base64
import scrapy

class MySpider(scrapy.Spider):

    # ...
        yield scrapy.Request(url, self.parse_result, meta={
            'splash': {
                'args': {
                    'html': 1,
                    'png': 1,
                    'width': 600,
                    'render_all': 1,
                }
            }
        })

    # ...
    def parse_result(self, response):
        data = json.loads(response.body_as_unicode())
        body = data['html']
        png_bytes = base64.b64decode(data['png'])
        # ...

运行简单的 Splash Lua 脚本

import json
import base64

class MySpider(scrapy.Spider):

    # ...
        script = """
        function main(splash)
            assert(splash:go(splash.args.url))
            return splash:evaljs("document.title")
        end
        """
        yield scrapy.Request(url, self.parse_result, meta={
            'splash': {
                'args': {'lua_source': script},
                'endpoint': 'execute',
            }
        })

    # ...
    def parse_response(self, response):
        doc_title = response.body_as_unicode()
        # ...

HTTP 基本认证

如果您需要使用 HTTP 基本认证访问 Splash,请使用 Scrapy 的 HttpAuthMiddleware

为什么不直接使用 Splash HTTP API 呢?

ScrapyJS 的明显替代方案是直接向 Splash HTTP API 发送请求。请查看下面的示例,并确保阅读其后的观察结果

import json

import scrapy
from scrapy.http.headers import Headers

RENDER_HTML_URL = "http://127.0.0.1:8050/render.html"

class MySpider(scrapy.Spider):
    start_urls = ["http://example.com", "http://example.com/foo"]

    def start_requests(self):
        for url in self.start_urls:
            body = json.dumps({"url": url, "wait": 0.5})
            headers = Headers({'Content-Type': 'application/json'})
            yield scrapy.Request(RENDER_HTML_URL, self.parse, method="POST",
                                 body=body, headers=headers)

    def parse(self, response):
        # response.body is a result of render.html call; it
        # contains HTML processed by a browser.
        # ...

它工作得很好,而且足够简单,但有一些问题你应该注意

  1. 有一些样板代码。

  2. 从 Scrapy 的角度来看,我们正在向 RENDER_HTML_URL 而不是目标 URL 发送请求。它影响了并发性和礼貌性设置:CONCURRENT_REQUESTS_PER_DOMAINDOWNLOAD_DELAY 等可能会以预期之外的方式表现,因为延迟和并发设置不再是按域的。

  3. 一些选项相互依赖 - 例如,如果您使用 timeout Splash 选项,那么您可能还想设置 download_timeout scrapy.Request 元数据键。

ScrapyJS 工具允许处理此类边缘情况并减少模板代码。

贡献

源代码和错误跟踪器在github上: https://github.com/scrapy-plugins/scrapy-splash

要运行测试,安装“tox”Python包,然后从源代码签出中运行 tox 命令。

更改

0.2 (2016-03-26)

0.1.1 (2015-03-16)

修复了非字符串元值的指纹计算问题。

0.1 (2015-02-28)

初始发布

项目详情


下载文件

下载适合您平台的文件。如果您不确定选择哪个,请了解更多关于 安装包 的信息。

源代码分发

scrapyjs-0.2.tar.gz (12.7 kB 查看哈希值)

上传时间 源代码

构建分发

scrapyjs-0.2-py2.py3-none-any.whl (13.3 kB 查看哈希值)

上传时间 Python 2 Python 3

由以下机构支持