注:此部落格為《python瘋狂講義》的學習筆記
文章目錄
- 一. 基礎概念
-
- 術語
- 端口
- 網絡模型
- 每層網絡子產品都有對應協定
- python 網絡子產品
- URL (Uniform Resource Locator)
- 二 urllib 子產品
-
- urllib.parse
-
- urlparse
- 解析查詢字元串 parse_qs, parse_qsl
- urljoin
- urllib.request
-
- urlopen
- Request
- 三. Http子產品
-
- cookie
- 四. socket
- 五. 郵件處理
-
- 1. 郵件發送
- 2. 郵件接收
- 六. 拓展學習
-
- 1. 請求封包與相應封包
- 2. 檢視本機IP
- 3. 檢視端口
- 5. UDP協定
一. 基礎概念
術語
- HTTP協定(HyperText Transfer Protocol,超文本傳輸協定):是一種釋出和接收 HTML頁面的方法。
- HTTPS(Hypertext Transfer Protocol over Secure Socket Layer)簡單講是HTTP的安全版,在HTTP下加入SSL層。
端口
端口是一個 16 位的整數,用于表示将資料交給哪個通信程式處理。 是以,端口就是應用程式 與外界交流的出入口,它是一種抽象的軟體結構,包括一些資料結構和 I/O (輸入/輸出) 緩沖區。 不同的應用程式處理不同端 口上的資料,在同一台機器中不能有兩個程式使用同一個端口 。 端 口号可以為 0~65535 ,通常将端口分為如下三類。
- 公認端口( Well Known Port) :喘口号為 0~1023 , 它們緊密地綁定(Binding) 一些特定 的服務。
- 注冊端口(Registered Port):端口号為 1024~49151 ,它們松散地結II定一些服務。應用程式 通常應該使用這個範圍内的端口 。
- 動态和/或私有端口( Dynamic and/or Private Port) : 端口号為 49152~65535,這些端口是 應用程式使用的動态端口,應用程式一般不會主動使用這些端口 。
網絡模型

