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

1. 功能介绍和基本实例

### Splash的使用
'''
Splash是一个JavaScript渲染服务,是一个带有HTTP API的轻量级浏览器,同时它对接了Python中的Twisted和QT库。
利用它,我们同样可以实现动态渲染页面的抓取。
''' ## 功能介绍
# 1.异步方式处理多个网页渲染过程
# 2.获取渲染后页面的源代码或截图
# 3.通过关闭图片渲染或者使用Adblock规则来加快页面渲染速度
# 4.可执行特定的JavaScript脚本
# 5.可通过Lua脚本来控制页面渲染过程
# 6.获取渲染的详细过程并通过HAR(HTTP Archive)格式呈现 ## 基本实例
function main(splash, args)
splash:go("http://www.baidu.com")
splash:wait(0.5)
local title = splash:evaljs("document.title")
return {
title = title
}
end

2. Splash用lua脚本爬取网页的基本使用介绍

  2.1 异步处理

## 异步处理
# ipairs,为集合元素进行编号(编号从1开始),类似于python的enumerate
# lua脚本语言中字符串拼接用 ..
# splash:wait()类似于python中的time.sleep()
# 当Splash执行wait方法时,它会转而去处理其他任务,等到指定时间结束后再回来进行继续处理 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

  2.2 Splash的对象属性

2.2.1 args,main方法中的第二个args属性即加载到splash中,即 args.url == splash.args.url

2.2.2 js_enabled,页面JavaScript的执行开关,默认为true

## js_enabled,页面JavaScript的执行开关,默认为True
function main(splash, args)
splash:go("http://www.baidu.com")
splash.js_enabled = False
local title = splash:evaljs("document.title")
return {
title = title
}
end '''
执行结果:
{
"error": 400,
"type": "ScriptError",
"description": "Error happened while executing Lua script",
"info": {
"type": "SPLASH_LUA_ERROR",
"message": "[string \"function main(splash, args)\r...\"]:3: setAttribute(self, QWebSettings.WebAttribute, bool): argument 2 has unexpected type 'NoneType'",
"source": "[string \"function main(splash, args)\r...\"]",
"line_number": 3,
"error": "setAttribute(self, QWebSettings.WebAttribute, bool): argument 2 has unexpected type 'NoneType'"
}
}
'''

2.2.3 resource_timeout,页面加载超时时间,单位是秒

## resource_timeout,页面加载超时时间,单位是秒
function main(splash, args)
splash.resource_timeout = 0.01
assert(splash:go("http://www.baidu.com"))
return splash:png()
end '''
{
"error": 400,
"type": "ScriptError",
"description": "Error happened while executing Lua script",
"info": {
"source": "[string \"function main(splash, args)\r...\"]",
"line_number": 3,
"error": "network5",
"type": "LUA_ERROR",
"message": "Lua error: [string \"function main(splash, args)\r...\"]:3: network5"
}
}
'''

2.2.4 images_enabled,页面图片是否加载,默认为true

## images_enabled,页面图片是否加载,默认为True
## 禁用图片可以节省网络流量以及加快网页加载速度,当加载页面可能会影响JavaScript的渲染
## Splash使用了缓存,即访问过一次页面的图片,即使禁用页面图片加载后,依旧可以访问到缓存中的图片
## 如下面示例,返回的phg页面就不会带有图片 function main(splash, args)
splash.images_enabled = false
assert(splash:go("https://www.bilibili.com/"))
return {
png = splash:png()
}
end

2.2.4 plugins_enabled,控制浏览器插件(如flash等)是否开启,默认为false

2.2.5 scroll_position,控制页面的上下左右滚动,用x定位左右,y定位上下;如下示例,定位到y=800的位置

## scroll_position,控制页面的上下左右滚动,用x定位左右,y定位上下;如下示例,定位到y=800的位置

function main(splash, args)
assert(splash:go("https://www.mi.com"))
splash.scroll_position = {y = 800}
return {png = splash:png()}
end

2.3 Splash对象的方法

2.3.1 go方法,用来请求某个链接,可以模拟get和post请求,同时传入请求头、表单等数据,赋值传入变量时用{}

