Splash的安装中出现的问题的解决和基本使用介绍

Splash是一个JavaScript渲染服务,是一个带有HTTP API的轻量级浏览器,同时它对接了Python中的Twisted和QT库。利用它,我们同样可以实现动态渲染页面和抓取。

功能介绍

  • 利用Splash,我们可以实现如下功能:
  • 异步方式处理多个网页渲染过程;
  • 获取渲染后的页面的源代码或截图;
  • 通过关闭图片渲染或者使用Adblock规则来加快页面渲染速度;
  • 可执行特定的JavaScript脚本;
  • 可通过Lua脚本来控制页面渲染过程;
  • 获取渲染的详细过程并通过HAR(HTTP Archive)格式呈现。

准备工作

我们要进行Splash 的安装,安装Splash我们要先安装Docker,我们只需从https://docs.docker.com/docker-for-windows/install/下载最新的Docker for Windows安装包即可,下载过程中我遇到了许多问题下面我就一一帮大家解决

我第一次用docker安装splash出现这种错误,这是因为我们的设置的DOCKER_HOST的设置连接不上去,后来我去百度它给我的解决办法是输入【docker-machine env default】,然后我输了还是不行,还是会继续报错,如下所示:

意思就是说Host连接不上去了,这时候我们就要重启下default,输入命令【docker-machine restart default】,如下所示:

Splash的安装中出现的问题的解决和基本使用介绍_第1张图片

然后再输入命令【docker-machine env --shell cmd default】,如下所示:

Splash的安装中出现的问题的解决和基本使用介绍_第2张图片

然后把下面的内容复制下就可以了,如下所示:

Splash的安装中出现的问题的解决和基本使用介绍_第3张图片

这时候再输入命令【docker version】,我们就可以显示成功了,如下所示:

Splash的安装中出现的问题的解决和基本使用介绍_第4张图片

再运行命令安装Splash即可安装成功如下所示:

Splash的安装中出现的问题的解决和基本使用介绍_第5张图片

然后输入命令【docker-machine ip default]会显示ip地址,将下面显示的地址复制到网页输出,如下所示:

Splash的安装中出现的问题的解决和基本使用介绍_第6张图片

这样Splash即可安装成功了

如上图右侧,呈现的是一个渲染示例。可以看到,上方有一个输入框,我们点击render me按钮开始渲染,可以看到,网页的返回结果呈现了渲染截图,HAR加载统计数据、网页的源代码。

这个过程是由一段脚本构成,这个脚本实际上是用Lua语言写的脚本,下面我们会介绍。

 

Splash Lua脚本

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

返回了网页的标题,这里我们通过evaljs()方法传入JavaScript脚本,而document.title的执行结果就是返回网页标题,执行完成后将其赋值给一个title变量,随后将其返回。

我们在这里定义的方法名称叫做main()。这个名称必须是固定的,Splash会默认调用这个方法。

该方法的返回值既可以是字典形式,也可以是字符串形式,最后都会转化为Splash HTTP Response。

  • 异步处理

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个站点

 

Splash对象属性

类似于Selenium中的WebDriver对象,我们可以调用它的一些属性和方法来控制加载过程。

  • args

该属性可以获取加载时配置的参数,比如URL,如果为GET请求,它还可以获取GET请求参数;如果为POST请求,它可以获取表单提交的数据。Splash也支持使用第二个参数直接作为args,例如:

function main(splash, args)
  local url=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代码,此时运行结果就会抛出异常:

HTTP Error 400 (Bad Request)
Type: ScriptError -> LUA_INIT_ERROR
Error happened while executing Lua script

