python學習筆記——爬蟲前置——HTTP協議簡介
Http協議簡介
因為最近剛剛接觸了python爬蟲,想要系統的學習一下,在初次使用requests庫時有一些無法理解的地方,於是就去簡要了解了一點點http協議的基礎知識。
Hyper Text Transfer Protocol 超文字傳輸協議
基於 TCP/IP 協議簇來傳遞資料,位於應用層的協議之一
TCP建立連線——三次握手
- 客戶端(client)傳送位碼syn=1,隨機產生 seq_number 的資料包到伺服器(server),伺服器由 syn=1 瞭解該客戶端要求建立連線
- 伺服器收到請求後,向客戶端傳送 ack_number = seq_number+1,syn=1,ack=1,隨機產生 seq_number 的資料包到客戶端
- 客戶端收到資料包,通過 ack_number 確定正確,以及確認 ack 是否為1;均滿足後客戶端傳送 ack_number = seq_number+1,ack=1到伺服器,伺服器收到後確認ack_number和ack=1正確後,建立連線
客戶端和伺服器就像我們打電話時,客戶端先問:“你聽得到嗎?”伺服器回答:“聽得到,你呢?”客戶端說:“我聽得到。”然後再開始對話。
Http message (Http報文)
所有 Http報文 都可以分成兩類:request message (請求報文) 和 response message (響應報文)。請求報文會向Web伺服器請求一個動作,響應報文會將請求的結果返回給客戶端。請求和相應報文的基本報文結構相同。
Http Requests (Http請求)
在客戶端與伺服器三次握手成功後,客戶端就可以向伺服器傳送 Requests請求,請求報文的格式如下:
<method> <request-URL> <version> <headers> <entity-body>
比如在Edge瀏覽器中訪問百度時,傳送的第一個請求如下:
由 burpsuite 抓包獲得
GET / HTTP/1.1
Host: www.baidu.com
Sec-Ch-Ua: "Chromium";v="92", " Not A;Brand";v="99", "Microsoft Edge";v="92"
Sec-Ch-Ua-Mobile: ?0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36 Edg/92.0.902.73
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6,ja;q=0.5
Connection: close
我們對該請求進行逐步分析:
Request Attributes(請求屬性)
第一行是 請求行:
GET / HTTP/1.1
其中 GET 是請求的方法(Method); / 是請求的路徑(URL); HTTP/1.1 表明該請求是基於 HTTP1.1 版本(Version)。
Http method
有一些常用的 http 方法:
方法 | 描述 |
---|---|
GET | 從伺服器獲取一份文件 |
HEAD | 只從伺服器獲取文件的首部 |
POST | 向伺服器傳送需要處理的資料 |
PUT | 將請求的主體部分儲存在伺服器上 |
TRACE | 對可能經過代理伺服器傳送到伺服器上的報文進行追蹤 |
PATCH | 向伺服器提交區域性修改請求 |
DELETE | 從伺服器上刪除一份文件 |
在較早的http版本中,一些方法會缺失。
除了上述方法之外,伺服器還可能會實現一些自己的請求方法。
URL
URL 是瀏覽器尋找資訊時所需的資源位置,常見的URL語法如下:
<scheme>://<user>:<password>@<host>:<port>/<path>;<params>?<query>#<frag>
元件 | 描述 |
---|---|
scheme | 訪問伺服器時使用的協議,如https協議 |
user | 伺服器的使用者名稱,預設為匿名 |
password | 伺服器的密碼 |
host | 伺服器的主機名或ip地址 |
port | 伺服器正在監聽的埠號,Http的預設埠號為80,Https的預設埠號為443 |
path | 伺服器上資源的本地名 |
params | 指定輸入引數,為鍵值對 |
query | 傳遞引數,為鍵值對 |
frag | 資源片段的名字 |
如在百度中搜索python時,url如下:
https://www.baidu.com/s?wd=python
其中
- scheme = https
- user 省略,則預設為匿名
- host = www.baidu.com
- port 省略,則取 https的預設埠號 443
- path = /s
- params 省略
- query = 'wd=python'
- frag 省略
這也是我們見到的大多數https的 url格式:
https://<host>/<path>?<query>
Http version
常見的http版本有:
- HTTP 0.9
- HTTP 1.0
- HTTP 1.1
- HTTP 2.0
(感覺基本上都是 http 1.1 和 http 2.0 了)
Request Headers(請求首部)
從第二行開始到結尾,就都是 請求的首部:
Host: www.baidu.com
Sec-Ch-Ua: "Chromium";v="92", " Not A;Brand";v="99", "Microsoft Edge";v="92"
Sec-Ch-Ua-Mobile: ?0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36 Edg/92.0.902.73
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6,ja;q=0.5
Connection: close
首部都是 "名字:值" 的形式,如:
Host: www.baidu.com
即伺服器的域名為 www.baidu.com,也因此請求訊息中的URL並沒有傳遞主機名。之所以這樣設計是因為虛擬主機技術的發展,使得同一臺物理伺服器上可以存在多個虛擬主機,而他們共享一個ip地址。使用host欄位傳遞主機名,就可以將請求發往同一個伺服器上的不同網站。
如:
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36 Edg/92.0.902.73
User-Agent這一項在爬蟲中修改較多,該欄位是告訴伺服器使用者是使用何種工具傳送的請求。這個示例是edge瀏覽器的值,不同的瀏覽器有不同的值。
Http Response (Http響應)
在接收到客戶端傳送的 request 請求後,伺服器端會返回一個 response相應給客戶端。響應報文的格式如下:
<version> <status> <reason-phrase>
<headers>
<entity-body>
例如在傳送完上述請求給百度伺服器後,返回的 response 如下:
burpsuite 抓包獲取
HTTP/1.1 200 OK
Bdpagetype: 1
Bdqid: 0xa6f9ca590000f9cd
Cache-Control: private
Content-Type: text/html;charset=utf-8
Date: Mon, 16 Aug 2021 10:02:09 GMT
Expires: Mon, 16 Aug 2021 10:01:13 GMT
P3p: CP=" OTI DSP COR IVA OUR IND COM "
P3p: CP=" OTI DSP COR IVA OUR IND COM "
Server: BWS/1.1
Set-Cookie: BAIDUID=DFF935C15B376DD72F4785A559548401:FG=1; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2147483647; path=/; domain=.baidu.com
Set-Cookie: BIDUPSID=DFF935C15B376DD72F4785A559548401; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2147483647; path=/; domain=.baidu.com
Set-Cookie: PSTM=1629108129; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2147483647; path=/; domain=.baidu.com
Set-Cookie: BAIDUID=DFF935C15B376DD7F38BDD53843DD693:FG=1; max-age=31536000; expires=Tue, 16-Aug-22 10:02:09 GMT; domain=.baidu.com; path=/; version=1; comment=bd
Set-Cookie: BDSVRTM=0; path=/
Set-Cookie: BD_HOME=1; path=/
Set-Cookie: H_PS_PSSID=34399_34380_34370_34377_34004_34092_34094_26350_34419_34246_34390_34366; path=/; domain=.baidu.com
Strict-Transport-Security: max-age=172800
Traceid: 1629108129043925146612031870363097954765
X-Frame-Options: sameorigin
X-Ua-Compatible: IE=Edge,chrome=1
Connection: close
Content-Length: 308542
<html程式碼塊>
Response Attributes(響應屬性)
第一行是響應的屬性:
HTTP/1.1 200 OK
其中 HTTP/1.1 是HTTP協議的版本,與請求中的版本一致; 200 是狀態碼,這裡表示操作成功; OK 為狀態碼200提供了文字形式的解釋,表明操作成功。
stauts(狀態碼)
狀態碼可以告訴客戶端,在請求資料過程中發生了什麼事情。狀態碼的分類如下:
整體範圍 | 已定義範圍(可能不完整) | 分類 |
---|---|---|
100 ~ 199 | 100 ~ 102 | 資訊提示 |
200 ~ 299 | 200 ~ 208 | 成功 |
300 ~ 399 | 300 ~ 308 | 重定向 |
400 ~ 499 | 400 ~ 417、421、422、424、425、426 | 客戶端錯誤 |
500 ~ 599 | 500 ~ 508、511 | 伺服器錯誤 |
如果收到了不認識的狀態碼,可能是有人將其作為當前協議的擴充套件定義的,可以根據其所處範圍來判斷分類
reason-phrase(原因短語)
為狀態碼提供文字形式的解釋,如 狀態碼200 對應的 原因短語 是 "OK",狀態碼404 對應的 原因短語 是"Not Found"
Response Headers(響應首部)
響應的首部 和 請求的首部 類似,均是採用鍵值對的形式,不同鍵值對之間以換行符('\n')隔開。
entity-body(實體部分)
該部分是可選部分,在 request 和 response 中均可存在。
在本次示例response中,實體(entity-body)部分為百度首頁的html程式碼:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta content="always" name="referrer">
<meta name="theme-color" content="#2932e1">
<meta name="description" content="全球領先的中文搜尋引擎、致力於讓網民更便捷地獲取資訊,找到所求。百度超過千億的中文網頁資料庫,可以瞬間找到相關的搜尋結果。">
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" />
<link rel="search" type="application/opensearchdescription+xml" href="/content-search.xml" title="百度搜索" />
<link rel="icon" sizes="any" mask href="//www.baidu.com/img/baidu_85beaf5496f291521eb75ba38eacbd87.svg">
<link rel="dns-prefetch" href="//dss0.bdstatic.com"/><link rel="dns-prefetch" href="//dss1.bdstatic.com"/>
<link rel="dns-prefetch" href="//ss1.bdstatic.com"/><link rel="dns-prefetch" href="//sp0.baidu.com"/>
<link rel="dns-prefetch" href="//sp1.baidu.com"/><link rel="dns-prefetch" href="//sp2.baidu.com"/>
<title>百度一下,你就知道</title>
<!--省略:css檔案-->
</head>
<!--太長省略-->
</html>
除了 html程式碼之外,視訊、音訊、json檔案、……等多種檔案均可置於實體部分中,作為request中上傳的資料或response中獲取的資料。
TCP斷開連線——四次揮手
- 客戶端(client)傳送位碼fin=1,隨機產生 seq_number = a 的資料包到伺服器(server),伺服器由 fin=1 瞭解該客戶端要斷開連線
- 伺服器收到請求後,向客戶端傳送 ack_number = a+1,ack=1,隨機產生 seq_number = b 的資料包到客戶端,表面收到了客戶端的斷開連線請求
- 伺服器隨後傳送位碼fin=1,傳送 ack_number = a+1,ack=1,隨機產生 seq_number = c 的資料包到客戶端
- 客戶端收到資料包,通過 ack_number 確定正確,以及確認 ack和fin 是否為1;均滿足後客戶端傳送 ack_number = c+1,seq_number = a+1, ack=1到伺服器,伺服器收到後確認ack_number和ack=1正確後,斷開連線
- 客戶端等待一定時間後,若伺服器無報文到達,則說明自己的響應成功到達伺服器端,客戶端也斷開連線
仍然存在的一些問題
在學習過程中,仍然存在一些問題,暫時無法理解,先記錄下來,今後的學習中有機會再來弄懂。
- 百度主頁的url是 https://www.baidu.com/ , 主機名(host) 是 www.baidu.com,資源的本地名(path) 是 /;但是 / 是伺服器根目錄,並不是一個檔案,是伺服器自動重定向到index.html之類的檔案嗎?
- Mozilla/5.0、AppleWebKit/537.36、……等都是瀏覽器核心的版本號,為什麼edge瀏覽器傳送的user-agent要包括它沒用到的核心?