## go方法,用来请求某个链接,可以模拟get和post请求,同时传入请求头、表单等数据,赋值传入变量时用{}
## go方法有2个返回值,ok和reason,ok为空代表网页加载出现错误,此时reason变量中包含错误原因
# url:请求的URL
# baseurl:可选参数,默认为空,表示自愿加载的相对路径
# headers:可选参数,默认为空,请求头
# http_method:可选参数,默认为get,可以支持post
# body:可选参数,默认为空,发post请求时的表单数据,传入的数据内容类型为json
# formdata:可选参数,默认为空,发post请求时的表单数据,传入的数据内容类型为x-www-form-urlencoded function main(splash, args)
local ok, reason = splash:go{url="http://httpbin.org/post", http_method="POST", body="name=dmr"}
if ok then
return splash:html()
end
end

2.3.2 wait方法,控制页面的等待时间,可以传入多值,赋值传入变量时用{}

## wait方法,控制页面的等待时间,可以传入多值,赋值传入变量时用{}
## 同样有2个返回值,ok和reason,ok为空代表网页加载出现错误,此时reason变量中包含错误原因
## ok, reason = splash:go{time, cancel_on_redirect=false, cancel_on_error=false}
# time:等待的秒数
# cancel_on_redirect:可选参数,默认为false,表示如果发生了重定向则停止等待并返回重定向结果
# cancel_on_error:可选参数,默认为false,表示如果发生了错误就停止等待 function main(splash, args)
local ok, reason = splash:go("http://www.mi.com")
splash:wait(2)
if ok then
return splash:html()
end
end

2.3.3 JavaScript等的操作方法

## jsfunc方法,可以直接调用JavaScript定义的方法,所调用的方法要用双括号包围
## 如下示例,通过构造JavaScript方法来获取访问页面的title和div数量并返回
function main(splash, args)
local get_div_count = splash:jsfunc([[
function(){
var title = document.title;
var body = document.body;
var divs = body.getElementsByTagName('div');
var div_count = divs.length;
return {div_count, title};
}
]])
ok, reason = splash:go("https://www.mi.com")
result = get_div_count()
return ("This page'title is %s, there are %s divs"):format(result.title, result.div_count)
end ## evaljs方法,可以执行JavaScript代码并返回最后一条JavaScript的返回结果
## 如下示例,只返回最后一条JavaScript语句的执行结果
function main(splash, args)
splash:go("https://www.mi.com")
result = splash:evaljs("document.title;document.body.getElementsByTagName('div').length;")
return result
end ## runjs方法,可以执行JavaScript代码,与evaljs类似,但是更偏向于执行某些动作或声明某些方法
## 如下示例,用runjs方法构造了一个JavaScript定义的方法,然后用evaljs执行此方法获取返回结果
function main(splash, args)
splash:go("https://www.mi.com")
splash:runjs("fofo = function(){return 'dmr'}")
result = splash:evaljs('fofo()')
return result
end ## autoload方法,可以设置每个页面访问时自动加载的对象,在Lua语言中nil相当于python的None
## ok, reason = splash:autoload{source_or_url, source=nil, url=nil}
# source_or_url:JavaScript代码或JavaScript库链接
# source:JavaScript代码
# url:JavaScript库链接
# 示例1,通过构造一个get_path_title对象方法,用evaljs调用执行获取返回结果,在这里与runjs类似,不过构造方法需要用[]中括号
function main(splash, args)
splash:autoload([[
function get_path_title(){
return document.title;
}
]])
splash:go("https://www.mi.com")
result = splash:evaljs('get_path_title()')
return result
end # 示例2,用autoload加载jquery方法库
function main(splash, args)
assert(splash:autoload("https://code.jquery.com/jquery-2.2.4.min.js"))
assert(splash:go("https://www.baidu.com"))
local version = splash:evaljs("$.fn.jquery")
return 'Version is '..version
end

2.3.4 call_later方法,设置定时任务进行延时执行,并且可以在执行前通过cancel()方法重新执行定时任务

## call_later方法,设置定时任务进行延时执行,并且可以在执行前通过cancel()方法重新执行定时任务
# 如下示例,构造一个timer定时任务,当访问页面时,等待0.2秒获取页面的截图,再等待1秒后获取页面的截图
# 第一次获取页面的截图页面还没加载出来,所以获取到的是空白页 function main(splash, args)
local pngs = {}
local timer = splash:call_later(function()
pngs['a'] = splash:png()
splash:wait(1)
pngs['b'] = splash:png()
end, 0.2)
splash:go("https://www.mi.com")
return pngs
end

