动态渲染页面爬取-Splash
1 | Splash是一个JavaScript渲染服务,是一个带有HTTPAPI的轻量级浏览器,同时它对接了Python中的Twisted和 Q T 库。利用它,我们同样可以实现动态渲染页面的抓取。 |
Splash启动命令
1 | docker run -p 8050:8050 scrapinghub/splash |
功能介绍
1 | 利用Splash,我们可以实现如下功能: |
准备工作
1 | 在开始之前,请确保已经正确安装好了 Splash并可以正常运行服务。 |
实例引入
1 | 首先,通过Splash提供的Web页面来测试其渲染过程。例如,我们在本机8050端口上运行了 Splash服务,打开http://localhost:8050/即可看到其Web页面 |
1 | 在图7-6右侧,呈现的是一个渲染示例。可以看到,上方有一个输入框,默认是http://google.com,这里换成百度测试一下,将内容更改为https://www.baidu.com, 然后点击Render me按钮开始渲染 |
1 | 可以看到,网页的返回结果呈现了渲染截图、 HAR加载统计数据、网页的源代码。 |
Splash Lua 脚本
1 | Splash可以通过Lua脚本执行一系列渲染操作,这样我们就可以用Splash来模拟类似Chrome、PhantomJS 的操作了。 |
入口及返回值
1 | 首先,来看一个基本实例: |
1 | 注意,我们在这里定义的方法名称叫作main()0 这个名称必须是固定的, Splash会默认调用这个方法。 |
异步处理
1 | Splash支持异步处理,但是这里并没有显式指明回调方法,其回调的跳转是在Splash内部完成的。 |
1 | 运行结果是3 个站点的截图 |
1 | 在脚本内调用的wait()方法类似于Python中的 sleep(), 其参数为等待的秒数。当 Splash执行到此方法时,它会转而去处理其他任务,然后在指定的时间过后再回来继续处理。 |
Splash对象属性
1 | 我们注意到,前面例子中main()方法的第一个参数是 splash,这个对象非常重要,它类似于Selenium中的WebDriver对象,我们可以调用它的一些属性和方法来控制加载过程。接下来,先看下它的属性。 |
args
1 | 该属性可以获取加载时配置的参数,比如URL,如果为GET请求,它还可以获取GET请求参数; |
js_enabled
1 | 这个属性是Splash的JavaScript执行开关,可以将其配置为true或false来控制是否执行JavaScript代码,默 认 为tru eo 例如,这里禁止执行JavaScript代码: |
1 | 不过一般来说,不用设置此属性,默认开启即可。 |
resource_timeout
1 | 此属性可以设置加载的超时时间,单位是秒。如果设置为0或nil(类似Python中的None ), 代表不检测超时。示例如下: |
images_enabled
1 | 此属性可以设置图片是否加载,默认情况下是加载的。禁用该属性后,可以节省网络流量并提高网页加载速度。 |
1 | 禁用图片加载的示例如下: |
plugins_enabled
1 | 此属性可以控制浏览器插件(如Flash插件)是否开启。默认情况下,此属性是false, 表示不开启。可以使用如下代码控制其开启和关闭: |
scroll_position
1 | 通过设置此属性,我们可以控制页面上下或左右滚动。这是一个比较常用的属性,示例如下: |
1 | 这样我们就可以控制页面向下滚动400像素值 |
Splash对象的方法
1 | 除了前面介绍的属性外, Splash对象还有如下方法 |
go()
1 | 该方法用来请求某个链接,而且它可以模拟GET和POST请求,同时支持传入请求头、表单等数据,其用法如下: |
1 | 该方法的返回结果是结果ok和原因reason的组合,如果ok为空,代表网页加载出现了错误,此时reason变量中包含了错误的原因,否则证明页面加载成功。示例如下: |
1 | 这里我们模拟了一个POST请求,并传入了POST的表单数据,如果成功,则返回页面的源代码。 |
wait()
1 | 此方法可以控制页面的等待时间,使用方法如下: |
1 | 返回结果同样是结果ok和原因reason的组合。 |
jsfunc()
1 | 此方法可以直接调用JavaScript定义的方法,但是所调用的方法需要用双中括号包围,这相当于实现了JavaScript方法到Lua脚本的转换。示例如下: |
1 | 运行结果如下: |
1 | 首先,我们声明了一个JavaScript定义的方法,然后在页面加载成功后调用了此方法计算出了页面中div节点的个数。 |
evaljs()
1 | 此方法可以执行JavaScript代码并返回最后一条JavaScript语句的返回结果,使用方法如下: |
runjs()
1 | 此方法可以执行JavaScript代码,它与evaljs()的功能类似,但是更偏向于执行某些动作或声明某些方法。例如: |
autoload()
1 | 此方法可以设置每个页面访问时自动加载的对象,使用方法如下: |
1 | 但是此方法只负责加载JavaScript代码或库,不执行任何操作。如果要执行操作,可以调用evaljs()或runjs()方法。示例如下: |
1 | 这里我们调用autoload()方法声明了一个JavaScript方法,然后通过 evaljs()方法来执行此JavaScript方法。 |
call_ later()
1 | 此方法可以通过设置定时任务和延迟时间来实现任务延时执行,并且可以在执行前通过cancel()方法重新执行定时任务。示例如下: |
1 | 这里我们设置了一个定时任务,0.2秒的时候获取网页截图,然后等待1秒,1.2秒时再次获取网页截图,访问的页面是淘宝,最后将截图结果返回。 |
http_get()
1 | 此方法可以模拟发送HTTP的GET请求,使用方法如下: |
1 | 运行结果如下: ’ |
http_post()
1 | 和http_get()方法类似,此方法用来模拟发送POST请求,不过多了一个参数bod y, 使用方法如下: |
1 | 我们用实例感受一下: |
set_content()
1 | 此方法用来设置页面的内容,示例如下: |
html()
1 | 此方法用来获取网页的源代码,它是非常简单又常用的方法。示例如下: |
png()
1 | 此方法用来获取PNG格式的网页截图,示例如下: |
jpeg()
1 | 此方法用来获取JPEG格式的网页截图,示例如下: |
har()
1 | 此方法用来获取页面加载过程描述,示例如下: |
url()
1 | 此方法可以获取当前正在访问的URL ,示例如下: |
get_cookies()
1 | 此方法可以获取当前页面的Cookies,示例如下: |
add_cookies()
1 | 此方法可以为当前页面添加C ookie,用法如下: |
clear_cookies()
1 | 此方法可以清除所有的Cookies,示例如下: |
get_viewport_size()
1 | 此方法可以获取当前浏览器页面的大小,即宽高,示例如下: |
1 | 运行结果如下: |
set_viewport_size()
1 | 此方法可以设置当前浏览器页面的大小,即宽高,用法如下: |
set_viewport_full()
1 | 此方法可以设置浏览器全屏显示,示例如下: |
set_user_agent()
1 | 此方法可以设置浏览器的User-Agent,示例如下: |
set_custom_headers()
1 | 此方法可以设置请求头,示例如下: |
select()
1 | 该方法可以选中符合条件的第一个节点,如果有多个节点符合条件,则只会返回一个,其参数是css选择器。示例如下: |
1 | 这里我们首先访问了百度,然后选中了搜索框,随后调用了 send_text()方法填写了文本,然后返回网页截图。 |
select_all()
1 | 此方法可以选中所有符合条件的节点,其参数是CSS选择器。示例如下: |
1 | 这里我们通过css选择器选中了节点的正文内容,随后遍历了所有节点,将其中的文本获取下来。 |
mouse_click()
1 | 此方法可以模拟鼠标点击操作,传入的参数为坐标值x和y。此外,也可以直接选中某个节点,然后调用此方法,示例如下: |
1 | 这里我们首先选中页面的输入框,输入了文本,然后选中“提交”按钮 ,调用了 mouse_click()方法提交查询,然后页面等待三秒,返回截图 |
Splash API 调用
1 | 前面说明了Splash Lua脚本的用法,但这些脚本是在Splash页面中测试运行的,如何才能利用Splash渲染页面呢?怎样才能和Python程序结合使用并抓取JavaScript渲染的页面呢? |
render.html
1 | 此接口用于获取JavaScript渲染的页面的HTML代码,接口地址就是Splash的运行地址加此接口名称,例如 http://localhost:8050/render.htmlo 可以用 curl 来测试一下: |
1 | 如果用Python实现的话, 代码如下: |
render.png
1 | 此接口可以获取网页截图,其参数比render.html多了几个,比如通过width和 height来控制宽高, |
1 | 如果用Python实现,可以将返回的二进制数据保存为PNG格式的图片,具体如下: |
1 | 这样我们就成功获取了京东首页渲染完成后的页面截图,详细的参数设置可以参考官网文档 |
render.jpeg
1 | 此接口和render.png类似,不过它返回的是JPEG格式的图片二进制数据。 |
render.har
1 | 此接口用于获取页面加载的HAR数据,示例如下: |
render.json
1 | 此接口包含了前面接口的所有功能,返回结果是JSON格式,示例如下: |
execute
1 | 此接口才是最为强大的接口。前面说了很多Splash Lua脚本的操作,用此接口便可实现与Lua脚本的对接。 |
1 | 我们先实现一个最简单的脚本,直接返回数据: |
1 | 然后将此脚本转化为URL编码后的字符串,拼 接 到 execute接口后面,示例如下: |
1 | 这里我们更加关心的肯定是如何用Python来实现,上例用 Python实现的话,代码如下: |
1 | 这里我们用Python中的三引号将Lua脚本包括起来,然 后 用 urllib.parse模 块 里 的 quote()方法将 |
1 | 我们再通过实例看一下: |
1 | 运行结果如下: |
1 | 可以看到,返回结果是JSON形式,我们成功获取了请求的URL ,状态码和网页源代码。 |