【Python】Python3网络爬虫实战-38、动态渲染页面抓取:Splash的使用

本文主要是介绍【Python】Python3网络爬虫实战-38、动态渲染页面抓取:Splash的使用,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Splash 是一个 JavaScript 渲染服务,是一个带有 HTTP API 的轻量级浏览器,同时它对接了 Python 中的 Twisted和 QT 库,利用它我们同样可以实现动态渲染页面的抓取。

1. 功能介绍

利用 Splash 我们可以实现如下功能:

  • 异步方式处理多个网页渲染过程
  • 获取渲染后的页面的源代码或截图
  • 通过关闭图片渲染或者使用 Adblock 规则来加快页面渲染速度
  • 可执行特定的 JavaScript 脚本
  • 可通过 Lua 脚本来控制页面渲染过程获取渲染的详细过程并通过 HAR(HTTP Archive)格式呈现

接下来我们来了解一下它的具体用法。

2. 准备工作

在本节开始之前请确保已经正确安装好了 Splash 并可以正常运行服务,如没有安装可以参考第一章的安装说明。

3. 实例引入

首先我们可以通过 Splash 提供的 Web 页面来测试 Splash的渲染过程,例如我们在本机 8050 端口运行了 Splash 服务,打开:http://localhost:8050/ 即可看到其 Web 页面,如图 7-6 所示:

图 7-6 Web 页面
在右侧呈现的是一个渲染示例,我们可以看到在上方有一个输入框,默认是:http://google.com,我们在这里换成百度测试一下,将内容更改为:https://www.baidu.com,然后点击按钮,开始渲染,结果如图 7-7 所示:

图 7-7 运行结果
可以看到网页的返回结果呈现了渲染截图、HAR 加载统计数据、网页的源代码。
通过 HAR 的结果我们可以看到 Splash 执行了整个网页的渲染过程,包括 CSS、JavaScript 的加载等过程,呈现的页面和我们在浏览器得到的结果完全一致。
那么这个过程是由什么来控制的呢?我们重新返回首页可以看到实际上是有一段脚本,内容如下:

function main(splash, args)
  assert(splash:go(args.url))
  assert(splash:wait(0.5))
  return {
    html = splash:html(),
    png = splash:png(),
    har = splash:har(),
  }
end
Python资源分享qun 784758214 ,内有安装包,PDF,学习视频,这里是Python学习者的聚集地,零基础,进阶,都欢迎

这个脚本是实际是 Lua 语言写的脚本,Lua也是一门编程语言,简洁易用。
即使我们不懂这个语言的语法,但通过脚本表面意思我们也可以大致了解到它是首先调用 go() 方法去加载页面,然后调用 wait() 方法等待了一定的时间,最后返回了页面的源码、截图和 HAR 信息。
所以到这里我们可以大体了解到 Splash 是通过 Lua 脚本来控制了页面的加载过程,加载过程完全模拟浏览器,最后可返回各种格式的结果,如网页源码、截图等。
所以接下来我们要学会用 Splash 的话,一是需要了解其中 Lua 脚本的写法,二是需要了解相关 API 的用法,那么接下来我们就来了解一下这两部分内容。

4. Splash Lua脚本

Splash可以通过Lua脚本执行一系列渲染操作,这样我们就可以用Splash来模拟类似Chrome、PhantomJS的操作了。
首先我们先对 Splash Lua 脚本的用法有一个基本的认识,先了解一下它的入口和执行方式。

入口及返回值

首先我们来看一个基本实例:

function main(splash, args)splash:go("http://www.baidu.com")splash:wait(0.5)local title = splash:evaljs("document.title")return {title=title}
end

我们将代码粘贴到刚才我们所打开的:http://localhost:8050/ 的代码编辑区域,然后点击按钮来测试一下。
这样我们就会看到其返回了网页的标题,这里我们是通过 evaljs() 方法传入 JavaScript 脚本,而 document.title 的执行结果就是返回网页标题,执行完毕后赋值给一个 title 变量,随后将其返回,这样就可以看到其返回结果就是网页标题了,如图 7-8 所示:

图 7-8 运行结果
注意到我们在这里定义的方法名称叫做 main(),这个名称必须是固定的,Splash 会默认调用这个方法。
方法的返回值可以是字典形式、也可以是字符串形式,最后都会转化为一个 Splash HTTP Response,例如:

function main(splash)
    return {hello="world!"}
end

这样即返回了一个字典形式的内容。

function main(splash)
    return 'hello'
end

这样即返回了一个字符串形式的内容,同样是可以的。

异步处理