2.3.5 http_get方法,模拟发送http的get请求

## http_get方法,模拟发送http的get请求
## response = splash:http_get{url, headers=nil, follow_redirects=true}
# url:请求URL
# headers:可选参数,默认为空,请求头
# follwo_redirects:可选参数,表示是否启动自动重定向,默认为true function main(splash, args)
local t = require("treat")
local response = splash:http_get("https://www.taobao.com")
if response.status == 200 then
return {
b_html = response.body,
html = t.as_string(response.body),
url = response.url,
status = response.status,
}
end
end

2.3.6 http_post方法,模拟发送http的post请求,与http_get方法类似,不过多个body表单参数

## http_post方法,模拟发送http的post请求,与http_get方法类似,不过多个body表单参数
## response = splash:http_get{url, headers=nil, follow_redirects=true, body=nil}
# url:请求URL
# headers:可选参数,默认为空,请求头
# follwo_redirects:可选参数,表示是否启动自动重定向,默认为true
# body:可选参数,默认为空,表单数据
# 如下示例,将表单数据提交到了json中 function main(splash, args)
local t = require("treat")
local json = require("json")
local response = splash:http_post{
"http://httpbin.org/post",
body=json.encode({name="dmr"}),
headers={["content-type"]="application/json"}
}
if response.status == 200 then
return {
'response',
b_html = response.body,
html = t.as_string(response.body),
url = response.url,
status = response.status,
}
end
end

2.3.7 set_content方法,用来设置页面的内容

## set_content方法,用来设置页面的内容
## 如下示例,可以看到页面中有dmr的内容 function main(splash, args)
assert(splash:set_content("<h1>dmr</h1>"))
return splash:png()
end

2.3.8 html方法,用来获取网页的源代码

## html方法,用来获取网页的源代码

function main(splash, args)
assert(splash:go("https://www.baidu.com"))
return splash:html()
end

2.3.9 png方法和jpeg方法,用来获取网页页面png格式或jpeg格式的截图

## png方法和jpeg方法,用来获取网页页面png格式或jpeg格式的截图

function main(splash, args)
assert(splash:go("https://www.baidu.com"))
return {
png = splash:png(),
jpeg = splash:jpeg()
}
end

2.3.10 har方法,用来获取页面加载过程描述

## har方法,用来获取页面加载过程描述

function main(splash, args)
assert(splash:go("https://www.baidu.com"))
return {
har = splash:har()
}
end

2.3.11 url方法,用来获取当前正在访问页面的url

## url方法,用来获取当前正在访问页面的url

function main(splash, args)
assert(splash:go("https://www.baidu.com"))
return {url = splash:url()}
end

2.3.12 Cookies操作

## get_cookies方法,用来获取当前页面的cookies
function main(splash, args)
assert(splash:go("https://www.baidu.com"))
return {cookies = splash:get_cookies()}
end ## add_cookie方法,为当前页面添加cookie
## splash:add_cookie{name, value, path=nil, domain=nil, expires=nil, httpOnly=nil, secure=nil}
function main(splash, args)
splash:add_cookie{'name', 'dmr'}
assert(splash:go("https://www.baidu.com"))
return {cookies = splash:get_cookies()}
end ## clear_cookies方法,清楚所有的cookies
function main(splash, args)
splash:add_cookie{'name', 'dmr'}
assert(splash:go("https://www.baidu.com"))
splash:clear_cookies()
return {cookies = splash:get_cookies()}
end

2.3.13 浏览器视图操作

## get_viewport_size方法,用来获取当前页面的大小,即宽高
function main(splash, args)
assert(splash:go("https://www.taobao.com"))
return splash:get_viewport_size()
end ## set_viewport_size方法,设置当前浏览器页面的大小,即宽高
function main(splash, args)
splash:set_viewport_size(400, 400)
assert(splash:go("https://www.taobao.com"))
return splash:png()
end ## set_viewport_full方法,用来设置浏览器全屏显示
function main(splash, args)
splash:set_viewport_full()
assert(splash:go("https://www.taobao.com"))
return splash:png()
end

2.3.14 set_user_agent方法,用来设置浏览器的User-Agent

