简介

splash 能够执行用 Lua 编写的自定义脚本,这能使splash成为和 PhantomJS 相似的 browser automation tool 。

如果想要执行一个脚本并获得结果,可以使用 lua_source 参数发送脚本至 execute 或者 run

以下内容通过 execute 实现。

 Note:大多数时候,即使你不会 Lua 你也能实现下面的 Splash 脚本。然而,这门语言是值得学习的。你可以用 Lua 编写 Redis、Nginx、Apache、魔兽世界脚本、使用 Corona 创建移动端app,以及使用最先进的深度学习框架 Torch7。Lua 很容学习,推荐一些资料:Learn Lua in 15 minutes 和 Programming in Lua 。

让我们从下面的例子开始吧:

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

 如果我们通过参数  lua_source 向 execute 端点提交了这脚本,Splash 将先访问 example.com ,等待直到加载,再等待 0.5s ,然后获取页面的 title ,最后将结果封装成JSON对象返回。

 Note:Splash UI 还提供了一种简单的测试脚本的方法,访问  http://127.0.0.1:8050/  ,在代码编辑器里编辑 Lua 然后点击 “render me”。为了在splash中运行脚本,你需要弄清楚如何通过你的程序环境向Splash发送HTTP请求。可以查阅这个文档 How to send requests to Splash HTTP API? ,python + request 如何实现在这里有做说明。

Entry Point: the “main” Function

脚本中必须包含一个名为 main 的函数,它返回一个HTTP响应。脚本中可以包含其他辅助函数,但 main 是必须的。

上面的例子中,main返回了一个 Lua table (关联数组,类似python的字典),Lua table会被封装为JSON返回。

main也可以返回一个字符串:

function main(splash)
    return 'hello'
end

 

字符串会被原样返回,不像Lua table会被封装为JSON。

$ curl 'http://127.0.0.1:8050/execute?lua_source=function+main%28splash%29%0D%0A++return+%27hello%27%0D%0Aend'
hello

 

main 函数接收一个对象,所有的Splash特性都可以通过这个对象访问。我们通常约定这个对象的名字为:splash,但是你也可以不尊从这个约定:

function main(please)
    please:go("http://example.com")
    please:wait(0.5)
    return "ok"
end

 

Where Are My Callbacks?

以下是第一个例子中的部分代码:

splash:go("http://example.com")
splash:wait(0.5)
local title = splash:evaljs("document.title")

 

这段代码看起来是标准的流程式代码,没有回调,也没有复杂的 control-flow 结构。但这并不意味着 Splash 使用 同步 方式运转,相反它是异步的。在这段程序中,当执行到  splash:wait(0.5) 时,splash会切换,去执行其他任务,0.5s 后再回来执行接下来的代码。

我们可以在splash脚本中使用 循环、条件判断、函数:

function main(splash, args)
  splash:set_viewport_size(800, 600)
  splash:set_user_agent('Splash bot')
  local example_urls = {"www.google.com", "www.bbc.co.uk", "scrapinghub.com"}
  local urls = args.urls or example_urls
  local results = {}
  for _, url in ipairs(urls) do
    local ok, reason = splash:go("http://" .. url)
    if ok then
      splash:wait(0.2)
      results[url] = splash:png()
    end
  end
  return results
end
View Code

 

查看Splash Lua API 特性:Splash Lua API Overview

 

Living Without Callbacks

这一段看不懂

查看官方文档

 

Calling Splash Methods

Lua 通常使用 ' : ' 来调用对象的方法,例如调用splash的方法:splash:foo() 。

在splash脚本中调用 Lua method 主要有以下两种方式:

  • 参数为 位置参数时:splash:foo(val1, val2)
  • 参数为 关键字参数时:splash:foo{name1=val1, name2=val2}
  • 参数既有关键字参数,又有位置参数时:splash:foo{val1, name2=val2}
-- Examples of positional arguments:
splash:go("http://example.com")
splash:wait(0.5, false)
local title = splash:evaljs("document.title")

-- The same using keyword arguments:
splash:go{url="http://example.com"}
splash:wait{time=0.5, cancel_on_redirect=false}
local title = splash:evaljs{source="document.title"}

-- Mixed arguments example:
splash:wait{0.5, cancel_on_redirect=false}

 

为了方便,splash 的方法被设计成既可以通过位置参数调用,也可以通过命名参数调用。但是由于 Lua 中没有真正意义上的命名参数,所以大多数方法都仅支持位置参数。

 

Error Handling

Lua 有两种报错的方法:raise an exception and return an error flag,see: http://www.lua.org/pil/8.3.html.

splash 使用以下约定:

  • 由于开发者而报错,这个错误将被抛出。例如:参数不正确。
  • 不是开发者引起的,则返回状态标记,例如:请求网页没有响应。functions that can fail return ok, reason pairs.

如果 main 函数引发了一个未处理的异常,splash 将返回 HTTP 400 。

你也可以使用 Lua 的 error 方法,手动抛出异常:

error("A message to be returned in a HTTP 400 response")

 

可以使用 pcall 方法处理 Lua 异常,查看文档

可以使用 assert 方法将 “status flag” errors 转变为异常。例如,你想让网站不用手动处理任何异常的工作,可以使用 assert 停止处理,并返回 HTTP 400,如果错误级别是 wrong:

local ok, msg = splash:go("http://example.com")
if not ok then
    -- handle error somehow, e.g.
    error(msg)
end

-- a shortcut for the code above: use assert
assert(splash:go("http://example.com"))

 

 

Sandbox

默认情况下,splash脚本是在受限制的环境中执行的:并不是所有标准的Lua模块和函数都可用,Lua require是受限制的,并且有资源限制(尽管相当宽松)。

当sandbox被禁用时,所有的 lua 模块就都可以使用.

在启动 splash 时禁用 sandbox:

$ docker run -it -p 8050:8050 scrapinghub/splash --disable-lua-sandbox

 

 

Timeouts

默认情况下,splash脚本的执行超时时间为30s 。

通过 I’m getting lots of 504 Timeout errors, please help! 和  2. Splash Lua script does too many things 查阅更多信息