【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的使用的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/276762

相关文章

C++使用栈实现括号匹配的代码详解

《C++使用栈实现括号匹配的代码详解》在编程中,括号匹配是一个常见问题,尤其是在处理数学表达式、编译器解析等任务时,栈是一种非常适合处理此类问题的数据结构,能够精确地管理括号的匹配问题,本文将通过C+... 目录引言问题描述代码讲解代码解析栈的状态表示测试总结引言在编程中,括号匹配是一个常见问题,尤其是在

Python调用Orator ORM进行数据库操作

《Python调用OratorORM进行数据库操作》OratorORM是一个功能丰富且灵活的PythonORM库,旨在简化数据库操作,它支持多种数据库并提供了简洁且直观的API,下面我们就... 目录Orator ORM 主要特点安装使用示例总结Orator ORM 是一个功能丰富且灵活的 python O

Java中String字符串使用避坑指南

《Java中String字符串使用避坑指南》Java中的String字符串是我们日常编程中用得最多的类之一,看似简单的String使用,却隐藏着不少“坑”,如果不注意,可能会导致性能问题、意外的错误容... 目录8个避坑点如下:1. 字符串的不可变性:每次修改都创建新对象2. 使用 == 比较字符串,陷阱满

Python使用国内镜像加速pip安装的方法讲解

《Python使用国内镜像加速pip安装的方法讲解》在Python开发中,pip是一个非常重要的工具,用于安装和管理Python的第三方库,然而,在国内使用pip安装依赖时,往往会因为网络问题而导致速... 目录一、pip 工具简介1. 什么是 pip?2. 什么是 -i 参数?二、国内镜像源的选择三、如何

使用C++实现链表元素的反转

《使用C++实现链表元素的反转》反转链表是链表操作中一个经典的问题,也是面试中常见的考题,本文将从思路到实现一步步地讲解如何实现链表的反转,帮助初学者理解这一操作,我们将使用C++代码演示具体实现,同... 目录问题定义思路分析代码实现带头节点的链表代码讲解其他实现方式时间和空间复杂度分析总结问题定义给定

Linux使用nload监控网络流量的方法

《Linux使用nload监控网络流量的方法》Linux中的nload命令是一个用于实时监控网络流量的工具,它提供了传入和传出流量的可视化表示,帮助用户一目了然地了解网络活动,本文给大家介绍了Linu... 目录简介安装示例用法基础用法指定网络接口限制显示特定流量类型指定刷新率设置流量速率的显示单位监控多个

JavaScript中的reduce方法执行过程、使用场景及进阶用法

《JavaScript中的reduce方法执行过程、使用场景及进阶用法》:本文主要介绍JavaScript中的reduce方法执行过程、使用场景及进阶用法的相关资料,reduce是JavaScri... 目录1. 什么是reduce2. reduce语法2.1 语法2.2 参数说明3. reduce执行过程

如何使用Java实现请求deepseek

《如何使用Java实现请求deepseek》这篇文章主要为大家详细介绍了如何使用Java实现请求deepseek功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1.deepseek的api创建2.Java实现请求deepseek2.1 pom文件2.2 json转化文件2.2

python使用fastapi实现多语言国际化的操作指南

《python使用fastapi实现多语言国际化的操作指南》本文介绍了使用Python和FastAPI实现多语言国际化的操作指南,包括多语言架构技术栈、翻译管理、前端本地化、语言切换机制以及常见陷阱和... 目录多语言国际化实现指南项目多语言架构技术栈目录结构翻译工作流1. 翻译数据存储2. 翻译生成脚本

Android 悬浮窗开发示例((动态权限请求 | 前台服务和通知 | 悬浮窗创建 )

《Android悬浮窗开发示例((动态权限请求|前台服务和通知|悬浮窗创建)》本文介绍了Android悬浮窗的实现效果,包括动态权限请求、前台服务和通知的使用,悬浮窗权限需要动态申请并引导... 目录一、悬浮窗 动态权限请求1、动态请求权限2、悬浮窗权限说明3、检查动态权限4、申请动态权限5、权限设置完毕后