## set_user_agent方法,用来设置浏览器的User-Agent

function main(splash, args)
splash:set_user_agent('Splash')
assert(splash:go("https://httpbin.org/get"))
return splash:html()
end

2.3.15 set_custom_headers方法,可以用来设置请求头

## set_custom_headers方法,可以用来设置请求头

function main(splash, args)
splash:set_custom_headers({
["User-Agent"] = "Splash",
["Host"] = "Splash.org"
})
assert(splash:go("https://httpbin.org/get"))
return splash:html()
end

2.3.16 select方法,查找符合条件的第一个节点,用的是CSS选择器

## select方法,查找符合条件的第一个节点,用的是CSS选择器

function main(splash, args)
assert(splash:go("https://www.taobao.com"))
input = splash:select("#q")
input:send_text("数码")
splash:wait(2)
return splash:jpeg()
end

2.3.17 select_all方法,查找符合条件的所有节点,用的是CSS选择器

## select_all方法,查找符合条件的所有节点,用的是CSS选择器

function main(splash, args)
local treat = require("treat")
assert(splash:go("https://movie.douban.com/top250"))
assert(splash:wait(1))
local items = splash:select_all(".inq")
local sum = {}
for index, item in ipairs(items) do
sum[index] = item.node.innerHTML
end
return {
obj1 = sum,
obj2 = treat.as_array(sum)
}
end

2.3.18 mouse_click方法,模拟鼠标点击操作

## mouse_click方法,模拟鼠标点击操作
## 1.传入x和y进行点击操作
## 2.查找到相关节点,调用此方法进行点击操作 function main(splash, args)
splash:go("https://www.baidu.com")
input = splash:select("#kw")
input:send_text("Python")
splash:wait(1)
search = splash:select('#su')
search:mouse_click()
splash:wait(2)
return splash:png()
end

3. Splash API的调用,以Python为例

    官方API文档:https://splash.readthedocs.io/en/stable/api.html

  3.1 render.html页面,此接口用于获取JavaScript渲染的页面的HTML代码

## render.html页面,此接口用于获取JavaScript渲染的页面的HTML代码
## 获取百度页面源代码url示例:http://localhost:8050/render.html?url=https://www.baidu.com
# 示例,通过调用render.html页面获取百度的源代码并且设置等待时间为4秒
import requests url = 'http://10.0.0.100:8050/render.html?url=https://www.baidu.com&wait=4'
response = requests.get(url)
print(response.text)

  3.2 render.png和render.jpeg,此接口获取网页截图, 返回的是二进制数据

## render.png和render.jpeg,此接口获取网页截图,返回的是二进制数据
## 配置参数:url,wait,width,height
## render.jpeg多了个参数quality,用来调整图片的质量,取值1-100,默认值为75,应尽量避免取95以上的数值
## url示例:http://localhost:8050/render.png?url=https://www.baidu.com&wait=2&width=400&height=400
# 示例,通过render.png接口获取页面宽400高400的页面截图并保存到文件中
import requests url = 'http://10.0.0.100:8050/render.png?url=https://www.taobao.com&wait=5&width=1000&height=700'
url2 = 'http://10.0.0.100:8050/render.jpeg?url=https://www.taobao.com&wait=5&width=1000&height=700&quality=90'
response = requests.get(url)
with open('taobao.png', 'wb') as f:
f.write(response.content)
response2 = requests.get(url2)
with open('taobao.jpeg', 'wb') as f:
f.write(response2.content)

  3.3 render.har,此接口用来获取页面加载的HAR数据,返回的是json格式的数据

## render.har,此接口用来获取页面加载的HAR数据,返回的是json格式的数据
## url示例:http://localhost:8050/render.har?url=https://www.baidu.com&wait=2
import requests, json url = 'http://10.0.0.100:8050/render.har?url=https://www.baidu.com&wait=2'
response = requests.get(url)
print(response.content)
with open('har.text', 'w') as f:
f.write(json.dumps(json.loads(response.content), indent=2))

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

