一、Splash 的使用
Splash 是一个JavaScript 渲染服务,带有 HTTP API的轻量级浏览器,同时对接了 Python 中的 Twisted 和 QT 库。利用它,同样可以实现动态渲染页面的抓取。
- 实例引入
- 通过 Splash 提供的 Web 页面来测试其渲染过程。例:在本机 8050 端口上运行 Splash 服务,打开 http://localhost:8050/ 即可看到其 Web 页面:
- 黑色框显示的是一个渲染示例。上方有个输入框,默认是 http://google.com, 换成百度测试,将内容更改为 https://www.baidu.com,点击 Render me 按钮开始渲染。 结果:
- 网页的返回结果呈现了渲染截图、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 脚本来控制了页面加载过程,加载过程完全模拟浏览器,最后可返回各种格式的结果,如:网页源码和截图等。
- 通过 Splash 提供的 Web 页面来测试其渲染过程。例:在本机 8050 端口上运行 Splash 服务,打开 http://localhost:8050/ 即可看到其 Web 页面:
- 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!按钮 测试
- 它返回网页的标题,这里通过 evaljs()方法传人 JavaScript 脚本,而 document.title 的执行结果就是返回网页标题,执行完毕后将其赋值给一个 title 变量,随后将其返回:
注意,在这里定义的方法名称叫作 main()。这个名称必须是固定的,Splash 会默认调用这个方法。
- 该方法的返回值既可以是字典形式,也可以是字符串形式,最后都会转化为 Splash HTTP Response,例如:
function main(splash) return { hello="world" } 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
输出:
-
- 在脚本内调用的 wait ()方法类似于 Python 中的 sleep(),其参数为等待的秒数。当 Splash 执行到此方法时,它会转而去处理其他任务,然后在指定的时间过后再回来继续处理。
- 注意:Lua 脚本中的字符串拼接和 Python 不同,它使用的是..操作符,而不是+。简单了解 Lua 脚本的语法:http://www.runoob.com/lua/lua-basic-syntax.html。
- 这里做了加载时的异常检测。go()方法会返回加载页面的结果状态,如果页面州现 4xx 或 5xx 状态码,ok 变量就为空,不会返回加载后的图片。
- splash 支持异步处理,但这里并没有显式指明回调方法,其回调的跳转是在 Splash 内部完成的。例:
- Splash 对象属性
- 前面例子中 main()方法的第一个参数是 splash,这个对象非常重要,类似于 Selenium 中的 WebDriver 对象,可以调用它的一些属性和方法来控制加载过程。
- args
-
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.url end
-
args 属性可以获取加载时配置的参数,如 URL,如果为 GET 请求,还可以获取 GET 请求参数;如果为 POST 请求,可以获取表单提交的数据。Splash 也支持使用第二个参数直接作为 args,例:
- js_enabled
- 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 代码,此时运行结果就会抛出异常:
View Code{ "error": 400, "info": { "line_number": 1, "error": "')' expected near char(239)", "source": "[string \"function main(splash, args)\r...\"]", "message": "[string \"function main(splash, args)\r...\"]:1: ')' expected near char(239)", "type": "LUA_INIT_ERROR" }, "description": "Error happened while executing Lua script", "type": "ScriptError" }
- js_enabled 属性是 Splash 的 JavaScript 执行开关,可以将其配置为 true 或 false 来控制是否执行 JavaScript 代码,默认为 true。如:这里禁止执行 JavaScript 代码: