在本篇文章里小编给大家整理的是关于Python3爬虫中Splash的知识总结内容,需要的朋友们可以学习参考下。
Splash是一个JavaScript渲染服务,是一个带有HTTP API的轻量级浏览器,同时它对接了Python中的Twisted和QT库。利用它,我们同样可以实现动态渲染页面的抓取。
1. 功能介绍
・利用Splash,我们可以实现如下功能:
・异步方式处理多个网页渲染过程;
・获取渲染后的页面的源代码或截图;
・通过关闭图片渲染或者使用Adblock规则来加快页面渲染速度;
・可执行特定的JavaScript脚本;
・可通过Lua脚本来控制页面渲染过程;
・获取渲染的详细过程并通过HAR(HTTP Archive)格式呈现。
接下来,我们来了解一下它的具体用法。
2. 准备工作
在开始之前,请确保已经正确安装好了Splash并可以正常运行服务。如果没有安装,可以参考第1章。
3. 实例引入
首先,通过Splash提供的Web页面来测试其渲染过程。例如,我们在本机8050端口上运行了Splash服务,打开http://localhost:8050/即可看到其Web页面,如图7-6所示。
图7-6 Web页面
在图7-6右侧,呈现的是一个渲染示例。可以看到,上方有一个输入框,默认是http://google.com,这里换成百度测试一下,将内容更改为https://www.baidu.com,然后点击Render me按钮开始渲染,结果如图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
这个脚本实际上是用Lua语言写的脚本。即使不懂这个语言的语法,但从脚本的表面意思,我们也可以大致了解到它首先调用go()方法去加载页面,然后调用wait()方法等待了一定时间,最后返回了页面的源码、截图和HAR信息。
到这里,我们大体了解了Splash是通过Lua脚本来控制了页面的加载过程的,加载过程完全模拟浏览器,最后可返回各种格式的结果,如网页源码和截图等。
接下来,我们就来了解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/的代码编辑区域,然后点击Render me!按钮来测试一下。
我们看到它返回了网页的标题,如图7-8所示。这里我们通过evaljs()方法传入JavaScript脚本,而document.title的执行结果就是返回网页标题,执行完毕后将其赋值给一个title变量,随后将其返回。
图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
运行结果是3个站点的截图,如图7-9所示。
图7-9 运行结果
在脚本内调用的wait()方法类似于Python中的sleep(),其参数为等待的秒数。当Splash执行到此方法时,它会转而去处理其他任务,然后在指定的时间过后再回来继续处理。
这里值得注意的是,Lua脚本中的字符串拼接和Python不同,它使用的是..操作符,而不是+。如果有必要,可以简单了解一下Lua脚本的语法,详见http://www.runoob.com/lua/lua-basic-syntax.html。
另外,这里做了加载时的异常检测。go()方法会返回加载页面的结果状态,如果页面出现4xx或5xx状态码,ok变量就为空,就不会返回加载后的图片。
5. Splash对象属性
我们注意到,前面例子中main()方法的第一个参数是splash,这个对象非常重要,它类似于Selenium中的WebDriver对象,我们可以调用它的一些属性和方法来控制加载过程。接下来,先看下它的属性。
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 exe<i style="color:transparent">来源gaodai$ma#com搞$$代**码网</i>cuting 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_enabled
此属性可以控制浏览器插件(如Flash插件)是否开启。默认情况下,此属性是false,表示不开启。可以使用如下代码控制其开启和关闭:
splash.plugins_enabled = true/false
scroll_position
通过设置此属性,我们可以控制页面上下或左右滚动。这是一个比较常用的属性,示例如下:
function main(splash, args) assert(splash:go('https://www.taobao.com')) splash.scroll_position = {y=400} return {png=splash:png()} end
这样我们就可以控制页面向下滚动400像素值,结果如图7-10所示。
图7-10 运行结果
如果要让页面左右滚动,可以传入x参数,代码如下:
splash.scroll_position = {x=100, y=200}
6. Splash对象的方法
除了前面介绍的属性外,Splash对象还有如下方法。
go()
该方法用来请求某个链接,而且它可以模拟GET和POST请求,同时支持传入请求头、表单等数据,其用法如下:
ok, reason = splash:go{url, baseurl=nil, headers=nil, http_method="GET", body=nil, formdata=nil}
其参数说明如下。
url:请求的URL。
baseurl:可选参数,默认为空,表示资源加载相对路径。
headers:可选参数,默认为空,表示请求头。
http_method:可选参数,默认为GET,同时支持POST。
body:可选参数,默认为空,发POST请求时的表单数据,使用的Content-type为application/json。
formdata:可选参数,默认为空,POST的时候的表单数据,使用的Content-type为application/x-www-form-urlencoded。
该方法的返回结果是结果ok和原因reason的组合,如果ok为空,代表网页加载出现了错误,此时reason变量中包含了错误的原因,否则证明页面加载成功。示例如下:
function main(splash, args) local ok, reason = splash:go{"http://httpbin.org/post", http_method="POST", body="name=Germey"} if ok then return splash:html() end end
这里我们模拟了一个POST请求,并传入了POST的表单数据,如果成功,则返回页面的源代码。
运行结果如下:
<pre>{ "args": {}, "data": "", "files": {}, "form": { "name": "Germey" }, "headers": { "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "Accept-Encoding": "gzip, deflate", "Accept-Language": "en,*", "Connection": "close", "Content-Length": "11", "Content-Type": "application/x-www-form-urlencoded", "Host": "httpbin.org", "Origin": "null", "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/602.1 (KHTML, like Gecko) splash Version/9.0 Safari/602.1" }, "json": null, "origin": "60.207.237.85", "url": "http://httpbin.org/post" }
可以看到,我们成功实现了POST请求并发送了表单数据。
wait()
此方法可以控制页面的等待时间,使用方法如下:
ok, reason = splash:wait{time, cancel_on_redirect=false, cancel_on_error=true}
参数说明如下。
time:等待的秒数。
cancel_on_redirect:可选参数,默认为false,表示如果发生了重定向就停止等待,并返回重定向结果。
cancel_on_error:可选参数,默认为false,表示如果发生了加载错误,就停止等待。
返回结果同样是结果ok和原因reason的组合。
我们用一个实例感受一下:
function main(splash) splash:go("https://www.taobao.com") splash:wait(2) return {html=splash:html()} end
这可以实现访问淘宝并等待2秒,随后返回页面源代码的功能。
jsfunc()
此方法可以直接调用JavaScript定义的方法,但是所调用的方法需要用双中括号包围,这相当于实现了JavaScript方法到Lua脚本的转换。示例如下:
function main(splash, args) local get_div_count = splash:jsfunc([[ function () { var body = document.body; var divs = body.getElementsByTagName('div'); return divs.length; } ]]) splash:go("https://www.baidu.com") return ("There are %s DIVs"):format( get_div_count()) end
运行结果如下:
There are 21 DIVs
首先,我们声明了一个JavaScript定义的方法,然后在页面加载成功后调用了此方法计算出了页面中div节点的个数。
关于JavaScript到Lua脚本的更多前端的相关知识总结的文章就介绍到这了,更多前端的相关知识内容请搜索gaodaima搞代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持gaodaima搞代码网!
以上就是Python3爬虫中Splash的知识总结的详细内容,更多请关注gaodaima搞代码网其它相关文章!