Python抓取靜態(tài)網(wǎng)頁(yè)數(shù)據(jù)的完整指南
一.什么是靜態(tài)網(wǎng)頁(yè)
1.靜態(tài)網(wǎng)頁(yè)的含義
靜態(tài)網(wǎng)頁(yè)是指網(wǎng)頁(yè)的內(nèi)容在服務(wù)器上被創(chuàng)建和存儲(chǔ)時(shí)就已經(jīng)完全確定好了。當(dāng)用戶通過(guò)瀏覽器請(qǐng)求這個(gè)網(wǎng)頁(yè)時(shí),服務(wù)器會(huì)原封不動(dòng)地將這個(gè)預(yù)先制作好的文件(通常是.html、.css、.js文件),發(fā)送給用戶的瀏覽器。網(wǎng)頁(yè)的內(nèi)容不會(huì)因用戶的不同,時(shí)間的變化或用戶的交互而改變。
可以想象成一本書(shū)的某一頁(yè),或者一張打印出來(lái)的宣傳單頁(yè):它的內(nèi)容在印刷完成的那一刻就已經(jīng)固定了。
2.靜態(tài)網(wǎng)頁(yè)的特點(diǎn)
1.內(nèi)容固定不變
網(wǎng)頁(yè)上的所有文字、圖片、布局和鏈接都是開(kāi)發(fā)人員在編寫(xiě)代碼時(shí)就已經(jīng)確定好的,除非開(kāi)發(fā)人員手動(dòng)修改源代碼并且重新上傳到服務(wù)器,否則任何用戶在任何時(shí)間、任何地點(diǎn)看到的網(wǎng)頁(yè)內(nèi)容都是一樣的
2.服務(wù)器處理簡(jiǎn)單
服務(wù)器不需要處理任何額外的程序或查詢數(shù)據(jù)庫(kù),它的任務(wù)僅僅是找到用戶查詢的文件,然后把它發(fā)送出去。這就像從一個(gè)文件柜里取出一個(gè)已經(jīng)歸檔的文件。
3.加載速度快
因?yàn)榉?wù)器不需要進(jìn)行任何動(dòng)態(tài)數(shù)據(jù)處理,所以相應(yīng)速度非常快。能極大提升用戶體驗(yàn)和搜索引擎排名
4.開(kāi)發(fā)成本低,易于部署
靜態(tài)網(wǎng)頁(yè)通常只由HTML、CSS、JavaScript這三種前端技術(shù)組成,開(kāi)發(fā)簡(jiǎn)單,對(duì)服務(wù)器環(huán)境要求低,部署也非常方便
5.安全性高
由于沒(méi)有與數(shù)據(jù)庫(kù)的交互和執(zhí)行服務(wù)器端腳本(如PHP、Python),它受黑客攻擊的入口點(diǎn)更少,因此比動(dòng)態(tài) 網(wǎng)頁(yè)更安全
3.靜態(tài)網(wǎng)頁(yè)的技術(shù)構(gòu)成
- HTML:負(fù)責(zé)網(wǎng)頁(yè)的內(nèi)容和結(jié)構(gòu),比如標(biāo)題、段落、圖片、鏈接等
- CSS:負(fù)責(zé)網(wǎng)頁(yè)的樣式和布局,比如顏色、字體、間距、相應(yīng)式設(shè)計(jì)等
- JavaScript:負(fù)責(zé)網(wǎng)頁(yè)的交互行為,比如下拉表單、圖片輪播、表單驗(yàn)證等
重要提示:一個(gè)網(wǎng)頁(yè)即使包含了復(fù)雜的JavaScript動(dòng)畫(huà)和交互,只要它的核心內(nèi)容(如文章、產(chǎn)品、公司介紹)是預(yù)先寫(xiě)死在HTML里面的,它仍然屬于靜態(tài)網(wǎng)頁(yè)
4.靜態(tài)網(wǎng)頁(yè) vs. 動(dòng)態(tài) 網(wǎng)頁(yè)
為了更好地理解,我們將其與動(dòng)態(tài) 網(wǎng)頁(yè)進(jìn)行對(duì)比:
| 特性 | 靜態(tài)網(wǎng)頁(yè) | 動(dòng)態(tài) 網(wǎng)頁(yè) |
|---|---|---|
| 內(nèi)容來(lái)源 | 預(yù)先編寫(xiě)好的HTML文件 | 服務(wù)器端腳本(PHP, Python, Node.js等)實(shí)時(shí)從數(shù)據(jù)庫(kù)或其他數(shù)據(jù)源獲取數(shù)據(jù)并生成HTML |
| 內(nèi)容變化 | 手動(dòng)更新源代碼 | 根據(jù)用戶、時(shí)間、數(shù)據(jù)庫(kù)狀態(tài)等自動(dòng)變化 |
| 服務(wù)器負(fù)載 | 低(主要是文件傳輸) | 高(需要執(zhí)行腳本和數(shù)據(jù)庫(kù)查詢) |
| 開(kāi)發(fā)復(fù)雜度 | 低 | 高 |
| 典型例子 | 公司官網(wǎng)、個(gè)人博客、產(chǎn)品介紹頁(yè)、活動(dòng)宣傳頁(yè) | 社交媒體(如微博、微信)、電商網(wǎng)站(如淘寶)、在線郵箱(如Gmail) |
5.現(xiàn)代靜態(tài)網(wǎng)站的演進(jìn)
傳統(tǒng)的靜態(tài)網(wǎng)頁(yè)概念在今天有了一些新的發(fā)展,特別是 Jamstack 架構(gòu)的流行。
Jamstack 的核心思想是:
- 預(yù)渲染:在部署之前,使用靜態(tài)站點(diǎn)生成器(如 Gatsby, Next.js, Hugo, Jekyll)將網(wǎng)站的所有頁(yè)面提前生成為靜態(tài)文件。
- 解耦架構(gòu):通過(guò) APIs 和 微服務(wù) 來(lái)處理動(dòng)態(tài)功能。
例如:一個(gè)新聞網(wǎng)站。
傳統(tǒng)靜態(tài):每篇新文章都需要手動(dòng)寫(xiě)一個(gè)HTML文件。
現(xiàn)代Jamstack:
- 編輯在內(nèi)容管理系統(tǒng)(如WordPress + Headless插件,或Contentful)中寫(xiě)好文章。
- 當(dāng)文章發(fā)布時(shí),會(huì)觸發(fā)一個(gè)構(gòu)建流程。
- 靜態(tài)站點(diǎn)生成器(如Gatsby)會(huì)從CMS的API獲取這篇新文章的內(nèi)容,自動(dòng)生成一個(gè)新的靜態(tài)HTML頁(yè)面,并更新網(wǎng)站列表頁(yè)。
- 最后將整個(gè)更新后的靜態(tài)網(wǎng)站部署到服務(wù)器。
這樣,它既保留了靜態(tài)網(wǎng)站快速、安全的優(yōu)點(diǎn),又具備了易于內(nèi)容更新的動(dòng)態(tài)能力。
二.抓取靜態(tài)網(wǎng)頁(yè)的技術(shù)
靜態(tài)網(wǎng)頁(yè)是HTML格式的網(wǎng)頁(yè),這種網(wǎng)頁(yè)在瀏覽器中呈現(xiàn)的內(nèi)容都會(huì)體現(xiàn)在源代碼中。如果我們要抓取靜態(tài)網(wǎng)頁(yè)的數(shù)據(jù),只需要獲得網(wǎng)頁(yè)的源代碼即可。
網(wǎng)絡(luò)爬蟲(chóng)抓取靜態(tài)網(wǎng)頁(yè)數(shù)據(jù)的過(guò)程是獲得網(wǎng)頁(yè)原代碼的過(guò)程,這個(gè)過(guò)程也就是模擬用戶通過(guò)瀏覽器訪問(wèn)網(wǎng)頁(yè)的過(guò)程,包括向Web服務(wù)器發(fā)送HTTP請(qǐng)求、服務(wù)器對(duì)HTTP請(qǐng)求作出相應(yīng)并返回網(wǎng)頁(yè)源代碼
ulrlib、urllib3、requests是Python提供的可以抓取靜態(tài)網(wǎng)頁(yè)的庫(kù)
1.urllib
urllib是Python最早的內(nèi)置的HTTP客戶端庫(kù),涵蓋了基礎(chǔ)的網(wǎng)絡(luò)請(qǐng)求功能
它主要包含了4個(gè)用于處理URL的模塊:urllib.error模塊、urllib.error模塊、urllib.parse模塊、urllib.robotparser模塊
其中urllib.requests模塊封裝了構(gòu)造和發(fā)送網(wǎng)絡(luò)請(qǐng)求的功能
urllib.error模塊封裝了發(fā)送請(qǐng)求時(shí)出現(xiàn)的網(wǎng)絡(luò)異常
urllib.parse模塊封裝了解析網(wǎng)頁(yè)數(shù)據(jù)的功能
urllib.robotparser模塊封裝解析robots.txt文件的功能
2.urllib3
它主要服務(wù)于升級(jí)的HTTP1.1標(biāo)準(zhǔn),增加了一些urllib庫(kù)中缺少了特性,如線程安全、連接池、客戶端TLS/SSL驗(yàn)證、壓縮編碼
3.requests
基于urllib3編寫(xiě)的庫(kù),該庫(kù)自稱HTTP for Humans,專門(mén)為人類設(shè)計(jì)的HTTP庫(kù)
相比urllib,requests庫(kù)會(huì)在請(qǐng)求網(wǎng)頁(yè)數(shù)據(jù)后重復(fù)使用Socket套接字,并沒(méi)有與服務(wù)器斷開(kāi),而urllib庫(kù)會(huì)在請(qǐng)求網(wǎng)頁(yè)數(shù)據(jù)后斷開(kāi)與服務(wù)器的鏈接
三.發(fā)送基本請(qǐng)求
GET和POST是HTTP協(xié)議中最常用的兩種請(qǐng)求方法,它們?cè)谠O(shè)計(jì)理念和使用場(chǎng)景上有本質(zhì)區(qū)別。
GET和POST請(qǐng)求核心區(qū)別總結(jié)
| 特性 | GET | POST |
|---|---|---|
| 語(yǔ)義 | 獲取數(shù)據(jù) | 提交數(shù)據(jù) |
| 參數(shù)位置 | URL查詢字符串 | 請(qǐng)求體 |
| 參數(shù)可見(jiàn)性 | 明文顯示在URL中 | 隱藏在請(qǐng)求體中 |
| 數(shù)據(jù)長(zhǎng)度 | 有限制(瀏覽器不同) | 理論上無(wú)限制 |
| 安全性 | 較低(參數(shù)在URL中) | 相對(duì)較高 |
| 緩存 | 可被緩存 | 通常不被緩存 |
| 冪等性 | 冪等(多次請(qǐng)求結(jié)果相同) | 非冪等 |
| 書(shū)簽 | 可收藏為書(shū)簽 | 不可收藏 |
1.發(fā)送GET請(qǐng)求
不攜帶URL參數(shù)的GET請(qǐng)求
import requests
base_url = 'https://www.baidu.com/'
response = requests.get(base_url)
print("響應(yīng)碼為:",response.status_code) #響應(yīng)碼為: 200上面的代碼中,GET請(qǐng)求中的URL沒(méi)有攜帶參數(shù),
url參數(shù)是必需的
params參數(shù)(param英文意思就是參數(shù),paramter:界限,范圍,參數(shù))
發(fā)送攜帶參數(shù)的URL的GET請(qǐng)求
params參數(shù)就是用于查詢字符串的,它可以是一個(gè)字典,一個(gè)包含鍵值對(duì)的列表,或者一個(gè)字節(jié)字符串
import requests
base_url = 'https://www.baidu.com/'
param = 'wd=python'
full_url = base_url + '?' + param
# print(full_url) #https://www.baidu.com/?wd=python
response = requests.get(full_url)
print("響應(yīng)碼為:",response.status_code) # 響應(yīng)碼為: 200import requests
base_url = 'https://www.baidu.com/'
wd_params = {'wd':'python'}
response = requests.get(base_url, params=wd_params)
print(response.status_code) #200params的參數(shù)值為字典這種使用最常用
2.發(fā)送POST請(qǐng)求
如果網(wǎng)頁(yè)上form表單的method屬性的值為post,那么當(dāng)用戶提交表單時(shí),瀏覽器會(huì)用POST方法提交表單,并將各個(gè)表單元素及數(shù)據(jù)作為HTTP請(qǐng)求信息中的請(qǐng)求數(shù)據(jù)發(fā)送給服務(wù)器
POST請(qǐng)求方法用于發(fā)送HTTP POST請(qǐng)求,它比GET請(qǐng)求更安全,因?yàn)閰?shù)不會(huì)出現(xiàn)在URL中,而是放在請(qǐng)求體中,POST請(qǐng)求通常用于提交表單、上傳文件、調(diào)用API等
基本使用方法:
response = requests.post(url, data=None, json=None, **kwargs)
主要參數(shù):
url: 請(qǐng)求的目標(biāo)URL(必需)data: 字典、元組列表、字節(jié)或文件對(duì)象,用于作為表單數(shù)據(jù)發(fā)送json: 字典,用于作為JSON數(shù)據(jù)發(fā)送,會(huì)自動(dòng)設(shè)置Content-Type為application/json**kwargs: 其他可選參數(shù),如headers、cookies、auth、timeout等,與requests.get()相同
import requests
base_url = "https://www.gushiwen.cn/"
data = {
'username':'user_name',
'password':12345678,
}
response = requests.post(url=base_url, data=data)
print(response.status_code) # 200爬取并保存古詩(shī)文網(wǎng)中蘇軾的HTML數(shù)據(jù):
import requests
base_url = 'https://www.gushiwen.cn/'
data = {
'wd':'蘇軾'
}
# response = requests.post(base_url, data=data)
response = requests.get(base_url, params=data)
print(response.status_code)
with open("古詩(shī)文-蘇軾.html", 'wb') as file:
file.write(response.content)
print(response.url)這段代碼可以正常地運(yùn)行,正常地保存了.html文件,正常輸出了url的最終形式:https://www.gushiwen.cn/?wd=%E8%8B%8F%E8%BD%BC
但是當(dāng)我們用這個(gè)輸出的url去瀏覽器中訪問(wèn)時(shí),發(fā)現(xiàn)還是首頁(yè)的頁(yè)面,并不是查找蘇軾后的有關(guān)蘇軾古詩(shī)文的頁(yè)面
原因在于:使用的是主頁(yè) URL https://www.gushiwen.cn/,而不是搜索頁(yè)面的 URL
古詩(shī)文網(wǎng)的搜索功能通常有專門(mén)的搜索頁(yè)面
我們需要查看古詩(shī)文網(wǎng)中搜索表單的實(shí)際參數(shù)名
注:搜索功能一般是GET方法,不是POST方法哦
我們通??梢酝ㄟ^(guò)以下方式找到正確的搜索URL和請(qǐng)求方式:
- 瀏覽器的開(kāi)發(fā)者工具(按F12打開(kāi)),特別是網(wǎng)絡(luò)(Network)選項(xiàng)卡。
- 觀察網(wǎng)頁(yè)的搜索表單(如果有的話)的HTML結(jié)構(gòu)
步驟1:打開(kāi)古詩(shī)文網(wǎng),找到搜索框。
步驟2:打開(kāi)瀏覽器的開(kāi)發(fā)者工具,切換到網(wǎng)絡(luò)(Network)選項(xiàng)卡,并清空當(dāng)前記錄。
步驟3:在搜索框中輸入“蘇軾”,然后執(zhí)行搜索。
步驟4:在開(kāi)發(fā)者工具的網(wǎng)絡(luò)選項(xiàng)卡中,會(huì)看到瀏覽器發(fā)送的請(qǐng)求,找到第一個(gè)搜索結(jié)果的請(qǐng)求,點(diǎn)擊查看其詳細(xì)信息。
主文檔請(qǐng)求 - 這是最重要的
- 類型通常是 "document" 或 "xhr"(或者fatch類型的文檔,這些一般都是接口數(shù)據(jù))
- 名稱通常包含 "search"、"so" 等關(guān)鍵詞
- 這是實(shí)際返回搜索結(jié)果HTML頁(yè)面的請(qǐng)求
如何識(shí)別:
- 清空Network面板:在點(diǎn)擊搜索按鈕前,先點(diǎn)擊Network面板上的 ?? 清除按鈕
- 執(zhí)行搜索:在網(wǎng)站上輸入"蘇軾"并點(diǎn)擊搜索
- 觀察新出現(xiàn)的請(qǐng)求:你會(huì)看到一堆新的請(qǐng)求出現(xiàn)
重點(diǎn)關(guān)注:
- 按Name列排序,找包含 "search" 的請(qǐng)求
- 按Type列找 "document" 類型的請(qǐng)求
- 按Size列找較大的請(qǐng)求(通常主頁(yè)面比較大)

