返回博客
指南
Mihai MaximLast updated on Mar 31, 20261 min read

如何使用 Scrapy 执行 JavaScript

如何使用 Scrapy 执行 JavaScript

引言

欢迎来到动态网站抓取的精彩世界!正如您可能从我们之前的文章中了解到的那样,使用传统的网页抓取工具来处理这类网站可能会有些棘手。但请放心!Scrapy 作为您值得信赖的网页抓取助手,凭借各种插件和库,能让动态网站抓取变得轻而易举。

本文将深入探讨使用 Scrapy 抓取 JavaScript 驱动网站时最受欢迎的几种方案。为了让您更轻松上手,我们将提供每种方案的示例,助您自信地应对任何网站。

如果您是 Scrapy 的新手,也无需担心。您可以参考我们的指南,了解如何使用 Scrapy 进行网页抓取

无头浏览器?

如果您对无头浏览器不熟悉,让我为您解释一下。简而言之,这是一种不显示可见界面的网页浏览器。是的,我知道在使用时看不到浏览器窗口听起来很奇怪。但请相信我,在网页抓取领域,无头浏览器确实能带来革命性的改变。

原因如下:与仅显示网页的普通浏览器不同,无头浏览器能够执行 JavaScript。这意味着,如果你试图抓取一个依赖 JavaScript 生成内容的网站,无头浏览器可以通过执行 JavaScript 并让你抓取生成的 HTML 来提供帮助。

探索不同的解决方案

使用 Scrapy 渲染 JavaScript 的最佳策略取决于您的具体需求和资源。如果预算紧张,您需要选择一种性价比高的方案。使用无头浏览器或 JavaScript 渲染库可能是成本最低的选择,但您仍需应对 IP 被封禁的风险,以及维护和运行该方案的成本。

建议尝试几种不同的方案,以确定哪一种最适合您的具体用例。

如何使用 Splash 在 Scrapy 中执行 JavaScript

Splash 是一款专为网络爬虫设计的轻量级无头浏览器。它基于 WebKit 引擎,该引擎同样驱动着 Safari 浏览器。Splash 的优势在于易于配置,尤其是配合 Docker 使用时。它还通过 scrapy-splash 中间件与 Scrapy 集成。

要使用该中间件,您首先需要通过 pip 安装此包:

$ pip install scrapy-splash