## render.json,此接口包含了前面接口的所有功能,返回结果是json格式
## url示例:http://localhost:8050/render.json?url=https://www.baidu.com&html=1&png=1&jpeg=1&har=1
## 默认返回:{'url': 'https://www.baidu.com/', 'requestedUrl': 'https://www.baidu.com/', 'geometry': [0, 0, 1024, 768], 'title': '百度一下,你就知道'}
## 通过将html、png、jpeg、har参数置为1获取相关的页面数据
import requests, json url = 'http://10.0.0.100:8050/render.json?url=https://www.baidu.com&html=1&png=1&jpeg=1&har=1'
response = requests.get(url) data = json.loads(response.content)
print(data)
print(data.get('html'))
print(data.get('png'))
print(data.get('jpeg'))
print(data.get('har'))

  3.5 execute,功能强大,此接口可实现与Lua脚本的对接,实现交互性操作

## execute,此接口可实现与Lua脚本的对接,可实现交互性操作
## url示例:http://localhost:8050/execute?lua_source=
# 示例1,简单示例,返回lua的执行结果
from urllib.parse import quote
import requests lua = '''
function main(splash)
return 'hello'
end
'''
url = 'http://10.0.0.100:8050/execute?lua_source=%s' % quote(lua)
response = requests.get(url)
print(response.text)
# 示例2,通过execute执行lua脚本获取页面的url,png,html
from urllib.parse import quote
import requests, json lua = '''
function main(splash)
splash:go('https://www.baidu.com')
splash:wait(2)
return {
html = splash:html(),
png = splash:png(),
url = splash:url()
}
end
'''
url = 'http://10.0.0.100:8050/execute?lua_source=%s' % quote(lua)
response = requests.get(url)
print(type(response.text), response.text)
dic = json.loads(response.text)
print(type(dic), len(dic), dic.keys())

4. Splash通过Nginx配置负载均衡基本思路

1. 配置多台splash服务器

2. 选中其中一台或者另起一台服务器安装nginx服务

3. 配置nginx.conf配置文件,内容大致为:
http {
upstream splash {
least_conn; #最少连接负载均衡,不配置这进行轮询,ip_hash配置ip散列负载均衡
server 10.0.0.100:8050;
server 10.0.0.99:8050;
server 10.0.0.98:8050;
server 10.0.0.97:8050;
}
server {
listen 8050;
location / {
proxy_pass http://splash; # 指定域名
auth_basic "Restricted"; # 配置认证
auth_basic_user_file /etc/nginx/conf.d/.htpasswd; # 指定认证的用户密码文件
}
}
} 4. 如不配置认证,直接重载nginx:sudo nginx -s reload;配置了认证则需要构建密码文件,建议用htpasswd命令构建,在重载nginx 5. 进行相关测试,测试脚本
from urllib.parse import quote
import requests, re lua = '''
function main(splash)
local treat = require('treat')
response = splash:http_get('https://www.baidu.com')
return treat.as_string(response.body)
end
'''
url = 'http://splash/execute?lua_source=%s' % quote(lua)
response = requests.get(url)
ip = re.search('(\d+\.\d+\.\d+\.\d+)', response.text).group(1)
print(ip)