我們?cè)陂_(kāi)發(fā)者工具的網(wǎng)絡(luò)選項(xiàng)卡中發(fā)現(xiàn)了第一個(gè)文檔,后綴名為.document
該文檔中包含的url信息為:https://www.gushiwen.cn/search.aspx?value=%E8%8B%8F%E8%BD%BC
url組成部分分解
https://- 協(xié)議類型(安全超文本傳輸協(xié)議)www.gushiwen.cn- 域名(古詩(shī)文網(wǎng))/search.aspx- 服務(wù)器上的搜索處理頁(yè)面?value=- 查詢參數(shù)開(kāi)始,參數(shù)名為value%E8%8B%8F%E8%BD%BC- "蘇軾"的URL編碼形式
關(guān)于URL編碼
URL編碼(也叫百分號(hào)編碼)是將特殊字符轉(zhuǎn)換為%后跟兩位十六進(jìn)制數(shù)的形式。
%E8%8B%8F= "蘇"%E8%BD%BC= "軾"
可以在python中驗(yàn)證:
from urllib.parse import quote, unquote
# 編碼
encoded = quote('蘇軾')
print(f"編碼后: {encoded}") # 輸出: %E8%8B%8F%E8%BD%BC
# 解碼
decoded = unquote('%E8%8B%8F%E8%BD%BC')
print(f"解碼后: {decoded}") # 輸出: 蘇軾判斷正確URL的方法
時(shí)間順序法
- 在點(diǎn)擊搜索按鈕之前,先清空Network面板
- 點(diǎn)擊搜索后,第一個(gè)出現(xiàn)的文檔請(qǐng)求很可能就是搜索請(qǐng)求
- 因?yàn)樗阉鲃?dòng)作會(huì)觸發(fā)頁(yè)面跳轉(zhuǎn),這個(gè)跳轉(zhuǎn)的請(qǐng)求應(yīng)該是最先發(fā)起的
URL特征法
正確的搜索URL通常有這些特征:
- 包含
search、so、query、find等關(guān)鍵詞 - 參數(shù)中包含你的搜索詞(編碼后的)
- 通常是
.aspx、.php、/search/等動(dòng)態(tài)頁(yè)面
大小和類型判斷
- 搜索結(jié)果的HTML頁(yè)面通常比較大(幾十KB到幾百KB)
- 靜態(tài)資源(CSS、JS、圖片)通常較小或有特定類型
Headers信息驗(yàn)證
在開(kāi)發(fā)者工具中,點(diǎn)擊候選請(qǐng)求,查看:
- Response Headers 中的
Content-Type應(yīng)該是text/html - Request Headers 中可以看到完整的請(qǐng)求信息
正確的實(shí)現(xiàn)代碼:
import requests
base_url = 'https://www.gushiwen.cn/search.aspx?'
params = {
'value':'蘇軾',
}
response = requests.get(url=base_url, params=params)
response.raise_for_status()
print(response.url)
with open("古詩(shī)文-蘇軾.html", 'wb') as f:
f.write(response.content)輸出的url:https://www.gushiwen.cn/search.aspx?value=%E8%8B%8F%E8%BD%BC
3.處理復(fù)雜的請(qǐng)求
比如定制請(qǐng)求頭,網(wǎng)絡(luò)爬蟲(chóng)在發(fā)送請(qǐng)求抓取部分網(wǎng)頁(yè)內(nèi)容(如知乎首頁(yè))時(shí),可能會(huì)遇到服務(wù)器返回403錯(cuò)誤,即服務(wù)器有能力處理請(qǐng)求,但是拒絕處理該客戶端發(fā)送的請(qǐng)求。之所以出現(xiàn)服務(wù)器拒絕訪問(wèn)的問(wèn)題,是因?yàn)檫@些網(wǎng)頁(yè)為防止網(wǎng)絡(luò)爬蟲(chóng)惡意抓取網(wǎng)頁(yè)信息加入防爬蟲(chóng)措施。
它們通過(guò)檢查該請(qǐng)求頭,判定發(fā)送的請(qǐng)求不是客戶端,而可能是一個(gè)網(wǎng)絡(luò)爬蟲(chóng)
所以為了解決這個(gè)問(wèn)題,需要為網(wǎng)絡(luò)爬蟲(chóng)的請(qǐng)求定制一個(gè)請(qǐng)求頭,使得該請(qǐng)求偽裝成一個(gè)由瀏覽器發(fā)送的請(qǐng)求
在請(qǐng)求頭中添加User-Agent(用戶代理)
在請(qǐng)求中添加Cookie值{
設(shè)置Cookie有兩種方式{
1.將含有Cookie的信息的請(qǐng)求頭傳入請(qǐng)求函數(shù)的headers參數(shù)中(字典形式)
2.將Cookie信息的請(qǐng)求頭傳輸cookies參數(shù)中,cookies參數(shù)接受一個(gè)RequestsCookieJar類的對(duì)象
}
}
使用session保持會(huì)話
SSL證書(shū)驗(yàn)證
設(shè)置代理服務(wù)器
四.對(duì)Cookie、Session、Token的一些理解
當(dāng)用戶首次登入一個(gè)網(wǎng)站時(shí),網(wǎng)站往往需要用戶輸入用戶名稱和用戶密碼,并給出自動(dòng)登入選項(xiàng)供用戶勾選。用戶如果勾選了自動(dòng)登入選項(xiàng),那么在下一次訪問(wèn)該網(wǎng)站時(shí),不用輸入用戶名和密碼就能自動(dòng)登入。這是因?yàn)榈谝淮蔚侨霑r(shí)服務(wù)器發(fā)送了包含登入憑證的Cookie到用戶硬盤(pán)上,第二次登入時(shí)瀏覽器發(fā)送了Cookie,服務(wù)器驗(yàn)證了Cookie后就識(shí)別了用戶的身份,用戶便無(wú)需用戶名和密碼就可以登入該網(wǎng)站
Cookie(有時(shí)候也稱Cookies)是指某些網(wǎng)站為了辨別用戶身份、進(jìn)行會(huì)話跟蹤而暫時(shí)存儲(chǔ)在客戶端的一段文本數(shù)據(jù)(通常經(jīng)過(guò)加密)
我們可以打開(kāi)瀏覽器來(lái)看一下我們的瀏覽器保存了哪些Cookie:
打開(kāi)瀏覽器的設(shè)置 → 點(diǎn)擊“隱私、搜索和服務(wù)” → 在彈出來(lái)的界面中點(diǎn)擊Cookie
這相當(dāng)于說(shuō)把用戶名和密碼發(fā)在Cookie里是不夠安全的,電腦被黑,存儲(chǔ)在瀏覽器中的Cookie信息就會(huì)被盜取
瀏覽器訪問(wèn)服務(wù)器就是會(huì)話的開(kāi)始,但是會(huì)話的結(jié)束就相對(duì)來(lái)說(shuō)模糊一點(diǎn),當(dāng)你不小心關(guān)閉了這個(gè)網(wǎng)頁(yè),算不算會(huì)話的結(jié)束?
因此不同的網(wǎng)站會(huì)給用戶的會(huì)話設(shè)置了時(shí)間和一個(gè)唯一的ID,這個(gè)ID也就是Session ID,時(shí)間是會(huì)話的時(shí)間。這些數(shù)據(jù)由服務(wù)器設(shè)置,一般都保存在數(shù)據(jù)庫(kù)里面
Cookie
是什么:Cookie是一小段數(shù)據(jù)(最大通常為4KB),由服務(wù)器通過(guò)HTTP響應(yīng)頭的 Set-Cookie 字段發(fā)送給客戶端(通常是瀏覽器)。瀏覽器會(huì)將其保存起來(lái),并在后續(xù)對(duì)同一域名的請(qǐng)求中,自動(dòng)通過(guò)HTTP請(qǐng)求頭的 Cookie 字段將其攜帶回服務(wù)器。
核心特點(diǎn):
- 存儲(chǔ)在客戶端:數(shù)據(jù)保存在瀏覽器端。
- 自動(dòng)攜帶:瀏覽器會(huì)自動(dòng)在符合條件的請(qǐng)求中附帶上Cookie。
- 有域和路徑限制:只能被創(chuàng)建它的域名或路徑訪問(wèn),遵循同源策略。
- 可設(shè)置過(guò)期時(shí)間:可以是會(huì)話級(jí)(瀏覽器關(guān)閉即失效),也可以是持久性的(直到設(shè)定的過(guò)期時(shí)間)。
主要用途:
- 會(huì)話狀態(tài)管理(如用戶登錄狀態(tài)、購(gòu)物車)
- 個(gè)性化設(shè)置(如主題、語(yǔ)言偏好)
- 瀏覽器行為跟蹤(如用戶行為分析)
Session
是什么:Session代表的是一次用戶與服務(wù)器的交互會(huì)話。它是一種在服務(wù)器端保存用戶狀態(tài)和信息的機(jī)制。每個(gè)Session都有一個(gè)唯一的標(biāo)識(shí)符,稱為 Session ID。
核心特點(diǎn):
- 存儲(chǔ)在服務(wù)器端:用戶的真實(shí)數(shù)據(jù)(如用戶ID、用戶名、權(quán)限等)保存在服務(wù)器的內(nèi)存、文件或數(shù)據(jù)庫(kù)中。
- 依賴Cookie(或URL重寫(xiě)):服務(wù)器為了區(qū)分不同的客戶端,會(huì)將
Session ID通過(guò)Cookie(Set-Cookie: session_id=abc123...)發(fā)送給客戶端??蛻舳撕罄m(xù)請(qǐng)求時(shí)攜帶這個(gè)Session ID,服務(wù)器根據(jù)這個(gè)ID找到對(duì)應(yīng)的Session數(shù)據(jù)。 - 更安全:因?yàn)槊舾袛?shù)據(jù)都存在服務(wù)器,客戶端只有一個(gè)無(wú)意義的ID。
工作流程簡(jiǎn)述:
- 用戶登錄,服務(wù)器驗(yàn)證通過(guò)后,創(chuàng)建Session,并生成唯一
Session ID。 - 服務(wù)器通過(guò)響應(yīng)頭
Set-Cookie將Session ID發(fā)給瀏覽器。 - 瀏覽器保存這個(gè)Cookie,之后每次請(qǐng)求都會(huì)帶上這個(gè)
Session ID。 - 服務(wù)器收到請(qǐng)求,解析出
Session ID,并從存儲(chǔ)中查找對(duì)應(yīng)的Session數(shù)據(jù),從而得知用戶身份。
Token
是什么:Token是一種身份憑證,是服務(wù)器生成的一串字符串,其中包含了用戶信息和簽名。最常見(jiàn)的Token是 JWT(JSON Web Token)。
核心特點(diǎn):
- 自包含:Token本身(以JWT為例)就包含了所有需要的信息,如用戶ID、過(guò)期時(shí)間等。服務(wù)器無(wú)需在服務(wù)端存儲(chǔ)會(huì)話狀態(tài)。
- 存儲(chǔ)在客戶端:由客戶端保存,通??梢源鎯?chǔ)在Local Storage、Session Storage或Cookie中。
- 需要手動(dòng)攜帶:客戶端需要在每次請(qǐng)求時(shí),手動(dòng)地將其添加到請(qǐng)求頭中(通常是
Authorization: Bearer <token>),瀏覽器不會(huì)像Cookie一樣自動(dòng)發(fā)送。 - 無(wú)狀態(tài):服務(wù)器驗(yàn)證Token的簽名即可確認(rèn)其有效性,不需要在服務(wù)器端存儲(chǔ)任何會(huì)話信息。這使得服務(wù)器擴(kuò)展非常容易。
工作流程簡(jiǎn)述(以JWT為例):
- 用戶登錄,服務(wù)器驗(yàn)證通過(guò)后,生成一個(gè)JWT(包含用戶信息和簽名),將其返回給客戶端。
- 客戶端保存這個(gè)JWT(例如在Local Storage中)。
- 客戶端后續(xù)請(qǐng)求API時(shí),在HTTP請(qǐng)求頭的
Authorization字段中攜帶這個(gè)JWT。 - 服務(wù)器收到請(qǐng)求,驗(yàn)證JWT的簽名是否有效、是否過(guò)期。如果有效,就直接使用Token中包含的用戶信息進(jìn)行后續(xù)處理。
三者的聯(lián)系
Cookie 和 Session 是“黃金搭檔”:在傳統(tǒng)的Session認(rèn)證方案中,Cookie是Session ID的載體。Session機(jī)制解決了HTTP協(xié)議無(wú)狀態(tài)的問(wèn)題,而Cookie解決了Session ID的傳遞和存儲(chǔ)問(wèn)題。它們是相輔相成、密不可分的一對(duì)。
Token 可以作為 Cookie 的內(nèi)容:Token也可以選擇存儲(chǔ)在Cookie中,由瀏覽器自動(dòng)管理。這種方式結(jié)合了Cookie的自動(dòng)攜帶和Token的無(wú)狀態(tài)優(yōu)點(diǎn),但需要注意防范CSRF攻擊。
共同目標(biāo):三者的終極目標(biāo)都是為了在無(wú)狀態(tài)的HTTP協(xié)議之上,實(shí)現(xiàn)有狀態(tài)的用戶身份認(rèn)證和會(huì)話管理
核心區(qū)別(重點(diǎn))
| 特性 | Cookie | Session | Token (以JWT為例) |
|---|---|---|---|
| 存儲(chǔ)位置 | 客戶端(瀏覽器) | 服務(wù)器端(內(nèi)存、DB、Redis) | 客戶端(LocalStorage, Cookie等) |
| 安全性 | 較低,易被XSS和CSRF攻擊 | 較高,敏感信息在服務(wù)器 | 較高,但需防XSS。簽名防篡改 |
| 擴(kuò)展性 | - | 差,服務(wù)器集群間同步Session復(fù)雜 | 好,無(wú)狀態(tài),天然支持分布式 |
| 跨域支持 | 受同源策略限制,需額外配置CORS | 受同源策略限制 | 容易,可在請(qǐng)求頭中攜帶,支持CORS |
| 傳輸方式 | 瀏覽器自動(dòng)通過(guò)Cookie請(qǐng)求頭攜帶 | 通過(guò)Cookie攜帶其ID | 手動(dòng)通過(guò)Authorization等請(qǐng)求頭攜帶 |
| 數(shù)據(jù)容量 | 小(約4KB) | 大(受服務(wù)器資源限制) | 中等(不宜過(guò)大,影響傳輸效率) |
| 服務(wù)器壓力 | 無(wú) | 大,需要存儲(chǔ)所有用戶的會(huì)話數(shù)據(jù) | 小,只需驗(yàn)證簽名,無(wú)需存儲(chǔ) |
為了幫助你更好地理解,我們可以用一個(gè)形象的比喻:
Cookie 就像 “會(huì)員卡”。
你(瀏覽器)去健身房(服務(wù)器),前臺(tái)(服務(wù)器)給你一張印有卡號(hào)(Session ID)的會(huì)員卡(Cookie)。你下次來(lái),直接出示卡(自動(dòng)攜帶Cookie),前臺(tái)通過(guò)卡號(hào)查到你的檔案(Session)。
Session 就像 “健身房前臺(tái)的會(huì)員檔案柜”。
里面存著所有會(huì)員的詳細(xì)資料(用戶數(shù)據(jù))??ㄌ?hào)(Session ID)是打開(kāi)對(duì)應(yīng)檔案抽屜的鑰匙。
Token (JWT) 就像 “一張加密的防偽門(mén)票”。
你第一次驗(yàn)票進(jìn)場(chǎng)后,檢票處(服務(wù)器)給你一張?zhí)厥獠馁|(zhì)的門(mén)票(Token),上面用特殊工藝印著你的身份信息和防偽碼(簽名)。你去看每個(gè)場(chǎng)館(訪問(wèn)每個(gè)API)時(shí),都需要主動(dòng)出示這張票(手動(dòng)攜帶Token),檢票處用特定燈光(驗(yàn)證算法)一照,就能辨別真?zhèn)?,無(wú)需再回總臺(tái)查名單。
如何選擇?
- 傳統(tǒng)Web應(yīng)用(有服務(wù)端模板渲染,如JSP, PHP):使用 Cookie + Session 非常自然和方便。
- 前后端分離應(yīng)用(如React/Vue + Node.js/Java API)、移動(dòng)端APP或需要跨域認(rèn)證的場(chǎng)景:使用 Token(尤其是JWT) 是更現(xiàn)代、更合適的選擇,因?yàn)樗鼰o(wú)狀態(tài)、擴(kuò)展性好
五.用戶的真實(shí)賬號(hào)和密碼被存在了哪里
我們通常不會(huì)將用戶的真實(shí)密碼和賬號(hào)保存在Cookie或Session中。這樣做會(huì)帶來(lái)嚴(yán)重的安全風(fēng)險(xiǎn)。下面分別說(shuō)明:
Cookie:如果將用戶的賬號(hào)和密碼直接保存在Cookie中,那么這些敏感信息就會(huì)以明文形式存儲(chǔ)在用戶的瀏覽器中,并且每次請(qǐng)求都會(huì)自動(dòng)發(fā)送給服務(wù)器。這極易導(dǎo)致信息泄露,例如:
- 如果Cookie被竊?。ㄍㄟ^(guò)XSS攻擊),攻擊者就能拿到用戶的賬號(hào)和密碼。
- 即使加密存儲(chǔ),也不安全,因?yàn)槊荑€同樣需要存儲(chǔ)在客戶端,且加密可能被破解。
Session:在Session中,我們通常也不會(huì)保存用戶的真實(shí)密碼。Session中存儲(chǔ)的是用戶登錄后的狀態(tài)信息,例如用戶ID、用戶名、登錄狀態(tài)等。用戶的密碼在登錄驗(yàn)證通過(guò)后,就不應(yīng)該再被保留在Session中。
那么,正確的做法是怎樣的呢?
正確的認(rèn)證流程:
- 用戶登錄:用戶提交賬號(hào)和密碼。
- 服務(wù)器驗(yàn)證:服務(wù)器在數(shù)據(jù)庫(kù)中查找該賬號(hào),并驗(yàn)證密碼(通常數(shù)據(jù)庫(kù)中的密碼是經(jīng)過(guò)哈希加密的,不會(huì)存儲(chǔ)明文密碼)。
- 創(chuàng)建Session:驗(yàn)證通過(guò)后,服務(wù)器創(chuàng)建一個(gè)Session,在Session中存儲(chǔ)一些不敏感的用戶信息(如用戶ID、用戶名等)和登錄狀態(tài)。
- 設(shè)置Cookie:服務(wù)器將Session ID通過(guò)Cookie返回給瀏覽器,瀏覽器后續(xù)請(qǐng)求會(huì)攜帶這個(gè)Session ID。
- 后續(xù)請(qǐng)求:服務(wù)器通過(guò)Session ID找到對(duì)應(yīng)的Session,從而知道是哪個(gè)用戶。
另外,使用Token(如JWT)的方式:
- 用戶登錄:用戶提交賬號(hào)和密碼。
- 服務(wù)器驗(yàn)證:驗(yàn)證通過(guò)后,服務(wù)器生成一個(gè)Token(如JWT),Token中包含一些用戶信息(如用戶ID)和過(guò)期時(shí)間,并用服務(wù)器密鑰簽名。
- 返回Token:服務(wù)器將Token返回給客戶端,客戶端保存(通常放在localStorage或Cookie中)。
- 后續(xù)請(qǐng)求:客戶端在請(qǐng)求頭中攜帶Token,服務(wù)器驗(yàn)證Token的簽名和有效性,從而識(shí)別用戶。
在Token方式中,密碼同樣不會(huì)存儲(chǔ)在Token中,Token中只包含必要的信息(如用戶ID)和簽名。
總結(jié):
- 絕對(duì)不要將用戶的真實(shí)密碼存儲(chǔ)在Cookie或Session中。
- 在Session中只存儲(chǔ)必要的用戶標(biāo)識(shí)和狀態(tài),而不是敏感信息。
- 在認(rèn)證過(guò)程中,密碼應(yīng)該通過(guò)安全通道(如HTTPS)傳輸,并且在服務(wù)器端與存儲(chǔ)的哈希值進(jìn)行驗(yàn)證,驗(yàn)證后立即“忘記”密碼(不保存)。
所以,用戶的真實(shí)密碼既不應(yīng)該保存在Cookie里,也不應(yīng)該保存在Session里。
絕對(duì)不要將用戶的真實(shí)密碼和賬號(hào)保存在Cookie或Session中! 這是Web安全的基本原則。
六.requests模塊中cookies和session的作用
在 requests 進(jìn)行登錄時(shí),賬戶和密碼是通過(guò) POST 請(qǐng)求的 data 參數(shù)發(fā)送的。
data參數(shù)接受一個(gè)字典
我們之前討論過(guò),Cookie和Session不是用來(lái)存儲(chǔ)密碼的,而是用來(lái)維護(hù)會(huì)話狀態(tài)的。在requests庫(kù)中,Cookie和Session的作用如下:
- Session對(duì)象:在requests庫(kù)中,Session對(duì)象允許你跨請(qǐng)求保持某些參數(shù),比如Cookie、頭部信息等。它最常用的功能就是保持登錄狀態(tài)(通過(guò)自動(dòng)處理Cookie)。
- Cookie:在HTTP請(qǐng)求中,Cookie是服務(wù)器發(fā)送到瀏覽器并保存在本地的一小段數(shù)據(jù),瀏覽器會(huì)在后續(xù)的請(qǐng)求中自動(dòng)攜帶這些數(shù)據(jù)。在requests中,你可以手動(dòng)為請(qǐng)求添加Cookie,但更常見(jiàn)的做法是使用Session對(duì)象自動(dòng)管理。
在爬蟲(chóng)中,我們通常使用Session來(lái)模擬登錄后的會(huì)話,步驟如下:
a. 創(chuàng)建一個(gè)Session對(duì)象。
b. 發(fā)送登錄請(qǐng)求(POST請(qǐng)求,包含用戶名和密碼),這個(gè)請(qǐng)求會(huì)返回一個(gè)包含Cookie的響應(yīng),Session會(huì)自動(dòng)保存這個(gè)Cookie。
c. 使用同一個(gè)Session對(duì)象發(fā)送后續(xù)請(qǐng)求,Session會(huì)自動(dòng)在請(qǐng)求中攜帶之前保存的Cookie,這樣服務(wù)器就認(rèn)為你已經(jīng)登錄了。
注意:我們不會(huì)將密碼存儲(chǔ)在Cookie或Session中,而是通過(guò)登錄請(qǐng)求將密碼(通常是加密的)發(fā)送給服務(wù)器,服務(wù)器驗(yàn)證后返回一個(gè)會(huì)話標(biāo)識(shí)(例如Session ID),這個(gè)標(biāo)識(shí)會(huì)保存在Cookie中,后續(xù)請(qǐng)求就靠這個(gè)標(biāo)識(shí)來(lái)維持登錄狀態(tài)。
requests.Session() 的作用
不是用來(lái)存儲(chǔ)密碼的,而是用來(lái)自動(dòng)管理HTTP會(huì)話狀態(tài)的:
import requests # 創(chuàng)建會(huì)話對(duì)象 session = requests.Session() # Session會(huì)自動(dòng): # 1. 保持連接,提高性能 # 2. 自動(dòng)管理Cookies(服務(wù)器返回的) # 3. 保持請(qǐng)求頭等信息的一致性
Session的實(shí)際工作方式:
# 第一次請(qǐng)求:登錄
login_data = {'username': 'user', 'password': 'pass'}
response = session.post('https://example.com/login', data=login_data)
# 服務(wù)器返回 Set-Cookie: session_id=abc123
# Session對(duì)象會(huì)自動(dòng)保存這個(gè)cookie
# 第二次請(qǐng)求:訪問(wèn)個(gè)人頁(yè)面
# Session會(huì)自動(dòng)在請(qǐng)求頭中添加: Cookie: session_id=abc123
profile_response = session.get('https://example.com/profile')
# 不需要手動(dòng)處理cookies!Cookies 參數(shù)的作用
cookies 參數(shù)是用于手動(dòng)設(shè)置請(qǐng)求中的Cookie,而不是存儲(chǔ)密碼:
# 方式1:使用字典
cookies_dict = {'session_id': 'abc123', 'user_token': 'xyz789'}
response = requests.get(url, cookies=cookies_dict)
# 方式2:使用CookieJar
from http.cookies import SimpleCookie
cookie = SimpleCookie()
cookie['session_id'] = 'abc123'
cookie['session_id']['domain'] = 'example.com'
response = requests.get(url, cookies=cookie)課本上實(shí)現(xiàn)第二種方式使用的是requests.cookies.RequestsCookieJar()類
完整的登錄流程示例
import requests
# 創(chuàng)建會(huì)話
session = requests.Session()
# 1. 首先可能需要獲取登錄頁(yè),獲取CSRF token等
login_page = session.get('https://example.com/login')
# 這里可以解析頁(yè)面獲取CSRF token
# 2. 準(zhǔn)備登錄數(shù)據(jù)(密碼只在這里短暫使用)
login_data = {
'username': 'your_username',
'password': 'your_password', # 密碼只在這里出現(xiàn)一次
'csrf_token': '從登錄頁(yè)面獲取的token'
}
# 3. 發(fā)送登錄請(qǐng)求
login_response = session.post(
'https://example.com/login',
data=login_data
)
# 登錄成功后,session自動(dòng)保存了服務(wù)器返回的認(rèn)證cookie
# 后續(xù)請(qǐng)求都會(huì)自動(dòng)攜帶這個(gè)cookie
# 4. 訪問(wèn)需要登錄的頁(yè)面(自動(dòng)攜帶cookies)
dashboard = session.get('https://example.com/dashboard')
profile = session.get('https://example.com/profile')
# 密碼變量現(xiàn)在可以清除了(雖然Python會(huì)自動(dòng)回收)
del login_data['password']以上就是Python抓取靜態(tài)網(wǎng)頁(yè)數(shù)據(jù)的完整指南的詳細(xì)內(nèi)容,更多關(guān)于Python抓取靜態(tài)網(wǎng)頁(yè)數(shù)據(jù)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- Python使用PyQuery快速解析網(wǎng)頁(yè)數(shù)據(jù)的實(shí)戰(zhàn)指南
- Python通過(guò)BeautifulSoup抓取網(wǎng)頁(yè)數(shù)據(jù)并解析
- python實(shí)現(xiàn)抓取網(wǎng)頁(yè)數(shù)據(jù)并生成excel的實(shí)例
- Python實(shí)現(xiàn)快速抓取網(wǎng)頁(yè)數(shù)據(jù)的5種高效方法
- 一文教你Python如何快速精準(zhǔn)抓取網(wǎng)頁(yè)數(shù)據(jù)
- 利用Python抓取網(wǎng)頁(yè)數(shù)據(jù)的多種方式與示例詳解
- Python獲取網(wǎng)頁(yè)數(shù)據(jù)的五種方法
相關(guān)文章
python分布式庫(kù)celery處理大規(guī)模的任務(wù)并行化
Python中的分布式任務(wù)隊(duì)列時(shí),Celery是一個(gè)備受推崇的工具,它是一個(gè)功能強(qiáng)大的分布式系統(tǒng),可用于處理大規(guī)模的任務(wù)并行化,本文將介紹Celery的基本概念、用法和示例代碼,幫助讀者更好地了解和使用這個(gè)庫(kù)2024-01-01
Python3+Pycharm+PyQt5環(huán)境搭建步驟圖文詳解
這篇文章主要介紹了Python3+Pycharm+PyQt5環(huán)境搭建步驟圖文詳解,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-05-05
matplotlib 生成的圖像中無(wú)法顯示中文字符的解決方法
這篇文章主要介紹了matplotlib 生成的圖像中無(wú)法顯示中文字符的解決方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-06-06
Python使用Pandas讀取CSV文件數(shù)據(jù)的操作方法
Pandas?是?Python?中一個(gè)強(qiáng)大的數(shù)據(jù)分析庫(kù),它提供了大量的工具用于數(shù)據(jù)操作和分析,其中,read_csv?函數(shù)是?Pandas?中最常用的函數(shù)之一,用于從?CSV?文件中讀取數(shù)據(jù),本文將詳細(xì)介紹?read_csv?的基本用法,常見(jiàn)問(wèn)題及其解決方案,并通過(guò)代碼案例進(jìn)行說(shuō)明2024-12-12
python中的yield from語(yǔ)法快速學(xué)習(xí)
在本篇文章里小編給大家整理的是一篇關(guān)于python中的yield from語(yǔ)法快速學(xué)習(xí)相關(guān)內(nèi)容,有興趣的朋友們可以參考下。2020-11-11
Python+API打造一個(gè)終端天氣預(yù)報(bào)工具
這篇文章主要為大家詳細(xì)介紹了如何利用Python和API打造一個(gè)終端天氣預(yù)報(bào)工具,支持城市查詢,天氣圖標(biāo),美化輸出,有需要的小伙伴可以了解一下2025-07-07
Python用20行代碼實(shí)現(xiàn)批量摳圖功能
在日常的工作和生活中,我們經(jīng)常會(huì)遇到需要摳圖的場(chǎng)景,即便是只有一張圖片需要摳,也會(huì)摳得我們不耐煩。本文將為大家分享一個(gè)20行代碼就能實(shí)現(xiàn)是批量摳圖,需要的可以參考一下2022-05-05
docker django無(wú)法訪問(wèn)redis容器的解決方法
今天小編就為大家分享一篇docker django無(wú)法訪問(wèn)redis容器的解決方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-08-08