使用 Docker 配置 Splash 非常简单。您只需在本地机器上通过 Docker 运行一个 Splash 实例(https://docs.docker.com/get-docker/)。

$ docker run -p 8050:8050 scrapinghub/splash

之后,您应该能够通过 http://localhost:8050/ 访问本地 Splash 实例

Splash 提供了一个 REST API,使其能够轻松与 Scrapy 或任何其他网络爬虫工具配合使用。您可以在 Scrapy 控制台中发送一个 fetch 请求来测试服务器:

fetch('http://localhost:8050/render.html?url=<target_url>')

要配置中间件,请在 settings.py 文件中添加以下几行代码。

SPLASH_URL = 'http://localhost:8050'

DOWNLOADER_MIDDLEWARES = {

    'scrapy_splash.SplashCookiesMiddleware': 723,

    'scrapy_splash.SplashMiddleware': 725,

    'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware': 810,

}

SPIDER_MIDDLEWARES = {

    'scrapy_splash.SplashDeduplicateArgsMiddleware': 100,

}

DUPEFILTER_CLASS = 'scrapy_splash.SplashAwareDupeFilter'

HTTPCACHE_STORAGE = 'scrapy_splash.SplashAwareFSCacheStorage'

访问 https://github.com/scrapy-plugins/scrapy-splash 以了解各项设置的详细说明。

使用 Splash 渲染请求的最简单方法是在您的蜘蛛(spider)中使用 scrapy_splash.SplashRequest:

import scrapy

from scrapy_splash import SplashRequest

class RandomSpider(scrapy.Spider):

    name = 'random_spider'

    def start_requests(self):

        start_urls = [

        '<first_url',

        '<second_url>'

       ]

        for url in start_urls:

           yield SplashRequest(url=url, callback=self.parse, args={'wait': 5})

    def parse(self, response):

       

            result = response.css("h3::text").extract()

         

            yield result

您可以添加一个“wait”参数,指定 Splash 在返回请求前需要等待的时间。

使用 Splash 的一个潜在缺点是,它需要借助 Lua 脚本语言来执行点击按钮、填写表单和跳转页面等操作。

如何使用 Selenium 通过 Scrapy 执行 JavaScript

您可以将 Scrapy 与 Selenium WebDriver 结合使用。scrapy-selenium 中间件通过将 Selenium WebDriver 注入请求流程来工作,从而将生成的 HTML 返回给蜘蛛进行解析。

在实施此方案前,请注意:您需要安装 Web 驱动程序才能与浏览器交互。例如,若要使用 Selenium 配合 Firefox,则需安装 geckodriver。安装 Web 驱动程序后,您可在 Scrapy 项目设置中配置 Selenium:

SELENIUM_DRIVER_NAME = 'firefox'

SELENIUM_DRIVER_EXECUTABLE_PATH = which('geckodriver')

SELENIUM_DRIVER_ARGUMENTS=['-headless']  # '--headless' if using chrome instead of firefox

DOWNLOADER_MIDDLEWARES = {

    'scrapy_selenium.SeleniumMiddleware': 800

}

ITEM_PIPELINES = {

    'myproject.pipelines.SanitizePipeline': 1,

}

随后即可配置您的爬虫:

import scrapy

from scrapy_selenium import SeleniumRequest

class RandomSpider(scrapy.Spider):

    name = 'random_spider'

    def start_requests(self):

        start_urls = [

        '<first_url',

        '<second_url>'

       ]

        for url in start_urls:

            yield SeleniumRequest(url=url, callback=self.parse)

    def parse(self, response):

            print(response.request.meta['driver'].title)

            #The request will be handled by selenium, and the request will have an additional meta key, named driver containing the selenium driver with the request processed.

       

            result = response.selector.css("#result::text").extract()

            #The selector response attribute work as usual (but contains the  html processed by the selenium driver).

         

            yield result

有关可用驱动程序方法和属性的更多信息,请参阅 Selenium Python 文档:

http://selenium-python.readthedocs.io/api.html#module-selenium.webdriver.remote.webdriver

由于 Selenium 并非独立的无头浏览器,因此运行 Selenium 的机器上必须安装 Web 浏览器。这使得在多台机器或云环境中部署和运行 Selenium 变得较为困难。

如何使用 WebScrapingApi 通过 Scrapy 执行 JavaScript

WebScrapingAPI 提供了一个 API,可为您处理所有繁重的工作。它能执行 JavaScript、轮换代理,甚至处理 CAPTCHA,确保您能轻松抓取网站。 此外,您再也不必担心因发送过多请求而导致 IP 被封禁。为了配置 Scrapy 与 WebScrapingAPI 协同工作,我们将配置一个代理中间件,将所有 fetch 请求通过 WSA 进行隧道传输。

为此,我们将配置 Scrapy 使其连接到 WSA 代理服务器:

import base64

# add this to your middlewares.py file

class WSAProxyMiddleware:

    def process_request(self, request, spider):

        # Set the proxy for the request

        request.meta['proxy'] = "http://proxy.webscrapingapi.com:80"

        request.meta['verify'] = False

        # Set the proxy authentication for the request

        proxy_user_pass = "webscrapingapi.render_js=1:<API_KEY>"

        encoded_user_pass = base64.b64encode(proxy_user_pass.encode()).decode()

        request.headers['Proxy-Authorization'] = f'Basic {encoded_user_pass}'

并启用中间件:

DOWNLOADER_MIDDLEWARES = {

    'myproject.middlewares.WSAProxyMiddleware': 1,

}

webscrapingapi.render_js=1 是代理认证的用户名,<API_KEY> 是密码。

您可通过在 https://www.webscrapingapi.com/ 创建新账户获取免费的 API_KEY

通过指定 render_js=1 参数,您将启用 WebScrapingAPI 的功能,使其能够使用无头浏览器访问目标网页,这允许在向您返回最终抓取结果之前渲染 JavaScript 页面元素。

您还可以指示 WSA 在处理 URL 时执行特定操作。您可以通过指定 js_instructions 参数来实现:

js_instructions=[

{"action":"click","selector":"button#log-in-button"}

]

// 此代码段可用于点击按钮

就这样,WSA 现在将自动为您完成所有请求。

总结

抓取动态网站可能是一项艰巨的任务,但有了合适的工具,它就会变得容易得多。在本文中,我们探讨了使用 Scrapy 抓取动态网站的三种不同方案。像 Splash 和 Selenium 这样的无头浏览器允许你像普通浏览器一样执行 JavaScript 并渲染网页。 不过,若想走捷径,使用 WebScrapingApi 这样的 API 也是绝佳的解决方案。它能为您处理所有复杂任务,让您即使从最棘手的网站也能轻松提取数据。无论选择哪种方案,关键在于根据具体需求,挑选最适合您项目的解决方案。感谢阅读,祝您爬取顺利!

关于作者
Mihai Maxim, 全栈开发工程师 @ WebScrapingAPI
Mihai Maxim全栈开发工程师

米海·马克西姆(Mihai Maxim)是 WebScrapingAPI 的全栈开发工程师,他在产品各领域均有贡献,并协助为该平台构建可靠的工具和功能。

开始构建

准备好扩展您的数据收集规模了吗?

加入2,000多家企业,使用WebScrapingAPI在无需任何基础设施开销的情况下,以企业级规模提取网络数据。