nginx相关反爬策略总结笔记
引言
互联网站点的流量一部分由人类正常访问行为产生,而高达30%-60%的流量则是由网络爬虫产生的,其中一部分包含友好网络爬虫,如搜索引擎的爬虫、广告程序、第三方合作伙伴程序、Robots协议友好程序等;而并非所有的网络爬虫都是友好的,爬虫流量中仍有约20%~30%的流量来自恶意网络爬虫。从网站业务安全的角度,例如文学博客、招聘网站、论坛网站、电商等网站均以文本为商品作为盈利点,而恶意爬虫则可以通过爬取核心文本从中谋取利益;竞品公司还可以通过利用恶意爬虫爬取商品价格和详情或者注册用户信息后进行同类产品线和价格的研究,通过推出过低价格等手段来破坏市场秩序;对于带宽有限的中小型网站,高频、大规模的恶意爬虫可能会降低网页加载速度,影响真实用户的访问体验,增加网站带宽负担。
本文参照实验楼实验,将Nginx部分汇总成相关笔记。
反爬虫介绍
由于恶意爬虫带来的不利影响,因此出现了爬虫防御技术-即反爬虫技术,反爬虫技术可分为被动防御机制与主动防御机制:
- 被动防御机制: 主要是根据检测结果展开的,如利用HTTP请求头User-Agent来判断、拦截爬虫请求,或对访问频率过高的IP地址进行封禁。被动防御存在部分缺陷:被动防御检测流程和机制单一,无法应对复杂多变的恶意爬虫,检测误判率高,容易造成误封、漏封。
- 主动防御机制: 是主流的爬虫防御发展方向,通过对网页底层代码的持续动态变换,增加服务器行为的“不可预测性”,大幅提升攻击难度,从而实现了从客户端到服务器端的全方位“主动防护”。
本文中所提到的关于nginx的一些操作,都属于被动防御机制。
nginx反爬策略
Nginx的配置参数是有非常多可供选择的,一般默认下载下来的格式只做了文件关联和tcp请求报文段的大小限制,而Nginx的输出日志格式为:
"$remote_addr,$time_local,$status,$body_bytes_sent,$http_user_agent,$http_referer,$request_method,$request_time,$request_uri,$server_protocol,$request_body,$http_token";
它们分别代表的意思为:
$remote_addr 客户端IP
$time_local 通用日志格式下的本地时间
$status 状态码
$body_bytes_sent 发送给客户端的字节数,不包括响应头的大小
$http_user_agent 客户端浏览器信息
$http_referer 请求的referer地址。
$request 完整的原始请求
$request_method #HTTP请求方法,通常为"GET"或"POST"
$request_time 请求处理时长
$request_uri 完整的请求地址
$server_protocol #服务器的HTTP版本,通常为 “HTTP/1.0” 或 “HTTP/1.1”
$request_body POST请求参数,参数需放form中
token $http_token (自定义header字段前加http_,即可将指定的自定义header字段打印到log中。)
version $arg_version (自定义body字段前加arg_,即可将指定的自定义header字段打印到log中。)
为此,我装门从学生机下了个Nginx,暴露了9090端口,放开来跑了两天,果然,就受到了一千多条的DDos攻击信息,正好也成为了现在写得素材,比如说其中一张截图为:
可以看到DDos还是挺频繁的,最大原因就是因为上述的配置我基本没怎么设置,所以以下将对Nginx的配置文件进行重新编写,以及使用flask做爬虫来限制。
请求头反爬
在我们访问目标站点时,浏览器会携带一些参数到服务器端,而这些参数可以被我们利用,加入或者检测某些特定值,从而鉴定爬虫程序。
浏览器的请求头,可以通过开发者工具查看,例如下图所示内容:

在开发者工具的标头视图中,寻找请求标头卡片,在其中会发现很多请求头参数。其中任意值都可以被我们用作反爬参数,接下来选择其中的某些参数,为大家展示如何反爬。
被选定的请求头参数如下:
- Referer: 请求头中用来标记请求来源页的参数,简单理解是被访问的页面是从哪里触发的。
- user-agent: 该参数携带的是客户端相关信息。
先从Referer开始讲起。
基于 Referer 参数的反爬
首先找到 default.conf
文件,通过 valid_referers
指令进行配置Nginx 配置文件,文件一般都在 /etc/nginx/conf.d
目录下,而如果是通过apt
下载的Nginx,文件就在’/etc/nginx/sites-enabled’下,比如我现在所使用的学生机,其中 referer
参数的指令格式为:
valid_referers none | blocked | server_names | string ...
参数说明:
- none:请求头缺少 Referer 字段,即 Referer 为空;
- blocked:请求头 Referer 字段不为空,并且这些值不能以
http,https
开头; - server_names :本机 server_name 配置的值可以访问;
- arbitrary string:任意字符串,定义服务器名称或可选 URI 前缀,主机名可以使用
*
号开头或结束; - regular expression:正则表达式,以
~
开头,在http://
或https://
之后的文本匹配。
接下来我们每种参数都进行一下基本设置,然后使用 python requests 模块实现模拟爬虫请求。
配置一:Referer 为空或者非 http,https 开头的字符串
修改配置文件如下:
location / {root html;index index.html index.htm;valid_referers none blocked server_names;if ($invalid_referer) {return 403;}
}
即覆盖原第一个location策略为:

修改完配置文件后,都需要重载 nginx 配置,并看见OK后就算重启成功:
root@VM-20-4-ubuntu:/etc/nginx/sites-enabled# sudo /etc/init.d/nginx reload
[ ok ] Reloading nginx configuration (via systemctl): nginx.service.
上述配置会出现如下几个场景:
- 当请求 Referer 为空时,请求可以正常返回;
- 当请求 Referer 不为空,并且以 http 或者 https 开头,请求被禁止,返回 403;
- 当请求为 server_name 设置的字符串时,请求可以正常返回。
那么我们的测试代码为:
import requestsheaders = {"referer":'http://localhost:9090'
}
res = requests.get('http://localhost:9090',headers=headers)
res.encoding = "utf-8"
print(res.text)

这里是添加了请求头的,因为加了http,所以被禁止访问,而如果将 header
设置为None,则结果为:

表示访问成功。
配置二:验证某些 Referer 可访问
修改配置文件为:
location / {root html;index index.html index.htm;valid_referers none blocked server_names*.pachong.vip pachong.*;if ($invalid_referer) {return 403;}
}
此时将字典 headers 中的 Referer 修改为如下值,然后通过下述代码测试:
import requestsheaders = {"referer":'http://localhost:9090'
}# 测试一 http://pachong.vip
header1 = {"Referer": 'http://pachong.vip'
}
# 测试二 http://pachong.vip
header2 = {"Referer": 'http://pachong.vip'
}
# 测试三 https://www.pachong.vip
header3 = {"Referer": 'https://pachong.vip'
}
# 测试四 https://www.pachong.vip
header4 = {"Referer": 'https://www.pachong.vip'
}
# 测试五 https://www.pachong.com
header5 = {"Referer": 'https://www.pachong.com'
}for i in range(1,6):res = requests.get('http://localhost:9090',headers=eval("header" + str(i)))res.encoding = "utf-8"print(res.status_code)"""
403
403
403
403
403"""
基于 user-agent 参数的反爬
user-agent 参数(简写为 UA),该参数携带的是客户端相关信息。跟Referer一样,同样可以直接在 Nginx 配置中对该参数进行验证,代码为:
server_name _;location / {root html;index index.html index.htm;# valid_referers none blocked server_names;# if ($invalid_referer) {# return 403;# }# 禁止 Scrapy 爬虫,Curl,HttpClientif ($http_user_agent ~* (Scrapy|Curl|HttpClient)) {return 403;}# First attempt to serve request as file, then# as directory, then fall back to displaying a 404.try_files $uri $uri/ =404;}
其中符号 ~*
表示正则匹配,并且不区分大小写,同样,重载配置后,测试请求代码为:
import requestsheaders = {"user-agent":"Scrapy" # 不能访问# "user-agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.54 Safari/537.36" # 可以访问
}
res = requests.get('http://localhost:9090',headers=headers)
res.encoding = "utf-8"
# print(res.text)
print(res.status_code)
"""
403
"""
当请求头中的 UA 参数被 Nginx 配置匹配成功,我们会发现,同样会直接返回 403 禁止访问,有了上述经验之后,我们可以继续更改配置文件禁止谷歌浏览器访问:
# 禁止携带 Chrome 关键字的 UA 访问
if ($http_user_agent ~* Chrome) {return 403;
}
测试文件为:
import requestsheaders = {"user-agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) 101.0.4951.54 Safari/537.36" # 能访问# "user-agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.54 Safari/537.36" # 不能访问
}
res = requests.get('http://localhost:9090',headers=headers)
res.encoding = "utf-8"
print(res.text)
print(res.status_code)
特殊参数 token 反爬
token空验证
token 表示的是令牌,在各种 Web 应用中,代表着鉴权相关的关键词,而nginx中也有这个关键字,在nginx中,token 参数一般用在请求头中,所以通过 Nginx 进行特定参数的判定,是最直接的验证方式,接下来先限制一个固定的 token 值,当 Nginx 获取的请求无此参数,或参数值不匹配时,直接返回 403 状态码。
这里跟上一节的位置一样,同样是location中,直接在 user-agent
后加上token就行了:
# 配置自定义参数,如果为空,返回 403
if ($http_token = "") {return 403;
}
修改配置文件之后,重新加载配置。然后可直接在网页端访问nginx主页,会发现被禁止:
去 /var/log/nginx/
下查看日志为:
(IP地址) - - [10/Feb/2023:16:50:26 +0800] "GET /favicon.ico HTTP/1.1" 403 208 "http://106.55.50.77:9090/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.0.0 Safari/537.36"
上图与日志的出现,表示使用浏览器默认访问,由于缺少 token 参数,已经无法拿到正确的服务器响应数据了,此时使用 Python 代码模拟携带参数的请求,代码如下:
import requests# 注意请求头字典 headers 中增加了 token,该值可以任意,但是不能为空
headers = {"referer": 'http://www.baidu.com',"token": 'xiangpica'
}
res = requests.get('http://localhost:9090', headers=headers)
print(res.text)
"""
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>body {width: 35em;margin: 0 auto;font-family: Tahoma, Verdana, Arial, sans-serif;}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p><p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p><p><em>Thank you for using nginx.</em></p>
</body>
</html>"""
发现得到了正确的数据,说明验证生效。这里还有一个trick需要特别注意,在 Nginx 配置文件中,我们检验的参数名是 $http_token
,而 Python 代码中传递的请求头参数为 token
,这个差异的出现原因是 Nginx 要求的,即请求头自定义参数在 Nginx 中读取,需要增加 $http_
这一固定前缀。
第二点需要注意的是,自定义请求头只能使用短横线 (-)连接单词,而且在 Nginx 配置端,需要将短横线修改为下划线。比如说,将配置文件改为:
if ($http_my_token = "") {return 403;
}
测试代码为:
import requestsheaders = {"referer": 'http://www.baidu.com',"my_token": 'xiangpica'
}res = requests.get('http://localhost:9090', headers=headers)
print(res.text)

而且在 Nginx 中大小写是不区分的,即 $http_My_token = ""
与 $http_my_token = ""
验证内容一致。
如果在测试中发现添加短横线之后无法匹配参数,需要添加如下参数:
underscores_in_headers on;
添加在location的上方:

或者还可以修改如下格式:
if ($http_my_token ~* "^$") {return 403;
}
token 验证固定值
有了上述经验之后,可以给 token 参数增加一个固定值判断:
# token 不等于 xiangpica,返回403
if ($http_token != "xiangpica"){return 403;
}
同样用上述代码进行测试:
import requestsheaders = {"referer": 'http://www.baidu.com',"token": 'xiangpica' # 可以修改为其它值,分别测试
}res = requests.get('http://localhost:9090', headers=headers)
print(res.text)
而根据这样一种规则,那我们就可以来模拟一种场景:前端通过用户填写的某栏数据做base64加密,然后再将加密后的字符串给后端进行解密并与存着的该用户信息比对,从而达到反爬的目的。这里复述一下流程:
- 前台使用 Base64(一种简单的加密形式)加密字符串(xiangpica)和一个时间戳;
- 后台解码前台传递过来的加密字符串,实现解密操作;
- 判断上述字符串是否可解密,解密之后是否有特定关键字。
首先更新前端代码为:
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>发送请求页面</title><script src="https://libs.baidu.com/jquery/1.11.3/jquery.min.js"></script>
</head>
<body>
<h2>该页面模拟发送 数据请求</h2>
<input id="fa" type="button" value="发送"><script type="text/javascript">$('#fa').click(function(){// 加密字符串 xiangpica + 时间戳var str64 = window.btoa("xiangpica"+Date.now());console.log(str64);$.post('/get_token',data={'token':str64},function(data){console.log(data);})})</script>
</body>
</html>
然后根据定义的接口与输入字符,写出后端接口为:
from flask import Flask
from flask import request
from flask import render_template
import base64app = Flask(__name__)@app.route('/index')
def index():return render_template('index.html')@app.route('/get_token', methods=['GET', 'POST'])
def get_token():token = request.values.get("token")# 解密前台传递过来的 token 加密串de_str = base64.b64decode(token).decode('utf-8')# 获取到字符串,然后匹配目标数据if de_str[:9] == "xiangpica":return "ok", 200else:return "error", 403if __name__ == '__main__':# app.run(host, port, debug, options)app.run(host="0.0.0.0", port=8080)
确保无误后,启动flask项目,进入网页端,我这里因为设置的是 0.0.0.0
,所以可以直接用外网进行访问:
点击发送按钮,后端界面就会根据前端传回来的base64编码进行解码,确认无误后,可以返回json信息,这里作为demo直接结束。
如果还想再复杂点,可以将前台的字符串进行二次加密,例如将 xiangpica
转换为 eGlhbmdwaWNh
,然后在进行 Base64 加密,不断提高爬虫爬取数据的难度。还可以让前台提前请求另一个接口,动态返回 token 值,让每次请求的加密关键字都不同,从而让爬虫工程师无处下手。
通过 IP 限制反爬
限制特定 IP
在常规的反爬手段中,IP 限制是应用广泛且比较有效的,但其存在一定的误杀,因同一 IP 下可能不止一位用户。本节从 Nginx 限制特定 IP 的配置开始学习,然后扩展到限制 IP 访问频次,最后通过文本文件模拟了黑名单 IP 库限制爬虫 IP 这一过程。
首先,在Nginx配置之前,还需要了解限制IP的两种机制,即 黑/白名单
- 黑名单: 在名单中的 IP 无法访问;
- 白名单: 在名单中的 IP 可以访问。
反爬中常见的是应用 IP 黑名单技术,若网站安全等级较高,可以启用 IP 白名单机制。
在最开始的DDOS攻击信息中,我们可以看到所有的攻击者的IP地址,因为Nginx本身就会将这些信息记录到日志里,那么就能很简单的构建一个黑名单机制,这里以我服务器本身ip为例,同样配置改写是在location下:
location / {root /usr/share/nginx/html;index index.html index.htm;allow 10.0.20.4;deny all;
}
将我的内网 IP 限制后,重启配置,使用 wget
进行测试:
wget 是一个从网络上自动下载文件的自由工具,支持通过 HTTP、HTTPS、FTP 三个最常见的 TCP/IP协议 下载,并可以使用 HTTP 代理。“wget” 这个名称来源于 “World Wide Web” 与 “get” 的结合。
# 测试 127.0.0.1
wget http://127.0.0.1# 测试 192.168.42.3
wget http://10.0.20.4
可以看到由于我们设置了仅允许(allow)IP 地址为 10.0.20.4
时,才可以访问目标站点,所以第一次请求 127.0.0.1
时,系统返回 403 禁止。
那么使用 deny
,毫无疑问是一种直接有效的方式,但如果IP多了,Nginx的配置文件岂不是会很长?所以,这里跟DNS的hosts文件一样,也可以做一个 blockip.conf
,可以与default同级目录下,即/etc/nginx/conf.d
:
root@VM-20-4-ubuntu:/etc/nginx/conf.d# echo 'allow 10.0.20.4;' >> blockip.conf
root@VM-20-4-ubuntu:/etc/nginx/conf.d# echo 'deny all;' >> blockip.conf
然后在主conf中添加进该路径:

那么配置就基本完成了,这里还有一个小trick,就是Nginx读配置是从上到下,假如把deny提前,那么之后的所有allow IP也就无法再登录:
所以,不管是任何的conf配置,如果参数之间有冲突,一定需要注意执行顺序。
限制 IP 访问频率
使用 Nginx 可以控制 IP 访问频率,涉及的两个配置,第一个配置是nginx.conf
下的http的设置项中,为:
limit_req_zone $binary_remote_addr zone=one:10m rate=2r/s;
参数说明:
- limit_req_zone : 该变量用于限制请求频率,只能在 http 使用;
- $binary_remote_addr: 二进制远程地址;
- zone=one: 定义一个名称为 one 的记录区,总容量为 10 M;
- rate: 每秒的请求为 2 个(测试用,实战中适当调高)。
除了上述配置外,还需要在 default.conf
中的 location 块配置如下内容:
limit_req zone=one burst=3 nodelay;
参数说明:
- zone=one : 设置使用哪个配置区域来做限制,与上面 limit_req_zone 的 name 对应;
- burst=3: burst 配置在这里,我们设置了一个大小为 3 的缓冲区,当有大量请求过来时,超过访问频次限制的请求,先放到缓冲区内等待,但不能超过 3 个,否则超过的请求会直接报 503 的错误然后返回,其中的 3 可自行设置;
- nodelay : 该参数表示超过的请求不被延迟处理。
我的位置如下:
该配置完成后,重启 Nginx 服务,否则配置不生效。
sudo /etc/init.d/nginx restart
测试的 Python 代码为:
import requestsprint(requests.get('http://127.0.0.1:9090'))
print(requests.get('http://127.0.0.1:9090'))
print(requests.get('http://127.0.0.1:9090'))
print(requests.get('http://127.0.0.1:9090'))
print(requests.get('http://127.0.0.1:9090'))
print(requests.get('http://127.0.0.1:9090'))
print(requests.get('http://127.0.0.1:9090'))
print(requests.get('http://127.0.0.1:9090'))
print(requests.get('http://127.0.0.1:9090'))
print(requests.get('http://127.0.0.1:9090'))
print(requests.get('http://127.0.0.1:9090'))

运行代码之后,得到如下响应状态码,可以看到从第 5 个请求开始,返回的是 503,你可以修改上文提及的配置值,将其调大,然后继续模拟不同数量的请求。
Cookie 反爬
通过在 Nginx 中判定特定的 Cookie 是否存在,从而实现反爬逻辑,这里跟上述的token其实类似,同样有空验证,同一个cookies验证与正则表达式,所以前面两个简单说明一下,就不再实验了,具体改的位置也还是在location中。
这里补充一下 Nginx 配置的正则方式,即匹配语法规则,例如下述 Location 的语法规则:
location [ = | ~ | ~* | ^~ | !~ | !~* ] /uri/{ … }
=
: 表示精确匹配;~
:表示区分大小写正则匹配;~*
:表示不区分大小写正则匹配;^~
:表示 URI 以某个常规字符串开头;!~
:表示区分大小写正则不匹配;!~*
: 表示不区分大小写正则不匹配;/
:通用匹配,任何请求都会匹配到。
优先级顺序为:
( location = ) > ( location 完整路径 ) > ( location ^~ 路径 ) > ( location ~,~*,!~,!~* 正则顺序 ) > ( location 部分起始路径 ) > ( / )
那么我们可以直接使用正则表达式进行cookies限制:
location / {root /usr/share/nginx/html;index index.html index.htm;if ($http_cookie !~* "example=xiangpica(\d+)"){return 403;}
}
由于在匹配规则中增加了 (\d+),即至少包含一个数字,否则会请求失败,测试代码为:
import requestsheader1 = {"cookie":"example=xiangpica;abc=test"
}header2 = {"cookie":"example=xiangpica3306;abc=test"
}res = requests.get("http://localhost:9090",headers=header1)
print(res)
res2 = requests.get("http://localhost:9090",headers=header2)
print(res2)"""
<Response [403]>
<Response [200]>"""

相关文章:

nginx相关反爬策略总结笔记
引言 互联网站点的流量一部分由人类正常访问行为产生,而高达30%-60%的流量则是由网络爬虫产生的,其中一部分包含友好网络爬虫,如搜索引擎的爬虫、广告程序、第三方合作伙伴程序、Robots协议友好程序等;而并非所有的网络爬虫都是友好的&#x…...

【Vue3】电商网站吸顶功能
头部分类导航-吸顶功能 电商网站的首页内容会比较多,页面比较长,为了能让用户在滚动浏览内容的过程中都能够快速的切换到其它分类。需要分类导航一直可见,所以需要一个吸顶导航的效果。 目标:完成头部组件吸顶效果的实现 交互要求 滚动距离大…...

HOMER docker版本安装详细流程
概述 HOMER是一款100%开源的针对SIP/VOIP/RTC的抓包工具和监控工具。 HOMER是一款强大的、运营商级、可扩展的数据包和事件捕获系统,是基于HEP/EEP协议的VoIP/RTC监控应用程序,并可以使用即时搜索、处理和存储大量的信令、RTC事件、日志和统计信息。 …...

【数据结构】单向链表的练习题
目录 前言 1、删除链表中等于给定值val的所有节点。 【题目描述】 【代码示例】 【 画图理解】 2、反转一个点链表 【题目描述】 【 代码思路】 【代码示例】 【画图理解】 3、给定一个带有头节点head的非空单链表,返回链表的中间节点,如果有两个…...

我的企业需要一个网站吗?答案是肯定的 10 个理由
如果您的企业在没有网站的情况下走到了这一步,您可能会想:我的企业需要一个网站吗?如果我的企业没有一个就已经成功了,那又有什么意义呢?简短的回答是,现在是为您的企业投资网站的最佳或更重要的时机。网站…...

CHI协议定义的NOC组件
请求结点RN 可以向NOC发送读/写等请求事务,有以下几种类型的RN: RN-F 一般是处理器核或者核簇结点,包含了局部cache和一致性部件snoopee。与NOC上的一致性部件一起,维护“可缓存”数据的一致性(这种可缓存数据…...

Python+Flask+MySQL开发的在线外卖订餐系统(附源码)
文章目录一、项目模块及功能介绍1、登录模块2、注册模块3、商家用户模块4、买家用户模块5、系统管理员模块源码二、项目结构三、环境依赖四、运行方法五、系统部分界面展示1、首页2、注册界面3、登录界面4、商家主界面5、商家菜单界面6、商家添加菜品界面7、商家修改菜品界面8、…...

OpenStack云平台搭建(4) | 部署Placement
目录 安装部署Placement 1、登录数据库授权 2、安装palcement-api 安装部署Placement 【Placement】服务 是从【nova】服务中拆分出来的组件,作用是收集各个【node】节点的可用资源,把【node】节点的资源统计写入到【MySQL】【Placement】服务会被【n…...

GNN图神经网络原理解析
一、GNN基本概念 1. 图的基本组成 图神经网络的核心就是进行图模型搭建,图是由点和边组成的。在计算机处理时,通常将数据以向量的形式进行存储。因此,在存储图时,就会有点的向量,点与点之间边的向量,全局向量(描述整张图),邻接矩阵(记录哪些点之间存在关联)等。 既…...

BI-SQL丨ALL、ANY、SOME
ALL、ANY、SOME ALL、ANY和SOME,这三个关键字,在SQL中使用频率较高,通常可以用来进行数据比较筛选。 注:SQL中ALL的用法和DAX中ALL的用法是完全不同的,小伙伴不要混淆了。 那么三者之间的区别是什么呢? A…...

从0到0.1学习 maven(三:声明周期、插件、聚合与继承)
该文章为maven系列学习的第三篇,也是最后一篇 第一篇快速入口:从0到0.1学习 maven(一:概述及简单入门) 第二篇快速入口:从0到0.1学习 maven(二:坐标、依赖和仓库) 文章目录啥子叫生命周期生命周期详解clean生命周期def…...

【直击招聘C++】2.5 this指针
2.5 this指针一、要点归纳1.什么是this指针2.this指针的深入讨论程序1程序23.类成员函数返回对象和返回对象引用的区别二、面试真题解析面试题1面试题2一、要点归纳 1.什么是this指针 this指针是隐含于每一个类对象的特殊指针,该指针值是一个正在被某个成员函数操作…...

spark数据清洗练习
文章目录准备工作删除缺失值 > 3 的数据删除星级、评论数、评分中任意字段为空的数据删除非法数据hotel_data.csv通过编写Spark程序清洗酒店数据里的缺失数据、非法数据、重复数据准备工作 搭建 hadoop 伪分布或 hadoop 完全分布上传 hotal_data.csv 文件到 hadoopidea 配置…...

Android 12首次开机启动Launcher前黑屏问题解析
在工作中,对于系统开发确实有些难度,特别是在开机阶段遇到的问题,比如开机动画播放完毕进入锁屏界面黑屏几秒然后进入 锁屏界面,这就需要根据开机日志来分析问题所在,在工作中遇到的几种黑屏情况做下记录首次开机进入L…...

使用 LSSVM 的 Matlab 演示求解反常微分方程问题(Matlab代码实现)
目录 💥1 概述 📚2 运行结果 🎉3 参考文献 👨💻4 Matlab代码 💥1 概述 LSSVM的特性 1) 同样是对原始对偶问题进行求解,但是通过求解一个线性方程组(优化目标中的线性约束导致…...

动态规划-背包问题
文章目录一、背包问题1. 背包问题简介2. 背包问题解决方法二、01 背包问题1. 实现思路2. 实现代码三、完全背包问题1. 实现思路2. 实现代码四、多重背包问题(一)1. 实现思路2. 实现代码五、多重背包问题(二)1. 实现思路2. 实现代码…...

计算24点与运算符重载
十几年前写过一个算24点的程序。记得当时有点费劲,不过最后总算捣鼓出来了。前几天突然想再写一次,结果轻松地写出来了。C,总行数不多,带命令行界面和注释共200行不到;利用了面向对象和运算符重载来简化代码。 首先谈…...

MES系统智能工厂,搭上中国制造2025顺风车
MES在电子制造业中的应用日益广泛,越来越多的厂商已经购置或自行开发了MES,并将其作为“智能化工厂”。国内大大小小、各行各业都有上百个MES系统,还有很多的国外MES系统,怎么才能在MES系统公司中找到适合自己的MES?希…...

【LeetCode】每日一题(1)
目录 题目: 解题思路: 代码: 写在最后: 题目: 这是他给出的接口: class Solution { public:int fillCups(vector<int>& amount) {} }; 作为一个数学学渣,我想不出厉害的数学算法…...

SpringCloud-Netflix学习笔记11——Hystrix实现服务降级
服务降级 是什么? 整体资源快不够了,忍痛将某些服务先关掉,待渡过难关,再开启回来。 如下图,在某一个时间段,访问服务A的请求特别多,而访问服务B和服务C的请求特别少,这时我们可以把…...

Oracle Dataguard(主库为 Oracle rac 集群)配置教程(03)—— 创建 dataguard 数据库之前的准备工作
Oracle Dataguard(主库为 Oracle rac 集群)配置教程(03)—— 创建 dataguard 数据库之前的准备工作 / 本专栏详细讲解 Oracle Dataguard(Oracle 版本为11g,主库为双节点 Oracle rac 集群)的配置…...

零代码做分析报表的bi软件才是好软件
有些数据分析软件对IT的依赖比较重,在制作报表的过程中需要用到SQL,这就导致了IT人员懂技术不懂业务,业务人员懂业务不懂技术,数据分析做来做去总是差点什么的局面。要是遇到了IT部门相对较弱的情况,还会加重IT负担&am…...

linux ALSA 驱动架构
一、kernel Audio驱动架构主流有两大类,一类是SOC Machine架构,另一类是simple-card架构。 MTK、QCom主要采用machine架构,rockchip采用simple card架构。 二、Machine架构驱动介绍 machine 架构每家平台实现并不完全相同,mach…...

JDK 8 JVM内存结构详解
前言 本文所介绍的是 JDK 1.8 版本,其他版本的 JDK 在这里并不一定正确;内容主要摘自周志明的《深入理解Java虚拟机》一书的关键点,并根据自身的理解进行记录。感兴趣的同学可以去阅读原著。 JVM 的内存结构,主要包括以下 5 个区…...

黑马程序员 Linux 教程
目录Linux 简介不同应用领域主流操作系统Linux 系统历史Linux 系统版本Linux 安装安装方式网卡设置安装 SSH 连接工具使用 FinalShell 连接到 LinuxLinux 和 Windows 目录结构对比Linux 目录介绍Linux 常用命令Linux 命令初体验Linux 命令使用技巧Linux 命令格式文件目录操作命…...

文件操作 -- IO
文章目录文件操作 -- IO文件 :文件路径 :文件的类型java 中的文件操作文件内容的相关操作字节流的读和写操作字符流的读和写操作代码案例代码案例一 :代码案例二 :代码案例三 :文件操作 – IO 文件 : 文件相比大家都不陌生把 , 打…...

FPGA解析串口协议帧3.0版本,增加了错误重发功能,提供仿真文件以及源码
FPGA解析串口协议帧已经发布2个版本了,分别如下: 版本1:点击查看版本1 版本1详细介绍了串口协议帧的帧组成和设计思想,但设计粗糙,注释不详细; 版本1:点击查看版本2 版本2优化了代码,…...

365天深度学习训练营 第P6周:好莱坞明星识别
🍨 本文为🔗365天深度学习训练营 内部限免文章(版权归 K同学啊 所有)🍦 参考文章地址: 🔗第P6周:好莱坞明星识别 | 365天深度学习训练营🍖 作者:K同学啊 | 接…...

一文读懂 Zebec Chain 的“先行网络” Nautilus 链
最近,Zebec 上线了 DAO 治理系统后,上线并通过了关于 Nautilus 链的提案,这也是DAO系统上线后通过的首个提案。 Nautilus 链可以被看作是Zebec Chain上线前的“先行”链,并且是目前行业内为数不多的以“Layer3”作为特点的模块化通…...

FuzzyMathematicalModel模糊数学模型-2-多目标模糊综合评价案例分享
主函数:clc, clear% 输入模糊矩阵的原型x [4700 6700 5900 8800 76005000 5500 5300 6800 600004.0 06.1 05.5 07.0 06.80030 0050 0040 0200 01601500 0700 1000 0050 0100];r muti_objective_fuzzy_analysis(x);% 各指标在决策中占的权重(专家系统,自…...