Splash是支持异步处理的,但是这里我们并没有显式地指明回调方法,其回调的跳转是在Splash内部完成的,我们先来看一个例子:

function main(splash, args)
  local example_urls = {"www.baidu.com", "www.taobao.com", "www.zhihu.com"}
  local urls = args.urls or example_urls
  local results = {}
  for index, url in ipairs(urls) do
    local ok, reason = splash:go("http://" .. url)
    if ok then
      splash:wait(2)
      results[url] = splash:png()
    end
  end
  return results
end

运行后的返回结果是三个站点的截图,如图 7-9 所示:

图 7-9 运行结果
在脚本内调用了 wait() 方法,这类似于 Python 中的 sleep(),参数为等待的秒数,当 Splash 执行到此方法时,它会转而去处理其他的任务,然后在指定的时间过后再回来继续处理。
在这里值得注意的是 Lua 脚本中的字符串拼接,和 Python不同,这里的字符串拼接使用的是 … 操作符,而不是 +,如有必要可以简单了解一下Lua脚本的语法,链接:http://www.runoob.com/lua/lua…。
另外这里我们做了加载时的异常检测,go() 方法会返回加载页面的结果状态,如果页面出现 4XX 或 5XX 状态码,ok 变量就会为空,就不会返回加载后的图片。

5. Splash对象属性

我们注意到在前面的例子中 main() 方法的第一个参数是 splash,这个对象非常重要,类似于在 Selenium 中的WebDriver 对象:

from selenium import webdriver
browser = webdriver.Chrome()

如上所示,现在的 splash 对象就如同此处 Selenium 中的 browser 对象,我们可以调用它的一些属性和方法来控制加载过程,接下来我们首先看下它的属性。

args

splash 对象的 args 属性可以获取加载时配置的参数,它可以获取加载的 URL,如果为 GET 请求它还可以获取 GET 请求参数,如果为 POST 请求它可以获取表单提交的数据。Splash 支持第二个参数直接作为 args,例如:

function main(splash, args)
    local url = args.url
end

在这里第二个参数 args 就相当于 splash.args 属性,以上代码等价于:

function main(splash)
    local url = splash.args.url
end

js_enabled

这个属性是 Splash 的 JavaScript 执行开关,我们可以将其配置为 True 或 False 来控制是否可以执行 JavaScript 代码,默认为 True,例如我们在这里禁用一下 JavaScript 的执行:

function main(splash, args)
  splash:go("https://www.baidu.com")
  splash.js_enabled = false
  local title = splash:evaljs("document.title")
  return {title=title}
end

禁用之后,我们重新调用了 evaljs() 方法执行 JavaScript 代码,那么运行结果就会抛出异常:

{
    "error": 400,
    "type": "ScriptError",
    "info": {
        "type": "JS_ERROR",
        "js_error_message": null,
        "source": "[string \"function main(splash, args)\r...\"]",
        "message": "[string \"function main(splash, args)\r...\"]:4: unknown JS error: None",
        "line_number": 4,
        "error": "unknown JS error: None",
        "splash_method": "evaljs"
    },
    "description": "Error happened while executing Lua script"
}

不过一般来说我们不用设置此属性开关,默认开启即可。

resource_timeout

此属性可以设置加载的超时时间,单位是秒,如果设置为 0或 nil(类似 Python 中的 None)就代表不检测超时,我们用一个实例感受一下:

function main(splash)
    splash.resource_timeout = 0.1
    assert(splash:go('https://www.taobao.com'))
    return splash:png()
end

例如这里我们将超时时间设置为 0.1 秒,如果在 0.1 秒之内没有得到响应就会抛出异常,错误如下:

{
    "error": 400,
    "type": "ScriptError",
    "info": {
        "error": "network5",
        "type": "LUA_ERROR",
        "line_number": 3,
        "source": "[string \"function main(splash)\r...\"]",
        "message": "Lua error: [string \"function main(splash)\r...\"]:3: network5"
    },
    "description": "Error happened while executing Lua script"
}

此属性适合在网页加载速度较慢的情况下设置,如果超过了某个时间无响应则直接抛出异常并忽略即可。

images_enabled

此属性可以设置图片是否加载,默认情况下是加载的,但是禁用之后可以节省网络流量并提高网页加载速度,但是值得注意的是禁用图片加载之后可能会影响 JavaScript 渲染,因为禁用图片之后它的外层 DOM 节点的高度会受影响,进而影响 DOM 节点的位置,所以如果 JavaScript 如果使用了相关变量的话,其执行就会受到影响,不过一般情况下不会。
另外值得注意的是 Splash 使用了缓存,所以如果你一开始加载出来了网页图片,然后禁用了图片加载,然后再重新加载页面,之前加载好的图片可能还会显示出来,这时可以重启一下 Splash 即可解决。
禁用图片加载的示例如下:

function main(splash, args)
  splash.images_enabled = false
  assert(splash:go('https://www.jd.com'))
  return {png=splash:png()}
end

这样返回的页面截图就不会带有任何图片,加载速度也会快很多。

plugins

这篇关于【Python】Python3网络爬虫实战-38、动态渲染页面抓取:Splash的使用的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


原文地址:https://blog.csdn.net/weichen090909/article/details/97686660
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.chinasem.cn/article/276762

相关文章

MySQL 多列 IN 查询之语法、性能与实战技巧(最新整理)

《MySQL多列IN查询之语法、性能与实战技巧(最新整理)》本文详解MySQL多列IN查询,对比传统OR写法,强调其简洁高效,适合批量匹配复合键,通过联合索引、分批次优化提升性能,兼容多种数据库... 目录一、基础语法:多列 IN 的两种写法1. 直接值列表2. 子查询二、对比传统 OR 的写法三、性能分析

深入理解Go语言中二维切片的使用

《深入理解Go语言中二维切片的使用》本文深入讲解了Go语言中二维切片的概念与应用,用于表示矩阵、表格等二维数据结构,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来一起学习学习吧... 目录引言二维切片的基本概念定义创建二维切片二维切片的操作访问元素修改元素遍历二维切片二维切片的动态调整追加行动态

prometheus如何使用pushgateway监控网路丢包

《prometheus如何使用pushgateway监控网路丢包》:本文主要介绍prometheus如何使用pushgateway监控网路丢包问题,具有很好的参考价值,希望对大家有所帮助,如有错误... 目录监控网路丢包脚本数据图表总结监控网路丢包脚本[root@gtcq-gt-monitor-prome

Python通用唯一标识符模块uuid使用案例详解

《Python通用唯一标识符模块uuid使用案例详解》Pythonuuid模块用于生成128位全局唯一标识符,支持UUID1-5版本,适用于分布式系统、数据库主键等场景,需注意隐私、碰撞概率及存储优... 目录简介核心功能1. UUID版本2. UUID属性3. 命名空间使用场景1. 生成唯一标识符2. 数

SpringBoot中如何使用Assert进行断言校验

《SpringBoot中如何使用Assert进行断言校验》Java提供了内置的assert机制,而Spring框架也提供了更强大的Assert工具类来帮助开发者进行参数校验和状态检查,下... 目录前言一、Java 原生assert简介1.1 使用方式1.2 示例代码1.3 优缺点分析二、Spring Fr

Python办公自动化实战之打造智能邮件发送工具

《Python办公自动化实战之打造智能邮件发送工具》在数字化办公场景中,邮件自动化是提升工作效率的关键技能,本文将演示如何使用Python的smtplib和email库构建一个支持图文混排,多附件,多... 目录前言一、基础配置:搭建邮件发送框架1.1 邮箱服务准备1.2 核心库导入1.3 基础发送函数二、

Android kotlin中 Channel 和 Flow 的区别和选择使用场景分析

《Androidkotlin中Channel和Flow的区别和选择使用场景分析》Kotlin协程中,Flow是冷数据流,按需触发,适合响应式数据处理;Channel是热数据流,持续发送,支持... 目录一、基本概念界定FlowChannel二、核心特性对比数据生产触发条件生产与消费的关系背压处理机制生命周期

java使用protobuf-maven-plugin的插件编译proto文件详解

《java使用protobuf-maven-plugin的插件编译proto文件详解》:本文主要介绍java使用protobuf-maven-plugin的插件编译proto文件,具有很好的参考价... 目录protobuf文件作为数据传输和存储的协议主要介绍在Java使用maven编译proto文件的插件

Python包管理工具pip的升级指南

《Python包管理工具pip的升级指南》本文全面探讨Python包管理工具pip的升级策略,从基础升级方法到高级技巧,涵盖不同操作系统环境下的最佳实践,我们将深入分析pip的工作原理,介绍多种升级方... 目录1. 背景介绍1.1 目的和范围1.2 预期读者1.3 文档结构概述1.4 术语表1.4.1 核

PowerShell中15个提升运维效率关键命令实战指南

《PowerShell中15个提升运维效率关键命令实战指南》作为网络安全专业人员的必备技能,PowerShell在系统管理、日志分析、威胁检测和自动化响应方面展现出强大能力,下面我们就来看看15个提升... 目录一、PowerShell在网络安全中的战略价值二、网络安全关键场景命令实战1. 系统安全基线核查