Splash脚本参考¶
注解
虽然这个参考十分全面,但是它很难作为入门的内容。如果您是初学状态,或者看不懂下面的内容, 请您首先查阅 Splash lua API概览 这部分的内容
splash
作为main函数的第一个参数被传进来,通过这个对象脚本可以控制浏览器。您可以将它看做一个单一浏览器标签的API [9]
属性¶
splash.args¶
splash.args
是一个传入参数的table类型,它包含了来自GET请求的原始url的合并值和 数据类型为 application/json
的POST请求的请求体的值
例如您在使用 Splash HTTP API的时候在脚本的参数中添加了一个url参数,那么 splash.args.url
就包含了您传入的这个URL [10]
您也可以将 splash.args
作为main函数的第二个参数传入:
function main(splash, args)
local url = args.url
-- ...
end
它等效于:
function main(splash)
local url = splash.args.url
-- ...
end
使用 args
或者 splash.args 是向Splash脚本传递参数的首选。另一个方式是通过字符串格式化将参数作为嵌入的变量
来构造lua脚本的字符串。但是相比与使用splash.args 来说,这种方法有两个问题
splash.js_enabled¶
允许或者禁止执行嵌入到页面中的JavaScript代码
原型: splash.js_enabled = true/false
默认情况下允许执行JavaScript代码
splash.private_mode_enabled¶
开启或者关闭 浏览器的私有模式(匿名模式)
原型: splash.private_mode_enabled = true/false
默认情况下匿名模式是开启的,除非您使用 --disable-private-mode
选项来启动Splash,请注意如果您关闭了匿名模式,某些请求数据可能会在
浏览器中持续存在(但是它并不影响cookie)
您也可以参考 如果关闭匿名模式
splash.resource_timeout¶
第二次设定网络请求的超时值
原型: splash.resource_timeout = number
例如,下面的例子演示了当请求远端的资源超过10s时异常告警
function main(splash)
splash.resource_timeout = 10.0
assert(splash:go(splash.args.url))
return splash:png()
end
当值为0或者 nil
时表示没有设置超时值
在设置请求的超时值事,在 splash:on_request 函数中使用 request:set_timeout
设置的超时值要优先于
splash.resource_timeout
splash.images_enabled¶
是否加载图片
原型: splash.images_enabled = true/false
默认情况下运行加载图片,禁止加载图片能节省大量的网络带宽(通常在50%左右)并且能提高渲染的速度。请注意这个选项可能会影响页面中JavaScript代码 的执行:禁止加载图片可能会影响DOM元素的坐标或者大小,而在脚本中可能会读取并使用它们
splash在使用缓存的情况下,如果禁止了图片的加载,当缓存中存储了对应的图片,图片就会被加载。所以可能造成的问题是当您在允许图片加载的情况下 加载了一个页面,然后禁止图片加载,接着再加载一个新页面,此时您可能会看到,第一个页面加载了图片,而第二个页面加载的部分图片 (被加载的是与第一个页面相同的图片)。在同一个进程中splash的缓存是可以被不同的脚本共享的,所以您可能会在某些页面中看到部分图片 即使您在一开始就禁止了图片的加载
示例
function main(splash, args)
splash.images_enabled = false
assert(splash:go(splash.args.url))
return {png=splash:png()}
end
splash.response_body_enabled¶
启用或者禁止响应内容追踪
原型: splash.response_body_enabled = true/false
从效率上考虑,默认情况下Splash不会在内存中保存每个请求的响应内容。这就意味着在函数 splash:on_response
的回调函数中,我们无法获取到 response.body 属性,同时也无法从
HAR 中获取到响应的对应内容。可以通过在lua脚本中设置 splash.response_body_enabled = true
来使响应内容变得有效
请注意,不管 splash.response_body_enabled 是否设置,在:ref:splash:http_get <splash-http-get> 和 splash:http_post 中总是能获取到 response.body 的内容
您可以通过在函数 splash:on_request 的回调中设置 request:enable_response_body 来启用每个请求的响应内容跟踪
splash.scroll_position¶
设置或者获取当前滚动的位置
原型: splash.scroll_position = {x=..., y=...}
这个属性允许我们设置或者获取当前主窗口的滚动的位置
将窗口滚动到内容以外是没有意义的,例如您设置 splash.scroll_position
为 {x=-100, y=-100}
效果与 splash.scroll_position
默认的 {x=0, y=0}
相同
在设置滚动位置的时候,您不用写全(例如, splash.scroll_position = {x=100, y=200}
) 您可以简写成 splash.scroll_position = {100, 200}
。
即使您使用的简写的方式,属性值也会被作为一个键为 x
和 y
的table
当然,您也可以省略您不想改变的坐标值,例如 splash.scroll_position = {y=200}
是将y的值改为200,而x的值保持不变
splash.indexeddb_enabled¶
允许或者禁止 IndexedDB
原型: splash.indexeddb_enabled = true/false
默认情况下 IndexedDB 是被禁止的。您可以使用 splash.indexeddb_enabled = true
来开启它
注解
在当前默认情况下 IndexedDB 是被禁止的,这是因为它在WebKit中存在一些问题,可能在未来它会被默认打开
splash.webgl_enabled¶
启用或者禁用 WebGL
原型: splash.webgl_enabled = true/false
WebGL 默认是启用的,您可以通过 splash.webgl_enabled = false
来禁用
splash.html5_media_enabled¶
禁止或者启用HTML5 多媒体,包括HTML5中的video 和audio (例如 <video>
标签进行回放)
原型: splash.html5_media_enabled = true/false
默认情况下 HTML5标签是被禁用的,您可以设置 splash.html5_media_enabled = true
来启用
注解
默认情况下HTML5 被禁止,因为它在某些环境下会使WebKit在访问某些网站时崩溃。在未来它可能会被设置为 true
。如果在您的程序中不需要使用
HTML5,请您明确的设置它为 false
您也可以参考 splash.html5_media_enabled 这个HTTP API参数的内容
splash.media_source_enabled¶
允许或者禁止 多媒体资源扩展API
原型: splash.media_source_enabled = true/false
多媒体资源在默认情况下是打开的,您可以使用 splash.media_source_enabled = false
来关闭它
方法¶
splash:go¶
跳转到一个URL,它的效果类似于在浏览器的地址栏中输入一个url,然后按回车键等待页面加载
原型:
ok, reason = splash:go{url, baseurl=nil, headers=nil, http_method="GET", body=nil, formdata=nil}
参数:
- url: 需要加载的页面的url
- baseurl: 这个参数为可选参数。当给定了
baseurl
参数后,页面仍然从url
参数中加载,但是它呈现为,页面中资源的相对路径是相对于baseurl来说的。,而且浏览器会认为baseurl在地址栏中。 - headers: 一个由lua table结构表示的http请求头,它被用来新增或者替换初始请求中的头信息
- http_method : 可选参数,它使用一个字符来表示如果请求url所表示的页面,默认为GET,splash同样支持POST
- body: 可选参数,它是POST请求中的body部分的字符串
- formdata: 可选参数,类型为lua中的table,当POST请求中的
Content-Type
为content-type: application/x-www-form-urlencoded
时,它会进行相应的编码,并作为POST请求的body部分。
返回值: ok
, reason
元组 [12]。如果在加载页面的过程中发生错误那么 ok
为空。reason
将会保存错误的类型信息
异步: 为异步操作,除非导航被锁
将会报告的5种错误类型( ok
会为 nil
的5种情况)
- 发生网络错误,主机不存在,失去与远程服务端的连接等等。在这种情况下
reason
为"network<code>"
。可以在 QT 的文档中找到对应的错误码,比如``network3`` 表示NDS错误(无效的主机名称) - spalsh返回带有 4xx 或者 5xx 状态码的HTTP响应信息。在这种情况下
reason
的值为http<code>
。例如当发生 HTTP 404 Not Found 时,reason
的值为"http404"
- 导航被锁住(请参阅 splash:lock_navigation ) 。此时
reason
的值为"navigation_locked"
- splash 不能加载主页面(例如第一个请求被丢弃)
reason
的值为render_error
- 如果splash不能确定是哪种错误,会简单的返回一个
error
请看下面的例子
local ok, reason = splash:go("http://example.com")
if not ok then
if reason:sub(0,4) == 'http' then
-- handle HTTP errors
else
-- handle other errors
end
end
-- process the page
-- assert can be used as a shortcut for error handling
assert(splash:go("http://example.com"))
只有当主页 [11] 请求失败时才会上报一个错误(ok==nil)。如果针对其中的相关资源的请求失败 splash:go
不会上报错误。为了确定上述错误
是否发生或者处理这些错误(像image/js/css 等链接加载失败,ajax请求失败),您可以使用 splash.har
和 splash:on_response
splash:go
在返回结果之前会一直跟随HTTP的重定向去请求其中的链接,但是它不会跟踪像 <meta http-equiv="refresh" ...>
这样在HTML中定义的重定向或者 在JavaScript代码中的跳转。此时您可以使用方法 splash:wait 进行等待,
以便使浏览器跳转到对应的页面上
headers
参数允许添加或者修改初始HTTP请求中的 header 值,您可以使用 splash:set_custom_headers 和
splash:on_request 来为以后所有的请求设置header的值(包括后续针对对应资源文件的请求)
下面是一个自定义设置header的例子:
local ok, reason = splash:go{"http://example.com", headers={
["Custom-Header"] = "Header Value",
}})
headers中的 User-Agent项比较特殊,一旦使用他将被保留并用于进一步的请求。这是一个实现的细节,我们可能在未来的版本中对这个特性进行修改。 在设置User-Agent 时,推荐使用方法 splash:set_user_agent
splash:wait¶
等待对应的时间(单位为秒),使程序等待WebKit 对网页进行进一步的处理
原型: ok, reason = splash:wait{time, cancel_on_redirect=false, cancel_on_error=true}
参数:
- time: 等待的时间,单位为s
- cancel_on_redirect: 如果它为true(默认为false) 并且在加载主页面的时候发生了重定向,
splash:wait
函数会提前返回,返回值为nil "redirect"
.但是在 HTML中通过<meta http-equiv="refresh" ...>
定义的重定向或者在JavaScript中的重定向不受影响 - cancel_on_error: 如果它为true(默认为true) 在等待时如果发生相关错误导致页面无法加载(像WebKit内部的错误或者重定向到了一个无法解析的主机上),此时
splash:wait
会提前退出并返回nil, "<error string>"
返回值: ok, reason
元组, 如果 ok
的值为 nil
,函数可能会提前退出,reason
可能会返回一个包含错误信息的字符串
是否为异步: 异步
使用示例
-- go to example.com, wait 0.5s, return rendered html, ignore all errors.
function main(splash)
splash:go("http://example.com")
splash:wait(0.5)
return {html=splash:html()}
end
默认情况下当重定向发生的时候计时器会继续计时,cancel_on_redirect
选项可以在每次重定向发生的时候让计时器重新计时.
例如下面这个函数演示了如何利用 cancel_on_redirect
来实现每次重定向并加载对应页面后等待对应的时间
function wait_restarting_on_redirects(splash, time, max_redirects)
local redirects_remaining = max_redirects
while redirects_remaining > 0 do
local ok, reason = self:wait{time=time, cancel_on_redirect=true}
if reason ~= 'redirect' then
return ok, reason
end
redirects_remaining = redirects_remaining - 1
end
return nil, "too_many_redirects"
end
splash:jsfunc¶
将JavaScript 函数转化为lua可调用的函数
原型: lua_func = splash:jsfunc(func)
参数:
- func: 包含js函数代码的字符串
返回值: 返回一个函数,该函数可以被lua执行并且可以在页面上下文中执行JavaScript代码
是否为异步: 否
例子
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(args.url)
return ("There are %s DIVs in %s"):format(
get_div_count(), args.url)
end
请注意,如果您了解lua 字符串中关于 [[ ]]
的语法知识将会对您理解这些代码有一定的帮助
JavaScript代码也可以接受参数
local vec_len = splash:jsfunc([[
function(x, y) {
return Math.sqrt(x*x + y*y)
}
]])
return {res=vec_len(5, 4)}
全局的JavaScript 函数可以被直接包含进来
local pow = splash:jsfunc("Math.pow")
local twenty_five = pow(5, 2) -- 5#2 is 25
local thousand = pow(10, 3) -- 10#3 is 1000
lua类型 到JavaScript之间的转化规则
Lua | JavaScript |
---|---|
string | string |
number | number |
boolean | boolean |
table | Object or Array, see below |
nil | undefined |
Element | DOM node |
lua中的 strings, numbers, booleans 和 tables类型的数据可以直接作为参数传入, 它们会被转化成js的 strings/numbers/booleans/objects 类型。 element 也是被支持的。 但是这类数据不能被放到lua的table中
就目前来说,不能传递其他的lua对象,比如不能往一个闭包的JavaScript函数中穿入一个闭包的JavaScript函数或者正常的lua函数作为参数
默认情况下lua中的table类型被转化为JavaScript中的object类型。如果您要将一个table类型转化为数组类型,可以使用函数 treat.as_array
JavaScript类型到lua对象的转化
Lua | JavaScript |
---|---|
string | string |
number | number |
boolean | boolean |
Object | table |
Array | table, 将其转化为数组(请参阅 treat.as_array ) |
undefined | nil |
null | “” (一个空字符串) |
Date | string: 一个使用ISO8601标砖表示的日期字符串, 例如. 1958-05-21T10:12:00.000Z |
Node | Element实例 |
NodeList | 一个由 Element 对象组成的 table |
function | nil |
circular object | nil |
host object | nil |
函数会将返回结果中的JavaScript类型转化为lua类型,它只支持一些简单的JavaScript类型的转化, 例如如果从闭包中返回一个函数或者jQuery 选择器,这种操作不被支持
当需要返回一个节点(html DOM元素的一个引用)或者节点的列表(document.querySelectorAll函数返回的结果)时, 只能返回节点或者节点列表这样单一的内容,它们不能被包含进数组或者其他的结构中
注解
经验法则:如果参数或者返回值能被序列化为json格式的话,那样最好,当然您也可以在函数中返回节点或者节点的 列表,但是它们不能被包含在其他结构中 [13] 。
请注意目前您不能返回jQuery $结果或者从JavaScript到lua的类似结构 [14] 。 要传递数据必须将您感兴趣的属性提取为普通的字符串/数字/对象/数组
-- 这个函数假设jQuery已经在页面中加载
local get_hrefs = splash:jsfunc([[
function(sel){
return $(sel).map(function(){return this.href}).get();
}
]])
local hrefs = get_hrefs("a.story-title")
当然您也可以在代码中使用 Element 对象和 splash:select_all
local elems = splash:select_all("a.story-title")
local hrefs = {}
for i, elem in ipairs(elems) do
hrefs[i] = elem.node:getAttribute("href")
end
函数的参数和返回值都是按值传递, 比如说您在JavaScript函数中修改了某个参数的值,作为函数调用者的lua代码是不知道的,您在js代码 中返回某个全局的js对象,并在lua中对它进行修改也不会影响到页面上下文。 Element 对象是一个例外,它里面有一些可变的字段。
如果 JavaScript抛出一个错误,它会作为一个lua错误,处理它最好的方式是在JavaScript代码中使用try/catch , 因为在JavaScript转lua的过程中可能存在数据的丢失
您也可以参考: splash:runjs , splash:evaljs , splash:wait_for_resume , splash:autoload , treat.as_array , Element Object , splash:select , splash:select_all .
splash:evaljs¶
在页面上下文中执行JavaScript代码并返回最后一条语句的结果
原型: result = splash:evaljs(snippet)
参数:
- snippet :一段可以执行的JavaScript代码的字符串
返回值: 返回 snippet 中最后一条语句的结果,并将这个结果有JavaScript的类型转化为lua对应的类型 。 如果发生JavaScript异常或者语法错误,则会引发错误。
是否异步: 否
JavaScript到lua的转化规则与 splash:jsfunc 相同
在只需要执行一小段代码而不用涉及到闭包函数的时候,使用 splash.eveljs
将会十分方便, 例如
local title = splash:evaljs("document.title")
当您不需要返回值的时候不要使用 splash:jsfunc 。这种方式十分低效,而且可能会带来一些问题 可以使用 splash:runjs 来代替。例如下面这段无辜的代码(使用 using jQuery)可能会做无用功
splash:evaljs("$(console.log('foo'));")
这段代码的一个问题是,它允许链接 jQuery $ 函数返回一个巨大的对象, 接着 splash:evaljs 尝试对其 进行序列化并将它转化为lua对象,这是一种对资源的浪费,但是 splash:jsfunc 不会出现这个问题
如果您经过评估发现您的代码需要使用参数,相比于使用 splash:evaljs 和格式化字符串的方式来说,使用 splash:jsfunc 将会是一种更好的选择。 请对比下面这段代码
function main(splash)
local font_size = splash:jsfunc([[
function(sel) {
var el = document.querySelector(sel);
return getComputedStyle(el)["font-size"];
}
]])
local font_size2 = function(sel)
-- FIXME: escaping of `sel` parameter!
local js = string.format([[
var el = document.querySelector("%s");
getComputedStyle(el)["font-size"]
]], sel)
return splash:evaljs(js)
end
-- ...
end
请参考: splash:runjs, splash:jsfunc , splash:wait_for_resume, splash:autoload , Element Object, splash:select, splash:select_all .
splash:runjs¶
在页面上下文中执行JavaScript代码
原型: ok, error = splash:runjs(snippet)
参数:
- snippet: 一段可以被执行的JavaScript代码的字符串
返回值: ok, error
的元组,如果执行结果正常 ok
的值为 True
, 如果JavaScript 代码发生错误,ok
的值为 nil
并且``error`` 是一个描述错误信息的字符串
是否异步: 否
示例
assert(splash:runjs("document.title = 'hello';"))
请注意使用语法 function foo(){}
定义的函数的作用返回并不是全局的
assert(splash:runjs("function foo(){return 'bar'}"))
local res = splash:evaljs("foo()") -- 此处会返回一个错误
这是一个实现的细节:传递给 splash:runjs 的代码是在闭包中执行的,您可以使用下面的方式来定义全局 函数和变量
assert(splash:runjs("foo = function (){return 'bar'}"))
local res = splash:evaljs("foo()") -- 这个位置将会返回 'bar'
如果代码中需要参数,使用 splash:jsfunc 将会是一个更好的选择
请对比下面的代码
function main(splash)
-- 滚动窗口到 (x, y) 位置的lua函数.
function scroll_to(x, y)
local js = string.format(
"window.scrollTo(%s, %s);",
tonumber(x),
tonumber(y)
)
assert(splash:runjs(js))
end
-- 一个简单的使用 splash:jsfunc的示例代码
local scroll_to2 = splash:jsfunc("window.scrollTo")
-- ...
end
您也可以参考: splash:runjs , splash:jsfunc, splash:autoload , splash:wait_for_resume
splash:wait_for_resume¶
以异步的方式在页面上下文中执行JavaScript代码,直到JavaScript代码告诉它恢复,Lua脚本才会恢复然后继续执行
原型: result, error = splash:wait_for_resume(snippet, timeout)
参数:
- snippet: 一个可以被执行的JavaScript代码的字符串,这段代码必须包含一个可被调用的main函数,main函数的第一个参数是一个包含了
resume``和 ``error
属性的对象,resume是一个可以用来恢复lua执行的函数,它传入一个可选参数,这个参数将会以result.value
的形式返回到lua中,error
是一个函数,当发生错误时会调用这个函数并返回一段包含错误信息字符串 - timeout: 它是一个数值,它决定了在强制返回到lua代码之前运行JavaScript代码运行多长时间(以秒为单位),默认值是0,这表示将禁用这个超时
返回值: result, error
的元组。当代码成功执行,result
是一个table,如果返回的值在JavaScript中未定义,
则会在 result
中包含一个由 splash.resume(…)
返回的键值 。 result
也可以包含由 splash.set(…)
添加进来的
键值对。如果执行JavaScript代码超时, result
的值将会为 nil
并且 error
会包含一个错误信息的字符串
是否为异步 : 是
例子:
第一个小例子主要演示如何将代码执行的控制权由lua转移到JavaScript,最后返回到lua中。这个命令主要告诉JavaScript代码休眠3s,然后 返回到lua中来,请注意:它使用异步的方式来执行,lua事件循环和JavaScript事件循环将在暂停3s之后再运行。但是lua代码会一直等到JavaScript 代码调用``splash.resume()`` 才会继续执行当前函数
function main(splash)
local result, error = splash:wait_for_resume([[
function main(splash) {
setTimeout(function () {
splash.resume();
}, 3000);
}
]])
-- 返回值为 {}
-- 错误值为 nil
end
返回值被设置为空的table,通过 splash.resume
函数未返回任何值。即使JavaScript 代码未返回任何值,您也可以使用
assert(splash:wait_for_resume(…))
因为对 assert()
返回空表表示为真
注解
请注意,您的JavaScript代码必须包含main 函数,如果您不包含它,将会得到一个错误。当然main函数的第一个参数的名称您可以随便取 在这份文档中为了方便我们将称它为splash
第二个例子将演示如果通过JavaScript代码返回对应的值到lua中,您可以返回布尔类型、数字类型、字符串类型、数组类型和JavaScript对象
function main(splash)
local result, error = splash:wait_for_resume([[
function main(splash) {
setTimeout(function () {
splash.resume([1, 2, 'red', 'blue']);
}, 3000);
}
]])
-- result is {value={1, 2, 'red', 'blue'}}
-- error is nil
end
注解
与 splash:evaljs 类似, 注意不要返回太大的JavaScript对象,类似于jQuery中的 $
。
太大的对象在转化为lua时会消耗大量的时间和内存
您也可以通过使用函数 splash.set(key, value)
来在JavaScript代码中添加键值对,新增的键值对将会被包含在 result
中
返回到lua。下面的代码就演示了这种情况
function main(splash)
local result, error = splash:wait_for_resume([[
function main(splash) {
setTimeout(function () {
splash.set("foo", "bar");
splash.resume("ok");
}, 3000);
}
]])
-- result is {foo="bar", value="ok"}
-- error is nil
end
下面的例子将演示一种 splash:wait_for_resume()
错误的调用方式, JavaScript代码中不包含main函数,此时 result
值为
nil
因为 splash.resume()
函数永远不会被调用, error
会返回一条包含错误信息的字符串来说明这个错误
function main(splash)
local result, error = splash:wait_for_resume([[
console.log('hello!');
]])
-- result is nil
-- error is "error: wait_for_resume(): no main() function defined"
end
下面一个例子将展示如何进行错误处理, 如果 splash.error(…)
代替 splash.resume()
被调用, result
返回值将会
是 nil
而 error
将会包含一个由 splash.error(…)
给出的错误信息
function main(splash)
local result, error = splash:wait_for_resume([[
function main(splash) {
setTimeout(function () {
splash.error("Goodbye, cruel world!");
}, 3000);
}
]])
-- result is nil
-- error is "error: Goodbye, cruel world!"
end
您的JavaScript代码在某一时刻只能调用 splash.resume()
或者 splash.error()
中的任意一个。
随后对这两个函数的调用都不起作用。下面这个例子展示了这一特性
function main(splash)
local result, error = splash:wait_for_resume([[
function main(splash) {
setTimeout(function () {
splash.resume("ok");
splash.resume("still ok");
splash.error("not ok");
}, 3000);
}
]])
-- result is {value="ok"}
-- error is nil
end
下面的例子将演示timeout参数的影响。我们将超时设置为1s,但是JavaScript代码中 splash.resume()
函数将在3s后执行。
这样确保 splash:wait_for_resume()
一定会超时.
当超时发生时 result
将会为 nil, error
将会包含一个字符串来解释超时,并且lua代码将会继续执行,在超时后调用 splash.resume()
或者
splash.error()
不起任何作用
function main(splash)
local result, error = splash:wait_for_resume([[
function main(splash) {
setTimeout(function () {
splash.resume("Hello, world!");
}, 3000);
}
]], 1)
-- result is nil
-- error is "error: One shot callback timed out while waiting for resume() or error()."
end
注解
超时值必须要 >= 0, 如果超时值为0 splash:wait_for_resume()
永远不会超时(但是Splash’s HTTP API中设置的超时仍然有用)
请确保您的JavaScript代码没有因为超时而被强制结束,它可能会一直执行,直到splash关闭浏览器的页面上下文。
您可以参考: splash:runjs , splash:jsfunc , splash:evaljs
splash:autoload¶
设置JavaScript代码在每个页面加载时自动加载
原型: ok, reason = splash:autoload{source_or_url, source=nil, url=nil}
参数:
- source_or_url: 可以是一段JavaScript代码的字符串或者是JavaScript代码所对应的url,以便在页面加载时执行
- source: 一段JavaScript代码的字符串
- url: 一个用于加载JavaScript源码的url
返回值: ok, reason
元组
是否异步: 是。 只有当远程资源的url被传递时采用的是异步
splash:autoload 允许在每个页面被加载时执行JavaScript代码,splash:autoload 并不会自己执行JavaScript代码,如果您想只执行一次JavaScript代码或者在页面加载完成之后执行,请使用 splash:runjs 或者 splash:jsfunc
splash.autoload 可以在页面加载之前预加载有用的JavaScript库,或者在页面要使用某些JavaScript对象 之前先替换这些对象
例子
function main(splash, args)
splash:autoload([[
function get_document_title(){
return document.title;
}
]])
assert(splash:go(args.url))
return splash:evaljs("get_document_title()")
end
为了方便,当 splash.autoload 第一个参数以 “http” 或者以 “https://” 开头时,认为它传进来的是一个URL. 示例2-确定某个远程的库是可达的
function main(splash, args)
assert(splash:autoload("https://code.jquery.com/jquery-2.1.3.min.js"))
assert(splash:go(splash.args.url))
local version = splash:evaljs("$.fn.jquery")
return 'JQuery version: ' .. version
end
您可以使用 “url” 或者 “source”参数来防止函数自己判断参数
splash:autoload{url="https://code.jquery.com/jquery-2.1.3.min.js"}
splash:autoload{source="window.foo = 'bar';"}
当参数不变时通过这种方式来禁止函数进行参数判断是一个很好的使用方式
如果 splash.autoload 多次被调用,那么所有的脚本都会在页面被加载时调用
如果不想每次页面加载都执行这段JavaScript代码可以使用 splash:autoload_reset
您可以参考: splash:evaljs , splash:runjs, splash:jsfunc, splash:wait_for_resume , splash:autoload_reset
splash:autoload_reset¶
取消先前通过函数 splash:autoload 向页面上下文中注册的所有JavaScript代码
原型: splash:autoload_reset()
返回值: nil
是否为异步: 否
当调用了 splash:autoload_reset 之后,之前使用 splash:autoload 注册的函数在后续的请求中将不再被执行。 您可以再次使用 splash:autoload 来设置一组不同的脚本代码
已经加载了的脚本将不会被移出当前的页面上下文
您可以参考 splash:autoload
splash:call_later¶
安排一些回调函数在对应的延迟时间过后再调用。
原型: timer = splash:call_later(callback, delay)
参数:
- callback:需要被执行的函数
- delay: 延迟时间
返回值: 一个允许取消挂起计时器的句柄或者注册回调时产生的异常
是否异步: 否
例子1-在页面开始加载后的1.5s和2.5s分别获取一段HTML代码
function main(splash, args)
local snapshots = {}
local timer = splash:call_later(function()
snapshots["a"] = splash:html()
splash:wait(1.0)
snapshots["b"] = splash:html()
end, 1.5)
assert(splash:go(args.url))
splash:wait(3.0)
timer:reraise()
return snapshots
end
splash:call_later 返回一个句柄(计时器) 如果需要取消任务,可以使用 timer:cancel()
。
如果一个回调已经开始,调用 timer:cancel()
将不会起作用
默认情况下,当通过 splash:call_later 注册的回调中发生错误,回调将会停止执行,但是这不影响main函数
中脚本的执行,您可以使用 timer:reraise()
来抛出异常
splash:call_later 定义的回调函数将会在后续执行,即使延迟时间为0它们也不会立即执行,当延迟为0时, 不早于当前函数产生的事件循环,即不早于某些异步函数被调用
splash:http_get¶
发送一个HTTP的GET请求,并返回一个未经过浏览器加载的响应
原型: response = splash:http_get{url, headers=nil, follow_redirects=true}
[15]
参数:
- url: 请求的url
- headers: 一个用户新增或者替换初始请求头的lua table类型
- follow_redirects: 是否跟随重定向
返回值: 返回一个 Response 对象
是否异步: 是
例子
local reply = splash:http_get("http://example.com")
该函数调用不会修改当前页面中的上下文环境和URL,如果要通过浏览器来加载web页面,请调用函数 splash:go
您可以参考: splash:http_post , Response Object
splash:http_post¶
发送一个HTTP的POST请求,并返回一个未经过浏览器加载的响应
原型: response = splash:http_post{url, headers=nil, follow_redirects=true, body=nil}
参数:
- url: 请求的url
- headers: 一个用户新增或者替换初始请求头的lua table类型
- follow_redirects: 是否跟随重定向
- body: 用字符串表示的请求的请求体,如果您打算将数据提交到表单,body应该进行url编码
返回值: 返回一个 Response 对象
是否异步: 是 一个提交form表单的例子
local reply = splash:http_post{url="http://example.com", body="user=Frank&password=hunter2"}
-- reply.body contains raw HTML data (as a binary object)
-- reply.status contains HTTP status code, as a number
-- see Response docs for more info
一个关于JSON的例子
json = require("json")
local reply = splash:http_post{
url="http://example.com/post",
body=json.encode({alpha="beta"}),
headers={["content-type"]="application/json"}
}
该函数调用不会修改当前页面中的上下文环境和URL,如果要通过浏览器来加载web页面,请调用函数 splash:go
您可以参考: splash:http_post , json , Response Object
splash:set_content¶
设置当前页面的上下文环境,并且等待直到页面加载
原型: ok, reason = splash:set_content{data, mime_type="text/html; charset=utf-8", baseurl=""}
参数:
- data: 新的页面上下文
- mime_type: 上下文的 MIME 类型
- baseurl: 页面中引用的外部对象的相对路径通过baseurl来定位
返回值: ok, reason
的元组,如果 ok
为空,表明在加载页面的时候发生了一些异常,reason
包含的发生的错误的类型信息
是否为异步: 是
例子
function main(splash)
assert(splash:set_content("<html><body><h1>hello</h1></body></html>"))
return splash:png()
end
splash:html¶
返回整个页面的HTML代码(以字符串的形式返回)
原型: html = splash:html()
返回值: 页面内容(以字符串的形式)
是否异步: 否
例子:
-- A simplistic implementation of render.html endpoint
function main(splash)
splash:set_result_content_type("text/html; charset=utf-8")
assert(splash:go(splash.args.url))
return splash:html()
end
没有什么能阻止我们获取多个HTML快照。例如我们先加载一个站点的3个页面,为每个页面存储它初始的HTML快照,然后等待0.5s,再加载下一个
treat = require("treat")
-- Given an url, this function returns a table
-- with the page screenshoot, it's HTML contents
-- and it's title.
function page_info(splash, url)
local ok, msg = splash:go(url)
if not ok then
return {ok=false, reason=msg}
end
local res = {
html=splash:html(),
title=splash:evaljs('document.title'),
image=splash:png(),
ok=true,
}
return res
end
function main(splash, args)
-- visit first 3 pages of hacker news
local base = "https://news.ycombinator.com/news?p="
local result = treat.as_array({})
for i=1,3 do
local url = base .. i
result[i] = page_info(splash, url)
end
return result
end
splash:png¶
返回当前页面指定尺寸的屏幕截图
原型: png = splash:png{width=nil, height=nil, render_all=false, scale_method='raster', region=nil}
参数:
- width: 可选值,以像素为单位的截图的宽
- height: 可选值, 以像素为单位的截图的高
- render_all: 可选值, 如果为
true
则返回整个页面的截图 - scale_method: 可选值, 调整图片大小时所以用的方法,取值为
'raster'``(位图) 和 ``'vector'
矢量图 - region: 可选值,
{left, top, right, bottom}
表示的裁剪矩形的坐标
返回值: 以 binary object 形式返回的PNG截图,
如果结果为空会返回 nil
是否为异步: 否
如果不传参数,splash:png()
则会返回当前视框的截图
width 参数设置返回图片的宽度,如果视口的宽度与设置的宽度不同,图片会放大或者缩小,匹配指定的图片大小。例如假设视口的宽度为 1024px
而设置 splash:png{width=100}
将会返回一个完整视口的截图,但是图片会被缩小到宽度为 100px
height 参数设置返回图片的高度,视口的高度与设置的高度不同,图片会被裁剪或者扩展以便匹配指定大小,但是不调整图片内容的大小。 通过这种扩展创建的区域是透明的。
您可以使用 splash:set_viewport_size , splash:set_viewport_full
或者使用参数 render_all 来对视口进行设置 render_all = true
相当于在开始渲染前调用 splash:set_viewport_full()
然后再恢复视口大小
您可以使用 region 参数来指定截取渲染页面的哪个部分,它是一个由 {left, top, right, bottom}
组成的table对象。它的坐标
值与当前滚动的位置有关,目前传入的坐标值必须在视口中。您可以在渲染前调用 splash:set_viewport_full
接着再调用 splash:png
来确保您传入的坐标值永远在视口中。在后续的splash版本中可能会修复这个问题
使用 region
参数或者使用 一小段JavaScript代码很容易实现只渲染某一个HTML DOM元素,例如下面的例子
-- This in an example of how to use lower-level
-- Splash functions to get element screenshot.
--
-- In practice use splash:select("a"):png{pad=32}.
-- this function adds padding around region
function pad(r, pad)
return {r[1]-pad, r[2]-pad, r[3]+pad, r[4]+pad}
end
function main(splash, args)
-- this function returns element bounding box
local get_bbox = splash:jsfunc([[
function(css) {
var el = document.querySelector(css);
var r = el.getBoundingClientRect();
return [r.left, r.top, r.right, r.bottom];
}
]])
-- main script
assert(splash:go(splash.args.url))
assert(splash:wait(0.5))
-- don't crop image by a viewport
splash:set_viewport_full()
-- let's get a screenshot of a first <a>
-- element on a page, with extra 32px around it
local region = pad(get_bbox("a"), 32)
return splash:png{region=region}
end
另一种简单的方法是使用 element:png
splash:select('#my-element'):png()
scale_method 参数的值必须是 'raster'
或者 'vector'
其中的一个,当 scale_method='raster'
时,图像是按照
像素来调整大小的,当 scale_method='vector'
时,在渲染过程中图像按照每个元素来调整大小. 矢量缩放更加高效,而且图像
更加清晰, 但是它可能导致渲染失真,所以请谨慎的使用这种方式
splash:png
返回的是 一个二进制对象 binary object , 因此您可
以直接将其作为返回值在main函数中返回,它将作为二进制图像数据与 适当的content-type头一起返回:
-- A simplistic implementation of render.png
-- endpoint.
function main(splash, args)
assert(splash:go(args.url))
return splash:png{
width=args.width,
height=args.height
}
end
splash:png()
的结果将会作为一个table对象进行返回, 它会以base64的方式进行编码以便嵌入到json数据中,在客户端中创建一个 data:uri
function main(splash)
assert(splash:go(splash.args.url))
return {png=splash:png()}
end
当图片为空时,splash:png 返回 nil
, 如果您想splash抛出一个错误,请使用 assert
function main(splash)
assert(splash:go(splash.args.url))
local png = assert(splash:png())
return {png=png}
end
您可以参考 splash:jpeg , Binary Objects , splash:set_viewport_size , splash:set_viewport_full , element:jpeg , element:png
splash:jpeg¶
返回指定尺寸的屏幕截图,以JPEG格式返回
原型: jpeg = splash:jpeg{width=nil, height=nil, render_all=false, scale_method='raster', quality=75, region=nil}
参数:
- width: 可选值,以像素为单位的截图的宽
- height: 可选值, 以像素为单位的截图的高
- render_all: 可选值, 如果为
true
则返回整个页面的截图 - scale_method: 可选值, 调整图片大小时所以用的方法,取值为
'raster'``(位图) 和 ``'vector'
矢量图 - quality: 可选值,返回JPEG图片的质量, 取1 到 100的整数值
- region: 可选值,
{left, top, right, bottom}
表示的裁剪矩形的坐标
返回值: 以 binary object 形式返回的JPEG截图,
width 参数设置返回图片的宽度,如果视口的宽度与设置的宽度不同,图片会放大或者缩小,匹配指定的图片大小。例如假设视口的宽度为 1024px
而设置 splash:jpeg{width=100}
将会返回一个完整视口的截图,但是图片会被缩小到宽度为 100px
height 参数设置返回图片的高度,视口的高度与设置的高度不同,图片会被裁剪或者扩展以便匹配指定大小,但是不调整图片内容的大小。 通过这种扩展创建的区域是透明的。
您可以使用 splash:set_viewport_size , splash:set_viewport_full
或者使用参数 render_all 来对视口进行设置 render_all = true
相当于在开始渲染前调用 splash:set_viewport_full()
然后再恢复视口大小
您可以使用 region 参数来指定截取渲染页面的哪个部分,它是一个由 {left, top, right, bottom}
组成的table对象。它的坐标
值与当前滚动的位置有关,目前传入的坐标值必须在视口中。您可以在渲染前调用 splash:set_viewport_full
接着再调用 splash:jpeg
来确保您传入的坐标值永远在视口中。在后续的splash版本中可能会修复这个问题
使用一小段JavaScript代码配合 region
参数可以实现只截取单一HTML DOM元素图片的功能,您可以参考 splash:png
文档中的 例子 。另一种方法是使用 element:jpeg
scale_method 参数的值必须是 'raster'
或者 'vector'
其中的一个,当 scale_method='raster'
时,图像是按照
像素来调整大小的,当 scale_method='vector'
时,在渲染过程中图像按照每个元素来调整大小. 矢量缩放更加高效,而且图像
更加清晰, 但是它可能导致渲染失真,所以请谨慎的使用这种方式
quality 参数的值必须是 0
到 100
之间的整数值, 当这个数值超过 95
时需要特别注意, quality=100
会禁用部分
JPEG的压缩算法, 并会产生一个大文件,而这个文件对图像质量的增益几乎没有任何效益
splash:jpeg
返回的是 一个二进制对象 binary object , 因此您可
以直接将其作为返回值在main函数中返回,它将作为二进制图像数据与 适当的content-type头一起返回:
-- A simplistic implementation of render.jpeg endpoint
function main(splash, args)
assert(splash:go(args.url))
return splash:jpeg{
width=args.width,
height=args.height
}
end
splash:jpeg()
的结果将会作为一个table对象进行返回, 它会以base64的方式进行编码以便嵌入到json数据中,在客户端中创建一个 data:uri
function main(splash)
assert(splash:go(splash.args.url))
return {jpeg=splash:jpeg()}
end
当图片为空时,splash:jpeg 返回 nil
, 如果您想splash抛出一个错误,请使用 assert
function main(splash)
assert(splash:go(splash.args.url))
local jpeg = assert(splash:jpeg())
return {jpeg=jpeg}
end
您可以参考 splash:png , Binary Objects , splash:set_viewport_size , splash:set_viewport_full , element:jpeg , element:png
请注意在 1.2..5x 版本之后, splash:jpeg
的速度要优于 splash:png
splash:har¶
原型: har = splash:har{reset=false}
参数:
- reset: 可选值, 当值为
true
时,每次拍快照之前会清除之前的记录
返回值: 返回页面加载的相关信息,发生的事件,发送的网络请求以及请求的响应信息,这些信息都被存储成 HAR 格式
是否异步: 否
您可以使用 splash:har 来获取关于网络请求的信息和splash的其他行为。如果您的脚本在顶层的 “har” 键中返回了 splash:har() 得到的结果,在splash UI中将会以很好的格式展示这些数据(就像 Firefox中的 “Network” 选项卡或者 Chrome 中的 开发者工具)
function main(splash)
assert(splash:go(splash.args.url))
return {har=splash:har()}
end
默认情况下当某些请求被创建(例如 splash:go 函数被多次调用), HAR数据会被累计并组合成单个对象。(日志仍然按页面进行分组)
如果您只想更新对应信息,请使用 reset
参数,它会清理之前所有已存在的日志,然后重新开始记录
function main(splash, args)
assert(splash:go(args.url1))
local har1 = splash:har{reset=true}
assert(splash:go(args.url2))
local har2 = splash:har()
return {har1=har1, har2=har2}
end
默认情况下,返回的HAR数据不包含响应体的内容,您可以使用 splash.response_body_enabled 属性或者 request:enable_response_body 方法
您也可以参考: splash:har_reset , splash:on_response , splash.response_body_enabled , request:enable_response_body .
splash:har_reset¶
原型: splash:har_reset()
返回值: nil
是否异步: 否
删除所有内部存储的 HAR 记录, 它与使用 splash:har{reset=true}
相似,但是不返回任何值
您可以参考 splash:har
splash:history¶
原型: entries = splash:history()
返回值: 返回页面加载时的请求与响应信息,以 HAR entries 格式返回
是否异步: 否
splash:history
返回中不包含相关资源的信息,像图片,脚本,样式或者AJAX请求,如果您需要这方面的信息,
请使用 splash:har 或者 splash:on_response .
让我们来获取一个JSON数组,其中包含我们想显示的响应头的信息
function main(splash)
assert(splash:go(splash.args.url))
local entries = splash:history()
-- #entries means "entries length"; arrays in Lua start from 1
local last_entry = entries[#entries]
return {
headers = last_entry.response.headers
}
end
您可以参考: splash:har, splash:on_response
splash:get_cookies¶
原型: cookies = splash:get_cookies()
返回值: 返回CookieJar 的内容, 一个包含所有脚本可用的cookie的数组, 结果以 HAR cookies 格式返回
是否异步: 否
一个返回值的例子
[
{
"name": "TestCookie",
"value": "Cookie Value",
"path": "/",
"domain": "www.example.com",
"expires": "2016-07-24T19:20:30+02:00",
"httpOnly": false,
"secure": false,
}
]
splash:add_cookie¶
添加一个cookie
原型: cookies = splash:add_cookie{name, value, path=nil, domain=nil, expires=nil, httpOnly=nil, secure=nil}
是否异步: 否
例子
function main(splash)
splash:add_cookie{"sessionid", "237465ghgfsd", "/", domain="http://example.com"}
splash:go("http://example.com/")
return splash:html()
end
splash:init_cookies¶
通过传入的cookie 来重新设置当前cookie
原型: splash:init_cookies(cookies)
参数:
- cookies: 一个用lua的table表示的需要设置的cookie值,与 splash:get_cookies 返回值的格式相同
返回值: nil
是否异步: 否
例1:保存并重新设置cookie
local cookies = splash:get_cookies()
-- ... do something ...
splash:init_cookies(cookies) -- restore cookies
例2:手工初始化cookie
splash:init_cookies({
{name="baz", value="egg"},
{name="spam", value="egg", domain="example.com"},
{
name="foo",
value="bar",
path="/",
domain="localhost",
expires="2016-07-24T19:20:30+02:00",
secure=true,
httpOnly=true,
}
})
-- do something
assert(splash:go("http://example.com"))
splash:clear_cookies¶
清理所有的cookie
原型: n_removed = splash:clear_cookies()
返回值: 返回被删除cookie的数量
是否异步: 否
如果只删除指定的cookie请使用 splash:delete_cookies
splash:delete_cookies¶
删除指定的cookie
原型: n_removed = splash:delete_cookies{name=nil, url=nil}
参数:
- name: 字符串类型,可选参数;所有name值为此值的cookie都将被删除
- url: 字符串类型,可选参数,所有应该发送到此地址的cookie将被删除
返回值: 被删除的cookie的个数
当name和url都为nil的时候,这个函数不做任何事情,您可以使用 splash:clear_cookies 来删除所有cookie
splash:set_result_status_code¶
设置返回给客户端的HTTP的状态码
原型: splash:set_result_status_code(code)
参数:
- HTTP 状态码(是一个 >= 200 <= 999 的整数)
返回值: nil
是否为异步: 否
通过此功能可以向splash 客户端发送HTTP状态码,以便向客户端报告相关错误
例子:
function main(splash)
local ok, reason = splash:go("http://www.example.com")
if reason == "http500" then
splash:set_result_status_code(503)
splash:set_result_header("Retry-After", 10)
return ''
end
return splash:png()
end
在使用这个函数时要注意: 某些代码可能配置成会根据不同的响应码来进行不同的处理。例如您可以查看nginx 的 proxy_next_upstream 选项
当存在未处理的lua错误时,不论之前调用 splash:set_result_status_code 设置了何值, 最终都会返回400.
您也可以参考: splash:set_result_content_type, splash:set_result_header
splash:set_result_content_type¶
设置返回给客户端结果的 Content-Type 值
原型: splash:set_result_content_type(content_type)
参数:
- content_type: 一个表示头中 Content-Type 键值的字符串
返回值: nil
是否异步: 否
如果main函数的返回值是一个table,那么这个函数将不起作用: Content-Type 会被设置成 application/json
这个函数并不是设置使用 splash:go 发送原始请求的Content-Type, 而是设置返回给客户端的结果的Content-Type
例子:
function main(splash)
splash:set_result_content_type("text/xml")
return [[
<?xml version="1.0" encoding="UTF-8"?>
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>
]]
end
您可以参考:
- splash:set_result_header 这个函数允许用户自定义任意的头信息,而不仅仅是Content-Type
- Binary Objects 它有它自己的方法来设置返回值的 Content-Type
splash:set_result_header¶
设置返回给客户端结果的header 值
原型: splash:set_result_header(name, value)
参数:
- name: 返回header的键名称
- value: 对应的键值
返回值: nil
这个函数并不是设置使用 splash:go 发送原始请求的headers, 而是设置通过splash返回到客户端的headers
例1:在header中设置 “foo=bar”
function main(splash)
splash:set_result_header("foo", "bar")
return "hello"
end
例2:获取将屏幕快照转化为PNG图片所需要的时间,并通过header返回
function main(splash)
-- this function measures the time code takes to execute and returns
-- it in an HTTP header
function timeit(header_name, func)
local start_time = splash:get_perf_stats().walltime
local result = func() -- it won't work for multiple returned values!
local end_time = splash:get_perf_stats().walltime
splash:set_result_header(header_name, tostring(end_time - start_time))
return result
end
-- rendering script
assert(splash:go(splash.args.url))
local screenshot = timeit("X-Render-Time", function()
return splash:png()
end)
splash:set_result_content_type("image/png")
return screenshot
end
您也可以看看: splash:set_result_status_code , splash:set_result_content_type .
splash:get_viewport_size¶
获取浏览器视口的尺寸
原型: width, height = splash:get_viewport_size()
返回值: 以像素为单位返回两个数值——视口的宽和高
是否异步: 否
splash:set_viewport_size¶
设置浏览器视口的大小
原型: splash:set_viewport_size(width, height)
参数:
- width: 整数值,视口的宽
- height: 整数值, 视口的高
返回值: nil
是否异步: 否
这个函数可能会修改可见区域大小和随后的渲染命令, 例如它可能会修改之后调用 splash:png 将产生具有指定大小的图像
splash:png 将会使用这个视口大小
例子
function main(splash)
splash:set_viewport_size(1980, 1020)
assert(splash:go("http://example.com"))
return {png=splash:png()}
end
注解
这将重新布局所有的document元素并影响 geometry 变量,像 window.innerWidth
和 window.innerHeight
。
然而 window.onresize
事件回调将会在下一次异步操作时被调用,很明显 splash:png 属于同步操作。
因此如果您希望在修改视口大小并希望它在执行截屏之前作出相应的调整,您可以使用 splash:wait 来等待。
splash:set_viewport_full¶
调整浏览器视口大小以便适应整个页面
原型: width, height = splash:set_viewport_full()
返回值: 返回两个数值,当前视口被设置的宽和高,以像素为单位
是否异步: 否
splash:set_viewport_full
只有在页面被加载之后才能调用,有时候需要等待一段时间(使用 splash:wait <splash-wait>
)。
这是一个糟糕的限制,但是这是使自动调整大小这一行为工作正常的唯一办法
您可以参考 splash:set_viewport_size 来获取与JS交互的相关内容
splash:png 将会使用这个设置的视口大小
例子:
function main(splash)
assert(splash:go("http://example.com"))
assert(splash:wait(0.5))
splash:set_viewport_full()
return {png=splash:png()}
end
splash:set_user_agent¶
重新设置后续所有请求头中的 User-Agent的值
原型: splash:set_user_agent(value)
参数:
- value: 一个表示HTTP请求头中 UA的字符串
返回值: nil
是否异步: 否
splash:set_custom_headers¶
设置每个请求的 HTTP请求头
原型: splash:set_custom_headers(headers)
参数:
- headers: 一个表示请求头的 LUA的table数据
返回值: nil
是否异步: 否
这里设置的headers将会与WebKit默认的headers合并, 在发生冲突时会覆盖 WebKit中的值
使用 splash:set_custom_headers
设置的请求值并不会作用在 splash:go 的请求上,
也就是说值不会进行合并。 splash:go 使用的headers 拥有更高的优先级
例子
splash:set_custom_headers({
["Header-1"] = "Value 1",
["Header-2"] = "Value 2",
})
注解
这个函数不支持使用参数名传参的方式
您也可以参考: splash:on_request
splash:get_perf_stats¶
返回一个与统计相关的表现资料
原型: stats = splash:get_perf_stats()
返回值: 返回一个对行为分析有用的table
是否异步: 否
就目前来说,这个table包含如下值:
walltime
: float型,返回epoch 时间(从1970 0点开始的时间), 类似于lua中的os.clock
cputime
: float型, splash 进程消耗的CPU时间maxrss
: int型, splash消耗的内存字节数的高位
splash:on_request¶
注册一个函数,每当发送HTTP请求的时候调用
原型: splash:on_request(callback)
参数:
- callback: 每次发送HTTP请求前被调用的函数
是否异步: 否
splash:on_request 的回调接收一个 splash
参数 (一个 Request 对象 )
获取更多关于请求的信息,您可以使用 请求对象的 属性 ,如果要在发起请求前修改或者丢弃对应请求,请使用请求对象的相关 方法
通过 spash:on_request 注册的回调函数中不能调用Splash中的异步函数,像 splash:go 或者 splash:wait
例1:使用 request.url 属性记录所有的请求URL
treat = require("treat")
function main(splash, args)
local urls = {}
splash:on_request(function(request)
table.insert(urls, request.url)
end)
assert(splash:go(splash.args.url))
return treat.as_array(urls)
end
例2:通过 request.info 属性来记录请求信息,但是不直接存储
treat = require("treat")
function main(splash)
local entries = treat.as_array({})
splash:on_request(function(request)
table.insert(entries, request.info)
end)
assert(splash:go(splash.args.url))
return entries
end
例3:丢弃所有针对 “.css” 资源的请求(请参考: request:abort )
splash:on_request(function(request)
if string.find(request.url, ".css") ~= nil then
request.abort()
end
end)
例4:替换资源(请参阅: request:set_url )
splash:on_request(function(request)
if request.url == 'http://example.com/script.js' then
request:set_url('http://mydomain.com/myscript.js')
end
end)
例5:设置自定义的代理服务器,并将相关凭据传递给Splash的HTTP请求(请参阅: request:set_proxy )
splash:on_request(function(request)
request:set_proxy{
host = "0.0.0.0",
port = 8990,
username = splash.args.username,
password = splash.args.password,
}
end)
例6:丢弃响应时间超过5s的请求,但是针对第一个请求允许它不超过15s(请参阅 request:set_timeout )
local first = true
splash.resource_timeout = 5
splash:on_request(function(request)
if first then
request:set_timeout(15.0)
first = false
end
end)
注解
splash:on_request 不能使用命名方式传参
您也可以参考 : splash:on_response , splash:on_response_headers , splash:on_request_reset , treat , Request Object
splash:on_response_headers¶
注册一个回调函数,这个函数在接收响应头之后,但是在接收到响应体之前被调用
原型: splash:on_response_headers(callback)
参数:
- callback: 在接收到响应头之后,但是在接收到响应体之前被调用的Lua函数
返回值: nil
是否异步 : 否
splash:on_response_headers 传入单个的 response
参数(一个 Response Object )
response.body 在 splash:on_response_headers 中 无效,因为此时并没有接收到响应体, splash:on_response_headers 方法使用的关键在于 您可以根据具体情况调用 response:abort 选择放弃接收响应体
在 splash:on_response_headers 定义的回调函数中无法使用Splash中的异步函数,
像 splash:go 或者 splash:wait 。 response
对象在退出回调函数后被清理。
所以您在回调函数之外无法使用这个对象
例1:记录在渲染时获取到的所有响应头的 content-type 值
function main(splash)
local all_headers = {}
splash:on_response_headers(function(response)
local content_type = response.headers["Content-Type"]
all_headers[response.url] = content_type
end)
assert(splash:go(splash.args.url))
return all_headers
end
例2:放弃接收响应头中 Content-Type值为 text/css
的响应体
function main(splash, args)
splash:on_response_headers(function(response)
local ct = response.headers["Content-Type"]
if ct == "text/css" then
response.abort()
end
end)
assert(splash:go(args.url))
return {
png=splash:png(),
har=splash:har()
}
end
例3:在不获取响应体的情况下提取站点中的所有cookie
function main(splash)
local cookies = ""
splash:on_response_headers(function(response)
local response_cookies = response.headers["Set-cookie"]
cookies = cookies .. ";" .. response_cookies
response.abort()
end)
assert(splash:go(splash.args.url))
return cookies
end
注解
splash:on_response_headers 不能使用命名方式传参
您也可以参考: splash:on_request , splash:on_response , splash:on_response_headers_reset , Response Object .
splash:on_response¶
注册一个回调函数,当响应下载完成之后调用
原型: splash:on_response(callback)
参数:
- callback: 每当下载完成之后需要调用的函数
返回值: nil
是否为异步: 否
splash:on_response 回调函数接受单个 response
参数(一个 Response 对象 )
默认情况下,response
对象没有 response.body 属性。
如果您想开启这个属性,请使用 splash.response_body_enabled 选项或者调用
request:enable_response_body 方法
注解
splash:on_response 不允许使用参数名称进行传参
您可以参考: splash:on_request , splash:on_response_headers , splash:on_response_reset , Response Object , splash.response_body_enabled , request:enable_response_body .
splash:on_request_reset¶
删除由 splash:on_request 函数注册的所有回调函数
原型: splash:on_request_reset()
返回值: nil
是否异步: 否
splash:on_response_headers_reset¶
清理所有由 splash:on_response_headers 注册的回调函数
原型: splash:on_response_headers_reset()
返回值: nil
是否异步: 否
splash:on_response_reset¶
移除所有由 splash:on_response 函数注册的回调函数
原型: splash:on_response_reset()
返回值: nil
是否异步: 否
splash:get_version¶
获取Splash的主版本和次版本号
原型: version_info = splash:get_version()
返回值: 一个包含版本信息的table结构
是否异步: 否
目前,这个table主要包含如下内容:
splash
: (string) Splash版本major
: (int) Splash主版本minor
: (int) Splash 次版本python
: (string) Python版本号qt
: (string) QT的版本webkit
: (string) WebKit版本sip
: (string) SIP 版本twisted
: (string) Twisted 版本
示例:
function main(splash)
local version = splash:get_version()
if version.major < 2 and version.minor < 8 then
error("Splash 1.8 or newer required")
end
end
splash:mouse_click¶
在Web页面中触发一个鼠标点击的消息
原型: splash:mouse_click(x, y)
参数:
- x: 需要点击元素的x坐标的值(距左侧的距离,相对于当前视口)
- y: 需要点击元素的y坐标的值(距上方的距离,相对于当前视口)
返回值: nil
是否异步: 否
鼠标事件的坐标必须与当前视口相关联
如果您想在某个元素上点击鼠标,一个简单的办法是使用 splash:select 和 element:mouse_click
local button = splash:select('button')
button:mouse_click()
您也可以使用 splash:mouse_click 来实现它,使用JavaScript代码来获取对应元素的坐标
-- Get button element dimensions with javascript and perform mouse click.
function main(splash)
assert(splash:go(splash.args.url))
local get_dimensions = splash:jsfunc([[
function () {
var rect = document.getElementById('button').getClientRects()[0];
return {"x": rect.left, "y": rect.top}
}
]])
splash:set_viewport_full()
splash:wait(0.1)
local dimensions = get_dimensions()
-- FIXME: button must be inside a viewport
splash:mouse_click(dimensions.x, dimensions.y)
-- Wait split second to allow event to propagate.
splash:wait(0.1)
return splash:html()
end
与 element:mouse_click 不同,splash:mouse_click 不是异步的,鼠标消息不会立即得到响应,为了查看鼠标点击事件执行后页面的变化,您必须要在调用 splash:mouse_click 之后调用 splash:wait
执行该操作的元素必须在视口之内(必须对用户可见),如果元素在视口之外,您需要滚动视口以便让其可见,您可以选择滚动该元素(使用JavaScript代码、
splash.scroll_position 或者 element:scrollIntoViewIfNeeded()
) 或者使用函数
splash:set_viewport_full 来将视口设置为整个页面大小
注解
与 splash:mouse_click 不同, element:mouse_click 会自动滚动屏幕
在splash引擎中, splash:mouse_click 会先执行 splash:mouse_press 再执行 splash:mouse_release
目前只支持鼠标左键点击事件
您可以参考: element:mouse_click , splash:mouse_press , splash:mouse_release , splash:mouse_hover, splash.scroll_position
splash:mouse_hover¶
触发Web 页面中鼠标悬停消息(JavaScript 中的mouseover消息)
原型: splash:mouse_hover(x, y)
参数:
- x: 需要触发悬停事件的元素所在位置的 x 坐标(距左边的距离,相对于当前视口来说)
- y: 需要触发悬停事件的元素所在位置的 y 坐标(距上边的距离,相对于当前视口来说)
返回值: nil
是否异步: 否
请在 splash:mouse_click 中参阅相关的鼠标事件
您也可以参考: element:mouse_hover
splash:mouse_press¶
触发页面中鼠标按下的事件
原型: splash:mouse_press(x, y)
参数:
- x: 需要触发鼠标左键按下事件的元素所在位置的 x 坐标(距左边的距离,相对于当前视口来说)
- y: 需要触发鼠标左键按下事件的元素所在位置的 y 坐标(距上边的距离,相对于当前视口来说)
返回值: nil
是否异步: 否
请在 splash:mouse_click 中参阅相关的鼠标事件
splash:mouse_release¶
触发页面中鼠标键抬起的事件
原型: splash:mouse_release(x, y)
参数:
- x: 需要触发鼠标左键抬起事件的元素所在位置的 x 坐标(距左边的距离,相对于当前视口来说)
- y: 需要触发鼠标左键抬起事件的元素所在位置的 y 坐标(距上边的距离,相对于当前视口来说)
返回值: nil
是否异步: 否
请在 splash:mouse_click 中参阅相关的鼠标事件
splash:with_timeout¶
设置执行函数的超时值
原型: ok, result = splash:with_timeout(func, timeout)
参数:
- func: 需要设置超时值的函数
- timeout: 超时值,单位为秒
返回值: ok, result
的元组;如果 ok
的值不为 true
表明在执行函数的过程中出现对应的错误,或者超时。
result
将会保存错误的类型信息, 如果 result
等于 timeout
则说明指定的超时时间已过。当 ok
为 true
时, result
中包含函数执行的结果。如果您的函数返回多个值,它们会被返回到后面多个 result
变量中
是否异步: 是
例1:
function main(splash, args)
local ok, result = splash:with_timeout(function()
-- try commenting out splash:wait(3)
splash:wait(3)
assert(splash:go(args.url))
end, 2)
if not ok then
if result == "timeout_over" then
return "Cannot navigate to the url within 2 seconds"
else
return result
end
end
return "Navigated to the url within 2 seconds"
end
例2:函数返回多个值:
function main(splash)
local ok, result1, result2, result3 = splash:with_timeout(function()
splash:wait(0.5)
return 1, 2, 3
end, 1)
return result1, result2, result3
end
请注意,如果函数执行时间超过了设置的超时值,那么splash会尝试中断函数的执行。但是splash是以 协作式多任务 的方式在运行, 因此在某些时候Spalash无法停止执行超时的函数。换句话说, 协作式多任务模式意味着管理程序(在这个例子中管理程序是Splash脚本引擎) 在对应子程序没有要求的情况下不会主动结束子程序。 在splash脚本中,只有在调用某些异步操作时,这些操作才会被结束 [16] 。 反之,同步函数无法被停止
注解
splash是以 协作式多任务 的方式在运行 。在进行同步调用的时候,您需要额外的小心
让我们在例子中看一下它们的不同
function main(splash)
local ok, result = splash:with_timeout(function()
splash:go(splash.args.url) -- 执行到此处时任务可以被停止
splash:evaljs(long_js_operation) -- 在执行js函数期间不能被停止
local png = splash:png() -- 执行到同步操作的时候,不能被停止
return png
end, 0.1)
return result
end
splash:send_keys¶
相对应的页面上下文环境发送键盘事件
原型: splash:send_keys(keys)
参数:
- keys : 表示要作为键盘事件发送的键的字符串
返回值: nil
是否异步: 否
指定的键值将会被使用 emacs edmacro 语法中的一个小子集来进行序列化
- 空格键将会被忽略,它仅仅用来分隔不同的键值
- 字符值将会原样的保留
- 括号内的词代表对应的功能键,像
<Return>
、<Home>
、<Left>
。您可以查看 QT 的帮助文档 来获取完整的功能键列表.<Foo>
会尝试匹配Qt::Key_Foo
下面这个表格展示了一些输入宏的例子,以及他们最终被转化的结果
宏 | 结果 |
---|---|
Hello World |
HelloWorld |
Hello <Space> World |
Hello World |
< S p a c e > |
<Space> |
Hello <Home> <Delete> |
ello |
Hello <Backspace> |
Hell |
键盘事件不会立即处理,而是要等到下一次进行消息循环。因此必须要调用 splash:wait 来等待事件的响应执行
您也可以参考: element:send_keys , splash:send_text .
splash:send_text¶
发送一个文本,作为页面上下文的输入, 字面上逐个字符输入
原型: splash:send_text(text)
参数:
- text: 作为输入的字符串
返回值: nil
是否异步: 否
键盘事件不会立即处理,而是要等到下一次进行消息循环。因此必须要调用 splash:wait 来等待事件的响应执行
这个函数与 splash:send_keys 一起涵盖了键盘输入的大部分需求,像自动填充和提交表单。
例1:选中第一个输入框,填充并提交表单:
function main(splash)
assert(splash:go(splash.args.url))
assert(splash:wait(0.5))
splash:send_keys("<Tab>")
splash:send_text("zero cool")
splash:send_keys("<Tab>")
splash:send_text("hunter2")
splash:send_keys("<Return>")
-- 请注意如何使用splash:send_keys来改写程序
-- splash:send_keys("<Tab> zero <Space> cool <Tab> hunter2 <Return>")
assert(splash:wait(0))
-- ...
end
例2:使用JavaScript代码或者 splash:mouse_click 来选中输入框
我们不能总是假定使用 <Tab> 会选中对应的输入框 <Enter> 会提交表单,选中输入框还可以通过点击它或者将焦点移动到它来完成。 提交表单也可以通过触发表单中的提交事件或者点击提交按钮来完成.
下面这个例子将会先选中输入框,然后通过函数 splash:mouse_click 来点击提交按钮完成表单的提交 。这里假设splash传入两个参数:username和password
function main(splash, args)
function focus(sel)
splash:select(sel):focus()
end
assert(splash:go(args.url))
assert(splash:wait(0.5))
focus('input[name=username]')
splash:send_text(args.username)
assert(splash:wait(0))
focus('input[name=password]')
splash:send_text(args.password)
splash:select('input[type=submit]'):mouse_click()
assert(splash:wait(0))
-- Usually, wait for the submit request to finish
-- ...
end
您也可以参考: element:send_text , splash:send_keys
splash:select¶
利用CSS选择器,在HTML DOM中选择第一个匹配的元素
原型: element = splash:select(selector)
参数:
- selector: 有效的CSS选择器
返回值: Element 对象的值
是否异步: 否
使用 splash:select 您可以通过CSS选择器来获取对应的元素, 就好像在浏览器中使用 document.querySelector 一样。 它返回的元素对象是 Element 。 这个对象包含许多有用的属性和方法,这些属性和方法与在JavaScript中类似
如果使用的CSS选择器不能找到对应的元素,函数将会返回 nil
。如果您输入的CSS选择器无效,将会抛出一个错误.
例1:选择类名为 element
的元素并且返回它所有兄弟元素的类名:
local treat = require('treat')
function main(splash)
assert(splash:go(splash.args.url))
assert(splash:wait(0.5))
local el = splash:select('.element')
local seen = {}
local classNames = {}
while el do
local classList = el.node.classList
if classList then
for _, v in ipairs(classList) do
if (not seen[v]) then
classNames[#classNames + 1] = v
seen[v] = true
end
end
end
el = el.node.nextSibling
end
return treat.as_array(classNames)
end
例2:判断返回的元素是否存在
function main(splash)
-- ...
local el = assert(splash:select('.element'))
-- ...
end
splash:select_all¶
在页面中通过CSS选择器来选择对应的DOM元素,并以列表的形式返回匹配的元素
原型: elements = splash:select_all(selector)
参数:
- selector: 有效的CSS选择器
返回值: 包含 Element 对象的列表
是否异步: 否
与 splash:select 不同的是,它会在table中返回所有匹配到的元素的列表。
如果没有元素被匹配到,它会返回一个 {}
, 如果传入的选择器无效,则会抛出一个错误
下面这个例子是选择所有 <img />
元素并获取它们的 src
属性
local treat = require('treat')
function main(splash)
assert(splash:go(splash.args.url))
assert(splash:wait(0.5))
local imgs = splash:select_all('img')
local srcs = {}
for _, img in ipairs(imgs) do
srcs[#srcs+1] = img.node.attributes.src
end
return treat.as_array(srcs)
end
[9] | 这是由于Splash一次只能加载一个页面,在加载新页面之前的老页面不会被保存 |
[10] | 这个意思是说我们在使用API时传入的参数都可以通过这个参数获取到 |
[11] | 这里的主页是指参数中url对应的页面,而页面中的资源等等不包含在里面 |
[12] | 这里的原文是 pair,由于我对lua不是很了解,这里翻译为元组可能更好理解 |
[13] | 我觉得这里官方应该是鼓励我们尽量返回能够被序列化的数据,而不要返回类似DOM元素的内容 |
[14] | 这里的意思应该是不要使用JavaScript的复杂结构 |
[15] | lua函数调用有两种形式,带形参名称的使用``{}`` 不带的使用 () |
[16] | Splash只能管理异步函数而无权管理这些同步函数,只能被动的等待函数执行完成 |