[string "function main(splash, args)
..."]:3: function arguments expected near '='

{
    "type": "ScriptError",
    "error": 400,
    "info": {
        "source": "[string \"function main(splash, args)\r...\"]",
        "line_number": 3,
        "message": "[string \"function main(splash, args)\r...\"]:3: function arguments expected near '='",
        "type": "LUA_INIT_ERROR",
        "error": "function arguments expected near '='"
    },
    "description": "Error happened while executing Lua script"
}

 

  • resource_timeout

此属性可以设置加载时间,单位是秒。如果设置为0或nil,代表不检测超时,如下所示:

function main(splash)
  splash.resource_timeout=0.1
  assert(splash:go('https://www.taobao.com'))
  return splash:png()
end
  • images_enabled

此属性可以设置图片是否加载,默认情况下是加载的。禁用该属性后,可以节省网络流量并提高网页加载速度。

function main(splash, args)
  splash.images_enabled=false
  assert(splash:go('https://www.jd.com'))
  return {
    png=splash:png()
  }
end

这样返回的页面截图就不会带有任何图片,加载速度也会快很多。

 

  • plugins_enabled

此属性可以控制浏览器插件是否开启。默认情况下是不开启的。

  • scroll_position

通过设置此属性,我们可以控制页面上下或左右滚蛋。这是一个比较常用的属性,示例如下:

function main(splash, args)
  assert(splash:go('https://www.taobao.com'))
  splash.scroll_position = {y=400}
  return {png=splash:png()}
end

这样我们就可以控制页面向下滚动400像素值

 

Splash对象的方法

  • go()

该方法是用来请求某个链接的,而且它可以模拟GET和POST请求,同时支持传入请求头、表单等数据,用法如下:

ok,reason=splash:go{url,baseurl=nil,header=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的表单数据,如果成功,则返回页面的源代码。

 

  • 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("http://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

我们声明了一个JavaScript定义的办法,然后在页面加载成功后调用了从方法计算出了页面中div节点的个数。

 

  • evaljs()

此方法可以执行JavaScript代码并返回最后一条JavaScript语句返回结果,使用方法如下:

result=splash:evaljs(js)
  • runjs()

此方法可以执行JavaScript代码,它与evaljs()的功能类似,但是更偏向于执行某些功能或声明某些办法。如下所示:

function main(splash, args)
  splash:go("https://www.baidu.com")
  splash:runjs("foo=function(){return 'bar'}")
  local result=splash:evaljs('foo()')
  return result
end

这里我们用runjs()先声明了一个JavaScript定义的方法,然后通过evaljs()来调用得到的结果。

 

  • autoload()

此方法可以设置每个页面访问时自动加载的对象,使用方法如下:

ok,reason=splash:autoload{source_or_url,source=nill,url=nil}
  • source_or_url:JavaScript代码或者JavaScript库链接
  • source:JavaScript代码
  • url:JavaScript库链接

此方法只负责加载JavaScript代码或库,不执行任何操作。

function main(splash, args)
  splash:autoload([[
    function get_document_title(){
    return document.title
  }
    ]])
  splash:go("https:www.baidu.com")
  return splash:evaljs("get_document_title()")
end

这里我们调用autoload()方法声明了一个JavaScript方法,然后通过evaljs()方法来执行此JavaScript()该方法。

 

  • call_later()

此方法可以通过设置定时任务和延迟时间来实现任务延时执行,并且可以在执行前通过cancel()方法重新执行定时任务。如下所示:

function main(splash, args)
  local snapshots={}
  local timer=splash:call_later(function()
      snapshots["a"]=splash:png()
      splash:wait(1.0)
      snapshots["b"]=splash:png()
  end,0.2)
  splash:go("https://www.taobao.com")
  splash:wait(3.0)
  return snapshots
end

这里我们设置了一个定时任务,0.2秒的时候获取网页截图,然后等待1秒,1.2秒时再次获取网页截图,访问的页面是淘宝,最后将截图结果返回。

 

  • http_get()

此方法可以模拟发送HTTP的GET请求,使用方法如下:

response=splash:http_get{url,headers=nil,follow_redirects=true}
  • url:请求URL
  • headers:可选参数,默认为空,请求头
  • follow_redirects:可选参数,表示是否启动自动重定向,默认为true。
function main(splash, args)
  local treat=require("treat")
  local response=splash:http_get("http://httpbin.org/get")
     return {
          html=treat.as_string(response.body),
          url=response.url,
          status=response.status
  }
end
  • http_post()

和http_get()方法类似,此方法用来模拟发送POST请求,不过多了一个参数body,使用方法如下:

response=splash:http_post{url,headers=nil,follow_redirects=true,body=nil}
  • url:请求URL。
  • headers:可选参数,默认为空,请求头
  • follow_redirects::可选参数,表示是否启动自动重定向,默认为true。
  • body:可选参数,即表单数据,默认为空。
function main(splash, args)
  local treat=require("treat")
  local json=require("json")
  local response=splash:http_post{"http://httpbin.org/post",
    body=json.encode({name="Germey"}),
    headers={["content-type"]="application/json"}
    }
  return {
    html=treat.as_string(response.body),
    url=response.url,
    status=response.status
  }
end

这里我们成功模拟提交了POST请求并发生了表单数据

 

  • set_content()

此方法用来设置页面的内容,示例如下:

function main(splash)
    assert(splash:set_content("

hello

")) return splash:png() end
  • html()

此方法用来获取网页的源代码,它是非常简单又常用的方法。示例如下:

function main(splash, args)
  splash:go("https://httpbin.org/get")
  return splash:html()
end
  • png()

此方法用来获取PNG格式的网页截图,示例如下:

function main(splash, args)
  splash:go("https://www.taobao.com")
  return splash:png()
end
  • jpeg()

此方法用来获取JPEG格式的网页截图,示例如下:

function main(splash, args)
  splash:go("https://www.taobao.com")
  return splash:jpeg()
end

 

  • har()

此方法用来获取页面加载过程描述,示例如下:

function main(splash, args)
  splash:go("https://www.baidu.com")
  return splash:har()
end
  • url()

此方法可以获取当前正在访问的URL,示例如下:

function main(splash, args)
  splash:go("https://www.baidu.com")
  return splash:url()
end
  • get_cookies()

此方法可以获取当前页面的Cookies,示例如下:

function main(splash, args)
  splash:go("https://www.baidu.com")
  return splash:get_cookies()
end
  • add_cookie()

此方法可以为当前页面添加Cookie

cookies=splash:add_cookie{name,value,path=nil,expires=nil,httpOnly=nil,secure=nil}
  • clear_cookies()

此方法可以清楚所有的cookies

  • get_viewport_size()

此方法可以获取当前浏览器页面的大小,即宽高。

  • set_viewport_size()

此方法可以设置当前浏览器页面的大小,即宽高。

  • set_viewport_full()

此方法可以设置浏览器全屏显示

  • set_user_agent()

此方法可以设置浏览器的User-Agent

  • set_custom_headers()

此方法可以设置请求头

  • select()

该方法可以选中符合条件的第一个节点,如果有多个节点符合条件,则只会返回一个,其参数是CSS选择器,示例如下:

function main(splash, args)
  splash:go("https://www.baidu.com/")
  input=splash:select("#kw")
  input:send_text("Splash")
  splash:wait(3)
  return splash:png()
  
end

我们这里首先访问了百度,然后选中了搜索框,随后调用了send_text()方法填写了文本,然后返回网页截图。

  • select_all()

此方法可以选中所有符合条件的节点,其参数是CSS选择器。示例如下:

function main(splash, args)
  local treat=require('treat')
  assert(splash:go("http://quotes.toscrape.com/"))
  assert(splash:wait(0.5))
  local texts=splash:select_all('.quote .text')
  local results={}
  for index,text in ipairs(texts) do
    results[index]=text.node.innerHTML
  end
  return treat.as_array(results)
end

这里通过CSS选择器选中了节点的正文内容,随后遍历了所有节点,将其中的文本获取下来。

 

  • mouse_click()

此方法可以模拟鼠标点击操作,传入的参数为坐标值x和y。此外,也可以直接选中某个节点,然后调用此方法,示例如下:

function main(splash, args)
  splash:go("https://www.baidu.com/")
  input=splash:select("#kw")
  input:send_text('Splash')
  submit=splash:select('#su')
  submit:mouse_click()
  splash:wait(3)
  return splash:png()
end

这里我们首先选中页面的输入框,输入文本,然后选中提交按钮,调用了mouse_click()方法提交查询,然后页面等待三秒,返回截图。

 

Splash API调用

  • render.html

此接口用于获取JavaScript渲染的页面的HTML代码,接口地址就是Splash的运行地址加此接口的名称

如果用Python实现的话,如下所示:

import requests
url='http://192.168.99.100:8050/render.html?url=https://www.baidu.com'
response=requests.get(url)
print(response.text)

这样就可以成功输出百度页面渲染后的源代码,此接口还可以指定其他参数

  • render.png

此接口可以获取网页截图,其参数比render.html多了几个,比如通过width和height来控制宽高,它返回的是PNG格式的图片二进制数据,示例如下:

import requests
url='http://192.168.99.100:8050/render.png?url=https://www.jd.com&wait=5&wait=1000&height=700'
response=requests.get(url)
with open('taobao.png','wb') as f:
    f.write(response.content)

这样我们就成功获取了京东首页渲染完成后的页面截图

 

  • render.jpeg

此接口和render.png不过它返回的是JPEG格式的图片二进制数据

另外,此接口比render.png多了个参数quality,用来设置图片质量。

 

  • render.har

此接口用于获取页面加载的HAR数据,

 

  • render.json

此接口包含了前面接口的所有功能,返回结果是JSON格式.

 

  • execute

此接口才是最为强大的接口。execute接口可以实现一些交互操作

import requests
from urllib.parse import quote
lua="""
function main(splash)
    return 'hello'
end
"""

url='http://192.168.99.100:8050/execute?lua_source='+quote(lua)
response=requests.get(url)
print(response.text)

这里我们用Python中的三引号将Lua脚本包括起来,然后用urllib.parse模板里的quote()方法将脚本进行URL转码,随后构造了Splash请求URL,将其作为lua_source参数传递,我们通过实例看下:

import requests
from urllib.parse import quote
lua="""
function main(splash,args)
    local treat=require("treat")
    local response=splash:http_get("http://httpbin.org/get")
    return {
         html=treat.as_string(response.body),
         url=response.url,
         status=response.status
         }
end         
"""
url='http://192.168.99.100:8050/execute?lua_source='+quote(lua)
response=requests.get(url)
print(response.text)

我们所说的Lua脚本均可以用此方法与Python进行对接。

你可能感兴趣的:(Python)