百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

如何使用 Scrapy 执行 JavaScript

itomcoil 2025-02-19 12:22 15 浏览

大多数现代网站都使用客户端 JavaScript 框架,例如 React、Vue 或 Angular。在没有服务器端渲染的情况下从动态网站抓取数据通常需要执行 JavaScript 代码。

我已经抓取了数百个网站,而且我总是使用 Scrapy。Scrapy 是一个流行的 Python 网页抓取框架。与其他 Python 抓取库(例如 Beautiful Soup)相比,Scrapy 帮助您根据一些最佳实践来构建代码。Scrapy 负责并发、收集统计数据、缓存、处理重试逻辑和许多其他问题。

在本文中,我比较了使用 Scrapy 执行 JavaScript 的最流行的解决方案,包括如何扩展无头浏览器,并介绍了与 ScrapingBee API 的开源集成以支持 JavaScript 和代理轮换。

使用 Scrapy 抓取动态网站

使用 Scrapy 抓取客户端呈现的网站曾经很痛苦。我经常自己检查浏览器网络工具上的 API 请求并从 JavaScript 变量中提取数据。虽然这些 hack 可能适用于某些网站,但我发现这些代码比传统的 XPATH 更难理解和维护。但要直接从 HTML 中抓取客户端数据,您首先需要执行 JavaScript 代码。

用于无头浏览器的 Scrapy 中间件

无头浏览器是没有图形用户界面的网络浏览器。我使用了三个库来使用 Scrapy 执行 JavaScript:scrapy-selenium、scrapy-splash 和 scrapy-scrapingbee。

所有三个库都集成为 Scrapy下载器中间件。一旦在您的项目设置中进行配置,您就不会从您的spiders产生一个正常的 Scrapy 请求,而是产生一个 SeleniumRequest、SplashRequest 或 ScrapingBeeRequest。

使用 Selenium 在 Scrapy 中执行

在本地,您可以使用带有scrapy-selenium中间件的 Scrapy 与无头浏览器交互。Selenium 是一个与浏览器交互的框架,通常用于测试应用程序、网页抓取和截屏。

Selenium 需要一个Web 驱动程序来与浏览器交互。例如,Firefox 要求您安装 geckodriver。然后,您可以在 Scrapy 项目设置中配置 Selenium。



from shutil import which

SELENIUM_DRIVER_NAME = 'firefox'

SELENIUM_DRIVER_EXECUTABLE_PATH = which('geckodriver')

SELENIUM_DRIVER_ARGUMENTS=['-headless']

DOWNLOADER_MIDDLEWARES = {

    'scrapy_selenium.SeleniumMiddleware': 800

}

在你的spiders中,你可以产生一个 SeleniumRequest。

from scrapy_selenium import SeleniumRequest

yield SeleniumRequest(url, callback=self.parse)

Selenium 允许您使用 Python 和 JavaScript 与浏览器进行交互。驱动程序对象可以从 Scrapy 响应中访问。有时在单击按钮后检查 HTML 代码会很有用。在本地,您可以使用 ipdb 调试器设置断点来检查 HTML 响应。

def parse(self, response):


    driver = response.request.meta['driver']
    driver.find_element_by_id('show-price').click()


    import ipdb; ipdb.set_trace()
    print(driver.page_source)

否则,可以从响应对象访问 Scrapy XPATH 和 CSS 选择器以从 HTML 中选择数据。

def parse(self, response):
    title = response.selector.xpath(
        '//title/@text'
    ).extract_first()

SeleniumRequest 接受一些额外的参数,例如在返回响应之前等待的 wait_time,等待 HTML 元素的 wait_until,截取屏幕截图的屏幕截图和用于执行自定义 JavaScript 脚本的脚本。

在生产中,scrapy-selenium 的主要问题是没有简单的方法来设置Selenium 网格以在远程机器上运行多个浏览器实例。接下来,我将比较两种使用 Scrapy 大规模执行 JavaScript 的解决方案。

使用 Splash 在 Scrapy 中执行 JavaScript

Splash是一种带有 API 的 Web 浏览器即服务。它由 Scrapy 的主要贡献者 Scrapinghub 维护,并通过scrapy-splash中间件与 Scrapy 集成。它也可以由 Scrapinghub 托管。

Splash 创建于 2013 年,在无头 Chrome 和其他主要无头浏览器于 2017 年发布之前。从那时起,其他流行的项目(如 PhantomJS)已停止使用,转而支持 Firefox、Chrome 和 Safari 无头浏览器。

您可以使用 Docker 在本地运行 Splash 实例。

docker run -p 8050:8050 scrapinghub/splash`

配置 Splash 中间件需要添加多个中间件并在项目设置中更改 HttpCompressionMiddleware 的默认优先级。

SPLASH_URL = 'http://192.168.59.103: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'

然后你可以产生一个带有可选参数 wait 和 lua_source 的 SplashRequest。

from scrapy_splash import SplashRequest

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

Splash 是一种流行的解决方案,因为它已经推出了很长时间,但它有两个主要问题:它使用自定义的无头浏览器,并且需要在 Lua 中编码才能与网站交互。由于这两个问题,在我的最后一个抓取项目中,我决定为 ScrapingBee API 创建一个中间件。

使用 ScrapingBee 在 Scrapy 中执行 JavaScript

ScrapingBee是一个 Web 抓取 API,可以为您处理无头浏览器和代理。ScrapingBee 使用最新的无头 Chrome 版本并支持 JavaScript 脚本。

与其他两个中间件一样,您可以简单地使用 pip 安装scrapy-scrapingbee中间件。

pip install scrapy-scrapingbee

首先,您需要创建一个 ScrapingBee 帐户以获取 API 密钥。然后你可以根据你的项目设置中的 ScrapingBee 计划添加下载器中间件并设置并发。

SCRAPINGBEE_API_KEY = 'REPLACE-WITH-YOUR-API-KEY'

DOWNLOADER_MIDDLEWARES = {
    'scrapy_scrapingbee.ScrapingBeeMiddleware': 725,
}

CONCURRENT_REQUESTS = 1

然后你可以从 ScrapingBeeSpider 继承你的蜘蛛并产生一个 ScrapingBeeRequest。

from scrapy_scrapingbee import ScrapingBeeSpider, ScrapingBeeRequest

class HttpbinSpider(ScrapingBeeSpider):
    name = 'httpbin'
    start_urls = [
        'https://httpbin.org',
    ]


    def start_requests(self):
        for url in self.start_urls:
            yield ScrapingBeeRequest(url)


    def parse(self, response):
        …

ScrapingBeeRequest 采用可选的 params 参数来执行 js_snippet,在返回响应之前设置自定义等待,或者使用 wait_for 在 HTML 代码中等待 CSS 或 XPATH 选择器。

在某些网站中,当您滚动浏览页面时,HTML 会异步加载。您可以使用下面的 JavaScript 片段滚动到页面末尾。

JS_SNIPPET = 'window.scrollTo(0, document.body.scrollHeight);'

yield ScrapingBeeRequest(url, params={
           'js_snippet': JS_SNIPPET,
           # 'wait': 3000,
           # 'wait_for': '#swagger-ui',
       })

ScrapingBee 收集了其他常见的 JavaScript 片段,以便与ScrapingBee 文档中的网站进行交互。

在幕后,scraping-scrapingbee 中间件将原始请求转换为转发到 ScrapingBee API 的请求,并对 URL 查询字符串中的每个参数进行编码。API 端点记录在您的 Scrapy 日志中,并且 api_key 被 ScrapingBeeSpider 隐藏。

2020-06-22 12:32:07 [scrapy.core.engine] DEBUG: Crawled (200)  (referer: None)

在您的蜘蛛的解析方法中,中间件将 response.url 解析为传递给 ScrapingBeeRequest 的原始 URL。

def parse(self, response):
    assert response.url == 'https://httpbin.org'

使用 ScrapingBee 的另一个优点是您可以使用以下参数访问不同国家的住宅代理和开箱即用的代理轮换。

yield ScrapingBeeRequest(url, params={
   'premium_proxy': True,
   'country_code': 'fr',
})

使用 Scrapy 缓存和并发来更快地抓取

Scrapy 在底层使用了 Twisted,这是一个异步网络框架。Twisted 使 Scrapy 快速并且能够同时抓取多个页面。但是,要执行 JavaScript 代码,您需要使用真正的浏览器或无头浏览器来解析请求。无头浏览器有两个挑战:它们速度较慢且难以扩展。

在无头浏览器中执行 JavaScript 并等待所有网络调用每页可能需要几秒钟。抓取多个页面时,它会使抓取器显着变慢。希望 Scrapy 提供缓存来加速生产运行的开发和并发请求。

在本地,在开发爬虫时,您可以使用 Scrapy 的内置缓存系统。由于响应存储在计算机上的隐藏文件夹 .scrapy/httpcache 中,它将使后续运行更快。您可以在项目设置中激活 HttpCacheMiddleware:

HTTPCACHE_ENABLED = True

无头浏览器的另一个问题是它们会为每个请求消耗内存。在生产环境中,您需要一个可以处理多个浏览器的环境。要同时发出多个请求,您可以修改项目设置:

CONCURRENT_REQUESTS = 1

使用 ScrapingBee 时,请记住根据您的 ScrapingBee 计划设置并发。

结论

我比较了三个使用 Scrapy 渲染和执行 JavaScript 的 Scrapy 中间件。Selenium 允许您在所有主要的无头浏览器中使用 Python 与 Web 浏览器进行交互,但可能难以扩展。Splash 可以使用 Docker 在本地运行或部署到 Scrapinghub,但依赖于自定义浏览器实现,您必须在 Lua 中编写脚本。ScrapingBee 使用最新的 Chrome 无头浏览器,允许您在 JavaScript 中执行自定义脚本,并为最难抓取的网站提供代理轮换。


scrapy-selenium

scrapy-splash

scrapy-scrapingbee

本地运行

是的

是的,使用 Docker

远程扩展

使用Selenium Grid

使用 Scrapinghub

使用ScrapingBee

脚本语言

JavaScript、Python

lua

JavaScript

浏览器支持

Chrome, Firefox, Edge, Safari

Splash

Latest Headless Chrome

代理轮换

由另一项服务 Crawlera 提供

是的,由相同的中间件提供

相关推荐

第十章:优化设计与自动化工作流(优化设计是)

以下重点讲解优化设计、自动化脚本编写以及与其他工具(如Python、优化算法库)的集成,提升CFD仿真的工程应用效率。目标:掌握参数化扫描、优化算法集成和批量任务管理,实现从单次模拟到自动化设计探索的...

安装python语言,运行你的第一行代码

#01安装Python访问Python官方(https://www.python.org/),下载并安装最新版本的Python。确保安装过程中勾选“Addpython.exetoPAT...

Python安装(python安装的库在哪个文件夹)

Windows系统1.安装python1.1下载Python安装包打开官方网站:https://www.python.org/downloads/点击"DownloadPython3.1...

比pip快100倍的Python包安装工具(python2.7.5安装pip)

简介uv是一款开源的Python包安装工具,GitHubstar高达56k,以性能极快著称,具有以下特性(官方英文原文):Asingletooltoreplacepip,pip-tool...

【跟着豆包AI学Python】Python环境的安装,编写第一个程序

最近几年,人工智能越来越走进人们的日常生活,国内各大公司都推出了自己的AI助手,例如:阿里旗下的通义千问、百度旗下的文心一言、腾讯的腾讯元宝、深度求索的deepseek等,元宝就是字节跳动公司推出的A...

Python3+ 变量命名全攻略:PEP8 规范 + 官方禁忌...

Python3+变量命名规则与约定详解一、官方命名规则(必须遵守)1.合法字符集变量名只能包含:大小写字母(a-z,A-Z)数字(0-9)下划线(_)2.禁止数字开头合法:user_age,...

Python程序打包为EXE的全面指南:从入门到精通

引言在Python开发中,将程序打包成可执行文件(EXE)是分发应用程序的重要环节。通过打包,我们可以创建独立的可执行文件,让没有安装Python环境的用户也能运行我们的程序。本篇文章将详细介绍如何使...

别再纸上谈兵了!手把手教你安装GraalVM,让你的代码瞬间起飞!

各位老铁们,是不是每次看到我吹嘘GraalVM的各种神迹,心里都痒痒的?想让自己的Java程序秒启动?想让Python脚本跑得比平时快好几倍?想体验一把多语言无缝协作的快感?但一想到要下载、配置、敲命...

纠结坏了!从 Python 3.8 升级到 3.14 真有必要吗?

点赞、收藏、加关注,下次找我不迷路"我电脑里装的Python3.8,现在都出3.14了,要不要赶紧升级啊?会不会像手机系统更新一样,越升级越卡?"相信很多刚入门的朋友都有类...

win10下python3.13.3最新版本解释器的下载与安装

一、python3.13.3下载官方下载地址:https://www.python.org/1.浏览器访问https://www.python.org/这个地址,进入python的网站,点击【Dowl...

Python简介与开发环境搭建详细教程

1.1Python简介与开发环境搭建详细教程一、Python语言简介1.Python的核心特点2.Python的应用领域表1.1Python主要应用领域领域典型应用常用库Web开发网站后端D...

python开发小游戏案例(python游戏开发入门经典教程)

#头条创作挑战赛#假设你正在开发一个小型游戏,需要实现角色移动、障碍物生成、碰撞检测等功能。你可以使用Python和Pygame库来开发这个游戏。输入以下命令来安装Pygame:pipinstall...

Python编程:从入门到实践 第十一、二 章 武装飞船

假设我们有一个名为AnonymousSurvey的类,用于收集匿名调查的答案。该类包含以下方法:classAnonymousSurvey:def__init__(self,questi...

「Python系列」python几个重要模块的安装(二)

一、python的pygame的安装:安装地址:https://www.cnblogs.com/charliedaifu/p/9938542.htmlpyagme包下载地址:https://down...

python如何绘制消消乐小游戏(python字母消消乐)

要开发一款消消乐的小游戏界面,我们可以使用Python的pygame库。首先需要安装pygame库,然后创建一个窗口,加载游戏素材,处理游戏逻辑,以及绘制游戏界面。以下是一个简单的消消乐游戏界面实现:...