每層網絡子產品都有對應協定
其中 ICMP ( Internet Control Message Protocol 〕、 IGMP Cinternet Group Manage Protocol)、 ARP (Address Resolution Protocol )、 RARP C Reverse Address Resolution Protocol) 等協定都可認為是 IP 協定族的子協定。
python 網絡子產品
傳輸層協定主要是 TCP 和 UDP, Python 提供了 socket 等子產品針對傳輸層協定進行程式設計。
URL (Uniform Resource Locator)
URL 可以由協定名 、主機、端口和資源路徑組成,即滿足以下格式:
protocol ://host :port/path/…/[?query-string][#anchor]
# query-string:參數,發送給http伺服器的資料
# anchor:錨(跳轉到網頁的指定錨點位置)
例如如下的 URL 位址:
http://www.crazyit.org/index.php
二 urllib 子產品
urllib 子產品則包含了多個用于處理 URL 的子子產品。 );
- urllib. request:這是最核心的子子產品,它包含了打開和讀取 URL 的各種函數。 );
- urllib.error: 主要包含由 urllib.request 子子產品所引發的各種異常。 );
- urllib.parse: 用于解析 URL。 );
- urllib.robotparser: 主要用于解析 robots.txt 檔案。
通過使用 urllib 子產品可以打開任意 URL 所指向的資源,就像打開本地檔案一樣,這樣程式就 能完整地下載下傳遠端頁面。如果再與第 10 章介紹的 re 子產品結合使用,那麼程式完全可以提取頁面中 各種資訊,這就是所謂的“網絡爬蟲”的初步原理。
在Python2.x中,urllib分為urllib和urllib2兩個子產品,前者用于簡單下載下傳,後者可用于http驗證,cookie管理
urllib.parse
urlparse
屬性名 | 元組索引 | 傳回值 | 屬性名 | 元組索引 | 傳回值 |
---|---|---|---|---|---|
scheme | – | fragment | 5 | ||
netloc | 1 | 主機和端口 | username | None | |
path | 2 | – | password | None | |
params | 3 | 資源路徑附加參數 | hostname | None | |
query | 4 | 查詢字元串 | port | None |
result = urlparse('http://www.crazyit.org:80/index.php;yeeku?name=fkit#frag')
print(result)
# 通過屬性名和索引來擷取URL的各部分
print('資源路徑:', result.path, result[2])
print('參數:', result.params, result[3])
print('查詢字元串:', result.query, result[4])
print('fragment:', result.fragment, result[5])
print(result.geturl())
# 輸出
資源路徑: /index.php /index.php
參數: yeeku yeeku
查詢字元串: name=fkit name=fkit
fragment: frag frag
http://www.crazyit.org:80/index.php;yeeku?name=fkit#frag
解析查詢字元串 parse_qs, parse_qsl
# 解析查詢字元串,傳回dict
result = parse_qs('name=fkit&name=%E7%96%AF%E7%8B%82java&age=12')
print(result)
# 解析查詢字元串,傳回list
result = parse_qsl('name=fkit&name=%E7%96%AF%E7%8B%82java&age=12')
print(result)
# 将清單格式的請求參數恢複成請求參數字元串
print(urlencode(result))
# 輸出
{'name': ['fkit', '瘋狂java'], 'age': ['12']}
[('name', 'fkit'), ('name', '瘋狂java'), ('age', '12')]
name=fkit&name=%E7%96%AF%E7%8B%82java&age=12
urljoin
# 被拼接URL不以斜線開頭
result = urljoin('http://www.crazyit.org/users/login.html', 'help.html')
print(result) # http://www.crazyit.org/users/help.html
result = urljoin('http://www.crazyit.org/users/login.html', 'book/list.html')
print(result) # http://www.crazyit.org/users/book/list.html
# 被拼接URL以斜線(代表根路徑path)開頭
result = urljoin('http://www.crazyit.org/users/login.html', '/help.html')
print(result) # http://www.crazyit.org/help.html
# 被拼接URL以雙斜線(代表絕對URL)開頭
result = urljoin('http://www.crazyit.org/users/login.html', '//help.html')
print(result) # http://help.html
urllib.request
urlopen
urllib.request.urlopen(url, data=None).
urllib.request.urlopen(urllib.request.Request).
- 該方法用于打開 url 指定的資源, 并從中讀取資料。根據請求 url 的不同, 該方法的傳回值會發生動 态改變。 如果 url 是一個 HTTP 位址, 那麼該方法傳回一個http.client.HTTP Response 對象。
- 使用data屬性向被請求的url發送資料
params = urllib.parse.urlencode({'name': 'fkit', 'password': '123888'})
f=urlopen("http://localhost:8080/test/post.jsp", data=params)
## 等價于使用附加參數,如下
#将請求參數添加到URL的後面
url = 'http://localhost:8080/test/get.jsp?%s' % params
f = urlopen(url=url)
Request
(1) 發送PUT請求
params = 'put請求資料'.encode('utf-8')
# 建立Request對象,設定使用PUT請求
req = Request(url='http://localhost:8080/test/put',
data=params, method='PUT')
req.add_header('Referer', 'http://www.crazyit.org/')
with urlopen(req) as f:
print(f.status)
print(f.read().decode('utf-8'))
三. Http子產品
cookie
例:
import urllib.request as ur
import http.cookiejar as hc, urllib.parse
# 以指定檔案建立CookieJar對象,對象将可以把cookie儲存在檔案中
cookie_jar = hc.MozillaCookieJar('coockie_info.txt')
cookie_processor = ur.HTTPCookieProcessor(cookie_jar)
opener = ur.build_opener(cookie_processor)
# 定義模拟Chrome浏覽器的user_agent
user_agent = r'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36' \
r' (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36'
# 定義請求頭
headers = {'User-Agent':user_agent, 'Connection':'keep-alive'}
#-------------下面代碼發送登入的POST請求----------------
# 定義登入系統的請求參數
params = {'name':'crazyit.org', 'pass':'leegang'}
postdata = urllib.parse.urlencode(params).encode()
# 建立向登入頁面發送POST請求的Request
request = ur.Request('http://localhost:8080/test/login.jsp',
data = postdata, headers = headers)
# 使用OpenerDirector發送POST請求
response = opener.open(request)
print(response.read().decode('utf-8'))
# 将cookie資訊寫入磁盤檔案
cookie_jar.save(ignore_discard=True, ignore_expires=True) # ①
#-------------下面代碼發送通路被保護資源的GET請求----------------
# 建立向"受保護頁面"發送GET請求的Request
request = ur.Request('http://localhost:8080/test/secret.jsp',
headers=headers)
response = opener.open(request)
print(response.read().decode())
四. socket
server.py示例
s = socket.socket()
# 将socket綁定到本機IP和端口
s.bind(('192.168.43.36', 3000))
# 服務端開始監聽來自用戶端的連接配接
s.listen()
while True:
# 每當接收到用戶端socket的請求時,該方法傳回對應的socket和遠端位址
c, addr = s.accept()
print('連接配接位址:', addr)
c.send('您好,您收到了伺服器的新年祝福!'.encode('utf-8'))
# 關閉連接配接
c.close()
client.py示例
s = socket.socket()
# 連接配接遠端主機
s.connect(('192.168.43.36', 3000))
rec = s.recv(1024).decode('utf-8')
以上a.accept()才用阻塞的方式接收消息。
通過 selectors 可實作監聽消息。
五. 郵件處理
1. 郵件發送
- 連接配接 SMTP 伺服器,并使用使用者名、密碼登入伺服器。
- 建立 Emai!Message 對象,該對象代表郵件本身。
- 調用代表與 SMTP 伺服器連接配接的對象的 sendmail()方法發送郵件
主要用到的子產品:smtplib,email.message.EmailMessage
2. 郵件接收
使用 poplib 收取郵件可分為兩步。
- 使用 poplib.POP3 或 poplib.POP3_SSL 按 POP3 協定從伺服器端下載下傳郵件。
- 使用 email.parser.Parser或 email.parser.BytesParser解析郵件件内容,得到 EmailMessage 對象
- 從 EmailMessage 對象中讀取郵件内容。
主要用到的子產品:poplib,email.parser,email.policy
六. 拓展學習
1. 請求封包與相應封包
詳細參考
- 請求封包
執行個體:
結構圖:
常見封包頭屬性
名稱 | 說明 | 值 |
---|---|---|
Accept | 告訴服務端 用戶端接受什麼類型的響應 | 一個或多個MIME類型 |
Cookie | – | – |
Refere | 表示這個請求是從哪個URL過來的 | url |
Cache-Control | 是否在客服端緩存 | – |
User-Agent | ||
其它 | – |
- 響應封包
(1)執行個體
(2)響應狀态碼
- 1xx 消息,一般是告訴用戶端,請求已經收到了,正在處理,别急…
- 2xx 處理成功,一般表示:請求收悉、我明白你要的、請求已受理、已經處理完成等資訊.
- 3xx 重定向到其它地方。它讓用戶端再發起一個請求以完成整個處理。
- 4xx 處理發生錯誤,責任在用戶端,如用戶端的請求一個不存在的資源,用戶端未被授權,禁止通路等。
-
5xx 處理發生錯誤,責任在服務端,如服務端抛出異常,路由出錯,HTTP版本不支援等。
(3)常見封包頭屬性
例 | 說明 |
---|---|
Cache-Control: max-age=3600 | 讓用戶端對響應内容緩存3600秒,也即在3600秒内,如果客戶再次通路該資源,直接從用戶端的緩存中傳回内容給客戶,不要再從服務端擷取 |
ETag:“…” | 當服務端資源發生變化,這個ETag就會相應發生變化。可以讓用戶端“更智能”地處理什麼時候要從服務端取資源,什麼時候可以直接從緩存中傳回響應。 |
Location: http://www.iteye.com | 其實是讓用戶端再發一個請求到A頁面 |
Set-Cookie: UserID=JohnDoe; Max-Age=3600; Version=1 | 服務端可以設定用戶端的Cookie |
2. 檢視本機IP
cmd: ipconfig/all
3. 檢視端口
目的 | – |
---|---|
檢視所有端口使用情況 | netstat -ano |
檢視特定端口 | netstat -ano |
5. UDP協定
- UDP (User Datagram Protocol,使用者資料報協定〉雖然目前 UDP 協定的應用不如TCP 協定廣泛,但 UDP 依然是一種非常實用和可行的網絡傳輸層協定。 尤其是在一些實時性很強的應用場景中,比如網絡遊戲、視訊會議等, UDP 協定的快速能力更具有獨特的魅力。
- UDP 是一種面向非連接配接的協定,面向非連接配接指的是在正式通信前不必與對方先建立連接配接,不 管對方狀态就直接發送資料。 至于對方是否可以接收到這些資料, UDP 協定無法控制,是以說 UDP 是一種不可靠的協定。 UDP 協定适用于一次隻傳送少量資料、對可靠性要求不高的應用環境。
- UDP 協定的主要作用是完成網絡資料流和資料報之間的轉換。在資訊的發送端, UDP 協定 将網絡資料流封裝成資料報,然後将資料報發送出去;在資訊的接收端, UDP 協定将資料報轉換 成實際資料内容。
可以認為 UDP協定的 socket類似于碼頭,資料報則類似于集裝箱。 碼頭的作用就· ‘益,是負責友送、接收集裝箱, 而 socket 的作用則是發送、接收資料報。 是以, 對于基于| UDP 協定的通信雙方而言,沒有所謂的客戶 端和伺服器端的概念。