爬虫动态渲染页面爬取之Splash的介绍和使用的更多相关文章

  1. 爬虫动态渲染页面爬取之selenium驱动chrome浏览器的使用

    Selenium是一个用于Web应用程序测试的工具.Selenium测试直接运行在浏览器中,就像真正的用户在操作一样,可以用其进行网页动态渲染页面的爬取. 支持的浏览器包括IE(7, 8, 9, 10 ...

  2. 动态渲染页面爬取-Selenium & Splash

    模拟浏览器的动机 JS动态渲染的页面不止Ajax一种 很多网页的Ajax接口含有加密参数,分析其规律的成本过高 通过对浏览器运行方式的模拟,我们将做到:可见即可爬 Python中常用的模拟浏览器运行的 ...

  3. 动态渲染页面爬取(Python 网络爬虫) ---Selenium的使用

    Selenium 的使用 Selenium 是一个自动化测试工具,利用它可以驱动浏览器执行特定的动作,如点击.下拉等操作,同时还可以获取浏览器当前呈现的页面的源代码,做到可见即可爬.对于一些JavaS ...

  4. 爬虫之Selenium 动态渲染页面爬取

    Selenim 是一个自动化测试工具,可以利用它驱动浏览器执行特定的动作,如点击.下拉等操作,同时可以获取浏览器当前呈现的页面的源代码,做到可见及可爬 1.使用流程 1)声明浏览器对象 Seleniu ...

  5. python3编写网络爬虫14-动态渲染页面爬取

    一.动态渲染页面爬取 上节课我们了解了Ajax分析和抓取方式,这其实也是JavaScript动态渲染页面的一种情形,通过直接分析Ajax,借助requests和urllib实现数据爬取 但是javaS ...

  6. [Python3网络爬虫开发实战] 7-动态渲染页面爬取

    在前一章中,我们了解了Ajax的分析和抓取方式,这其实也是JavaScript动态渲染的页面的一种情形,通过直接分析Ajax,我们仍然可以借助requests或urllib来实现数据爬取. 不过Jav ...

  7. 【图文详解】scrapy爬虫与动态页面——爬取拉勾网职位信息(2)

    上次挖了一个坑,今天终于填上了,还记得之前我们做的拉勾爬虫吗?那时我们实现了一页的爬取,今天让我们再接再厉,实现多页爬取,顺便实现职位和公司的关键词搜索功能. 之前的内容就不再介绍了,不熟悉的请一定要 ...

  8. 爬虫系列5:scrapy动态页面爬取的另一种思路

    前面有篇文章给出了爬取动态页面的一种思路,即应用Selenium+Firefox(参考<scrapy动态页面爬取>).但是selenium需要运行本地浏览器,比较耗时,不太适合大规模网页抓 ...

  9. 爬虫系列4:scrapy技术进阶之多页面爬取

    多页面爬取有两种形式. 1)从某一个或者多个主页中获取多个子页面的url列表,parse()函数依次爬取列表中的各个子页面. 2)从递归爬取,这个相对简单.在scrapy中只要定义好初始页面以及爬虫规 ...

随机推荐

  1. [no code] Scrum Meeting 博客目录

    项目 内容 2020春季计算机学院软件工程(罗杰 任健) 2020春季计算机学院软件工程(罗杰 任健) 作业要求 Scrum Meeting博客目录 我们在这个课程的目标是 远程协同工作,采用最新技术 ...

  2. Request failed with status code 500以及自引用循环Self referencing loop detected for property ‘xx‘ with type

    错误Error: Request failed with status code 500 ,调试前端没问题,后端也没问题,还报错"连接超时" 在Network中找到错误Self r ...

  3. stm32直流电机驱动与测速

    stm32直流电机驱动与测速 说实话就现在的市场应用中stm32已经占到了绝对住到的地位,51已经成为过去式,32的功能更加强大,虽然相应的难度有所增加,但是依然阻止不了大家学习32的脚步,不说大话了 ...

  4. 转:汇编中EBP寄存器和ESP寄存器的区别

    EBP和ESP都是汇编中关于指针的寄存器.但是定义不同: (1)ESP:栈指针寄存器(extended stack pointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的栈顶.(2 ...

  5. telnet IP 端口 的作用

    测试远程服务器的端口是否开启

  6. etcd安装常用操作

    etcd安装 etcd 是基于 Raft 的分布式 key-value 存储系统,由 CoreOS 开发,常用于服务发现.共享配置以及并发控制(如 leader 选举.分布式锁等).kubernete ...

  7. 【java+selenium3】模态框处理(五)

    一.模态框的定义: 模态对话框(Modal Dialogue Box , 又叫做模式对话框),是指在用户想要对话框以外的应用程序进行操作时候,必须先对该对话框进行响应.如单击[确定]或者[返回]按钮等 ...

  8. NAT & 防火墙

    NAT 网络地址转换 NAT产生背景 今天,无数快乐的互联网用户在尽情享受Internet带来的乐趣.他们浏览新闻,搜索资料,下载软件,广交新朋,分享信息,甚至于足不出户获取一切日用所需.企业利用互联 ...

  9. OSI模型 & TCP/IP模型

    分层思想 分层思想:将复杂 的流程分解 为几个功能相对单一 的子过程 整个流程更加清晰 ,复杂问题简单化 更容易发现问题并针对性的解决问题 分层思想在网络中的应用 OSI模型 国际标准化组织(Inte ...

  10. oxidized备份华为HRP防火墙配置失败问题

    Oxidized备份华为防火墙配置Last Status红色,备份失败,查看oxidized日志(默认是~/.config/oxidized/logs/oxidized.log)能看到报错日志: WA ...