網絡爬蟲【爬蟲庫urllib】

??我叫不三不四,很高興見到大家,歡迎一起學習交流和進步

今天來講一講爬蟲

urllib介紹

Urllib是Python自帶的標準庫,無須安裝,直接引用即可。

Urllib是一個收集幾個模塊來使用URL的軟件包,大致具備以下功能。
● urllib.request:用于打開和讀取URL。
● urllib.error:包含提出的例外urllib.request。
● urllib.parse:用于解析URL。
● urllib.robotparser:用于解析robots.txt文件。

發送請求

`urllib.request.urlopen`是 Python 中`urllib`模塊的一個函數,用于打開和讀取網絡資源。以下是關于`urlopen`的語法和參數的詳細說明:

語法

urllib.request.urlopen(url, data=None, [timeout, ]*, cafile=None, capath=None, cadefault=False, context=None)

參數解釋

1. url

? 含義:需要訪問的網絡資源的 URL 地址。

? 要求:URL 格式必須完整,包括協議(如`http://`或`https://`)。例如:

url = "https://movie.douban.com"


?? 錯誤示例:如果省略協議,如只寫`movie.douban.com`,程序會提示無法識別 URL 的錯誤。
2. data

? 含義:用于發送請求的數據。

? 默認值:`None`。

? 請求方式:

? 如果`data`為`None`,則表示發送的是 GET 請求。

? 如果`data`不為`None`,則表示發送的是 POST 請求。

? 數據格式:`data`必須是字節類型(`bytes`),通常需要將字典通過`urllib.parse.urlencode()`轉換為字符串,再用`encode()`轉換為字節。例如:
?

import urllib.parse
data = {"key": "value"}
data = urllib.parse.urlencode(data).encode("utf-8")

3. timeout

? 含義:設置請求的超時時間(以秒為單位)。

? 默認值:未設置超時時間時,程序會一直等待,直到請求完成或發生錯誤。

? 作用:避免程序因網絡延遲或服務器無響應而無限等待。例如:

response = urllib.request.urlopen(url, timeout=10) ?# 超時時間為10秒

4. cafile

? 含義:指定用于驗證服務器證書的 CA 證書文件路徑。

? 默認值:`None`。

? 作用:在使用 HTTPS 請求時,用于驗證服務器的身份。如果未指定,Python 會使用系統默認的 CA 證書。


5. capath

? 含義:指定包含 CA 證書的目錄路徑。

? 默認值:`None`。

? 作用:與`cafile`類似,但指定的是一個目錄,而不是單個文件。


6. cadefault

? 含義:已廢棄,不應使用。


7. context

? 含義:用于配置 SSL 上下文,通常用于 HTTPS 請求。

? 默認值:`None`。

? 作用:可以自定義 SSL 設置,例如禁用證書驗證(不推薦,可能不安全)。例如:

import ssl
context = ssl._create_unverified_context() ?# 禁用證書驗證
response = urllib.request.urlopen(url, context=context)

示例代碼

import urllib.request
import urllib.parse# 示例:發送 GET 請求
url = "https://movie.douban.com"
response = urllib.request.urlopen(url)
print(response.read()) ?# 讀取響應內容# 示例:發送 POST 請求
data = {"key": "value"}
data = urllib.parse.urlencode(data).encode("utf-8")
response = urllib.request.urlopen(url, data=data)
print(response.read()) ?# 讀取響應內容

注意事項

? 在使用`urlopen`時,需要確保 URL 格式正確,否則會引發`ValueError`或其他異常。

? 如果需要處理異常,可以使用`try-except`塊捕獲錯誤,例如超時或網絡錯誤。

? 對于 HTTPS 請求,建議使用默認的證書驗證,以確保安全。

?

更靈活的請求

`urllib.request.Request`是 Python 的`urllib`模塊中用于創建 HTTP 請求對象的類。通過這個類,可以自定義請求頭(headers)、請求方法(method)等信息,從而實現更靈活的網絡請求。以下是關于`urllib.request.Request`的語法和參數的詳細說明:
---

語法

urllib.request.Request(url, data=None, headers={}, method=None, origin_req_host=None, unverifiable=False, *, method=None)

---

參數解釋

1. url

? 含義:需要訪問的網絡資源的 URL 地址。

? 要求:必須是完整的 URL,包括協議(如`http://`或`https://`)。例如:

url = "https://movie.douban.com"

? 作用:指定請求的目標地址。

2. data

? 含義:請求的附加數據。

? 默認值:`None`。

? 請求方式:

? 如果`data`為`None`,則默認為 GET 請求。

? 如果`data`不為`None`,則為 POST 請求。

? 數據格式:`data`必須是字節類型(`bytes`)。通常需要將字典通過`urllib.parse.urlencode()`轉換為字符串,再用`encode()`轉換為字節。例如:
?

import urllib.parse
data = {"key": "value"}
data = urllib.parse.urlencode(data).encode("utf-8")

3. headers

? 含義:自定義的 HTTP 請求頭信息。

? 默認值:`{}`(空字典)。

? 作用:通過設置請求頭,可以模擬瀏覽器的行為,繞過某些網站的反爬蟲機制,或者添加必要的認證信息。例如:

headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3","Accept-Language": "en-US,en;q=0.9"}


? 常見請求頭字段:

? `User-Agent`:標識客戶端的軟件版本。

? `Accept-Language`:指定客戶端的語言偏好。

? `Referer`:標識請求的來源頁面。

? `Content-Type`:指定請求體的格式(如`application/json`或`application/x-www-form-urlencoded`)。


4. method

? 含義:顯式指定請求方法(如 GET、POST、PUT、DELETE 等)。

? 默認值:根據`data`參數自動判斷(`data=None`時為 GET,否則為 POST)。

? 作用:允許顯式指定請求方法,避免依賴`data`參數來判斷。例如:
?

request = urllib.request.Request(url, method="GET")

5. origin_req_host

? 含義:指定請求的來源主機名或 IP 地址。

? 默認值:`None`。

? 作用:用于某些特定的 HTTP/1.1 請求,通常不需要手動設置。


6. unverifiable

? 含義:標記請求是否為不可驗證的請求。

? 默認值:`False`。

? 作用:用于某些特定的 HTTP/1.1 請求,通常不需要手動設置。


---示例代碼
以下是一個使用`urllib.request.Request`設置請求頭的完整示例:

import urllib.request
import urllib.parse# 目標 URL
url = "https://movie.douban.com"# 自定義請求頭
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3","Accept-Language": "en-US,en;q=0.9"
}# 創建 Request 對象
request = urllib.request.Request(url, headers=headers)# 發送請求
response = urllib.request.urlopen(request)# 讀取響應內容
print(response.read().decode("utf-8"))

注意事項

1. 請求頭的重要性:某些網站會根據請求頭中的信息(如`User-Agent`)判斷請求是否來自合法的客戶端。如果請求頭設置不當,可能會被拒絕訪問。

2. 數據編碼:如果發送 POST 請求,`data`必須是字節類型。可以通過`urllib.parse.urlencode()`和`encode()`方法進行轉換。

3. 顯式指定方法:雖然`method`參數可以顯式指定請求方式,但通常情況下,通過`data`參數來區分 GET 和 POST 請求已經足夠。

通過`urllib.request.Request`,可以更靈活地控制 HTTP 請求的細節,從而實現更復雜的網絡交互。

代理IP

原理

代理IP的原理:以本機先訪問代理IP,再通過代理IP地址訪問互聯網,這樣網站(服務器)接收到的訪問IP就是代理IP地址。

以下是關于通過`urllib.request.ProxyHandler`動態設置 IP 池以及常見錯誤的描述:


---

動態設置 IP 池


在使用`urllib`進行網絡請求時,可以通過`urllib.request.ProxyHandler`動態設置 IP 池,以實現代理請求。具體步驟如下:

1. 準備代理 IP 池:收集多個可用的代理 IP 地址,格式通常為`http://代理IP:端口`或`https://代理IP:端口`。

2. 創建`ProxyHandler`對象:將代理 IP 地址以字典形式傳入`ProxyHandler`,例如:

proxies = {'http': 'http://代理IP1:端口','https': 'https://代理IP2:端口'
}
proxy_handler = urllib.request.ProxyHandler(proxies)


3. 構建`Opener`對象:使用`urllib.request.build_opener`方法將`ProxyHandler`添加到請求處理器中,并通過`install_opener`安裝該`Opener`對象,使其生效。

? ?opener = urllib.request.build_opener(proxy_handler)urllib.request.install_opener(opener)



4. 發送請求:使用`urllib.request.urlopen`方法發送請求,此時請求會通過指定的代理 IP 發送。

response = urllib.request.urlopen(url)



通過動態設置 IP 池,可以有效隱藏真實 IP 地址,避免被目標服務器封禁,同時提高請求的穩定性和安全性。


---

常見錯誤及原因


在使用代理 IP 池時,可能會遇到以下常見錯誤:
1. `ConnectionResetError: [WinError 10054] 遠程主機強迫關閉了一個現有的連接`

? 原因:該錯誤通常表示目標服務器主動關閉了連接。可能的原因包括:

? 代理 IP 被目標服務器封禁或限制訪問。

? 請求頻率過高,觸發了服務器的反爬蟲機制。

? 代理服務器不穩定或配置錯誤。

? 解決方法:更換代理 IP,降低請求頻率,確保代理服務器的穩定性。


2. `urllib.error.URLError: urlopen error Remote end closed connection without response`

? 原因:目標服務器在接收到請求后未返回任何響應,可能是因為:

? 代理服務器無法正常連接到目標服務器。

? 目標服務器拒絕了代理 IP 的請求。

? 網絡連接不穩定或超時。

? 解決方法:檢查代理 IP 的可用性,嘗試更換代理服務器,或增加請求的超時時間。


3. `urllib.error.URLError: urlopen error [WinError 10054] 遠程主機強迫關閉了一個現有的連接`

? 原因:與`ConnectionResetError`類似,該錯誤表示目標服務器關閉了連接。可能的原因包括:

? 代理 IP 被目標服務器封禁。

? 請求格式或參數不正確,導致服務器拒絕響應。

? 解決方法:更換代理 IP,檢查請求頭和參數是否符合目標服務器的要求。


4. `TimeoutError: [WinError 10060] 由于連接方在一段時間后沒有正確答復或連接的主機沒有反應,因此連接嘗試失敗`

? 原因:該錯誤表示請求超時,可能的原因包括:

? 網絡連接不穩定或延遲過高。

? 代理服務器響應緩慢或無法連接到目標服務器。

? 請求的超時時間設置過短。

? 解決方法:增加請求的超時時間,更換代理服務器,或優化網絡環境。


5. `urllib.error.URLError: urlopen error [WinError 10061] 由于目標計算機拒絕訪問,因此`

? 原因:該錯誤表示目標服務器拒絕了連接請求,可能的原因包括:

? 目標服務器未運行或端口未開放。

? 代理 IP 被目標服務器拒絕訪問。

? 請求的 URL 或端口錯誤。

? 解決方法:檢查目標服務器的狀態和端口是否開放,更換代理 IP,或驗證請求的 URL 和端口是否正確。

cookies

通過提交數據實現用戶登錄之后,會生成帶有登錄狀態的Cookies,這時可以將Cookies保存在本地文件中,下次程序運行的時候,可以直接讀取Cookies文件來實現用戶登錄。特別對于一些復雜的登錄,如驗證碼、手機短信驗證登錄這類網站,使用Cookies能簡單解決重復登錄的問題。

在 Python 中,`urllib`模塊中的`HTTPCookieProcessor`用于處理 HTTP 請求中的 Cookies,而`MozillaCookieJar`是一個用于讀寫 Cookies 的工具。以下是一個使用`HTTPCookieProcessor`和`MozillaCookieJar`來處理 Cookies 的完整示例:


示例:使用`urllib`和`MozillaCookieJar`管理 Cookies

import http.cookiejar
import urllib.request# 創建一個 MozillaCookieJar 對象實例來保存 cookie
cookie_jar = http.cookiejar.MozillaCookieJar('cookies.txt')# 創建一個 HTTPCookieProcessor 對象并傳入 cookie_jar
cookie_processor = urllib.request.HTTPCookieProcessor(cookie_jar)# 創建一個 opener 并傳入 cookie_processor
opener = urllib.request.build_opener(cookie_processor)# 創建請求對象
url = "http://example.com" ?# 替換為需要訪問的網站
request = urllib.request.Request(url)# 使用 opener 發送請求并獲取響應
response = opener.open(request)# 打印響應內容
print(response.read().decode('utf-8'))# 保存 cookies 到文件
cookie_jar.save(ignore_discard=True, ignore_expires=True)# 從文件加載 cookies
cookie_jar.load('cookies.txt', ignore_discard=True, ignore_expires=True)# 再次發送請求,此時會自動攜帶保存的 cookies
response_with_cookies = opener.open(request)
print(response_with_cookies.read().decode('utf-8'))


?

示例說明:

1. 創建`MozillaCookieJar`:用于保存和加載 Cookies。

? `cookie_jar = http.cookiejar.MozillaCookieJar('cookies.txt')`創建了一個`MozillaCookieJar`對象,并指定保存 Cookies 的文件名為`cookies.txt`。


2. 創建`HTTPCookieProcessor`:用于處理 HTTP 請求中的 Cookies。

? `cookie_processor = urllib.request.HTTPCookieProcessor(cookie_jar)`將`cookie_jar`傳遞給`HTTPCookieProcessor`,以便在 HTTP 請求中自動處理 Cookies。


3. 創建`opener`:用于發送 HTTP 請求。

? `opener = urllib.request.build_opener(cookie_processor)`創建了一個`opener`對象,并傳入`cookie_processor`。


4. 發送請求并保存 Cookies:

? 使用`opener.open(request)`發送請求。

? 調用`cookie_jar.save(ignore_discard=True, ignore_expires=True)`將獲取到的 Cookies 保存到文件中。


5. 從文件加載 Cookies:

? 使用`cookie_jar.load('cookies.txt', ignore_discard=True, ignore_expires=True)`從文件中加載 Cookies。


6. 再次發送請求:

? 再次使用`opener.open(request)`發送請求時,`HTTPCookieProcessor`會自動將加載的 Cookies 添加到請求中。
注意事項:

? `ignore_discard`和`ignore_expires`參數:這兩個參數用于在保存和加載 Cookies 時忽略過期時間。

? 網站的 Cookie 策略:某些網站可能使用會話 Cookie,這些 Cookie 在瀏覽器關閉后會失效。因此,保存的 Cookies 可能無法在后續請求中使用。

? 安全性:Cookies 可能包含敏感信息(如會話 ID),在保存和加載 Cookies 時要注意安全性,避免泄露。

如何獲取cookies

在之前的代碼中,雖然涉及到了保存和加載 Cookies 的操作,但沒有明確展示如何直接讀取和查看保存的 Cookies。

在 Python 中,可以通過`MozillaCookieJar`或`CookieJar`的方法直接讀取和查看 Cookies。


完整示例:使用`urllib`和`MozillaCookieJar`管理并讀取 Cookies


import http.cookiejar
import urllib.request# 創建一個 MozillaCookieJar 對象實例來保存 cookie
cookie_jar = http.cookiejar.MozillaCookieJar('cookies.txt')# 創建一個 HTTPCookieProcessor 對象并傳入 cookie_jar
cookie_processor = urllib.request.HTTPCookieProcessor(cookie_jar)# 創建一個 opener 并傳入 cookie_processor
opener = urllib.request.build_opener(cookie_processor)# 創建請求對象
url = "http://example.com" ?# 替換為需要訪問的網站
request = urllib.request.Request(url)# 使用 opener 發送請求并獲取響應
response = opener.open(request)# 打印響應內容
print(response.read().decode('utf-8'))# 保存 cookies 到文件
cookie_jar.save(ignore_discard=True, ignore_expires=True)# 從文件加載 cookies
cookie_jar.load('cookies.txt', ignore_discard=True, ignore_expires=True)# 再次發送請求,此時會自動攜帶保存的 cookies
response_with_cookies = opener.open(request)
print(response_with_cookies.read().decode('utf-8'))# 讀取并打印 cookies
print("\n當前保存的 Cookies:")
for cookie in cookie_jar:print(f"Domain: {cookie.domain}, Name: {cookie.name}, Value: {cookie.value}")


?

補充說明:

1. 讀取 Cookies:

? 在`MozillaCookieJar`對象中,可以通過迭代器的方式訪問保存的 Cookies。

? `for cookie in cookie_jar:`遍歷所有保存的 Cookies。

? 每個`cookie`對象是一個`http.cookiejar.Cookie`實例,包含以下屬性:

? `cookie.domain`:Cookie 所屬的域名。

? `cookie.name`:Cookie 的名稱。

? `cookie.value`:Cookie 的值。


2. 打印 Cookies:

? 在代碼中,通過`print(f"Domain: {cookie.domain}, Name: {cookie.name}, Value: {cookie.value}")`打印每個 Cookie 的詳細信息。


3. 其他 Cookie 屬性:

? 如果需要,還可以訪問其他屬性,例如:

? `cookie.path`:Cookie 的路徑。

? `cookie.expires`:Cookie 的過期時間(時間戳)。

? `cookie.secure`:是否為安全 Cookie(僅在 HTTPS 下有效)。


示例輸出:
假設訪問的網站返回了以下 Cookies:

Set-Cookie: session_id=123456789; Path=/; Domain=example.com
Set-Cookie: user=guest; Path=/; Domain=example.com


運行代碼后,打印的 Cookies 內容可能如下:
當前保存的 Cookies:

Domain: example.com, Name: session_id, Value: 123456789
Domain: example.com, Name: user, Value: guest

實際應用

在實際場景中,獲取網站的 Cookies(尤其是登錄相關的 Cookies)通常需要模擬登錄過程,因為 Cookies 是服務器在用戶登錄后生成并返回的。如果直接訪問一個需要登錄的網站,而沒有進行登錄操作,服務器通常不會返回登錄相關的 Cookies。


模擬登錄以獲取 Cookies
如果目標網站需要登錄,那么在獲取 Cookies 之前,必須先模擬登錄過程。這通常涉及以下幾個步驟:

1. 分析登錄請求:查看登錄頁面的表單數據,確定需要提交的用戶名、密碼和其他參數。

2. 構造登錄請求:使用`urllib`或其他庫構造一個包含登錄信息的 POST 請求。

3. 發送請求并獲取響應:通過`HTTPCookieProcessor`自動處理服務器返回的 Cookies。

4. 保存和使用 Cookies:將獲取到的 Cookies 保存到文件中,并在后續請求中使用這些 Cookies。


示例:模擬登錄以獲取 Cookies
以下是一個完整的示例,展示如何模擬登錄一個需要認證的網站,并獲取登錄后的 Cookies。

import http.cookiejar
import urllib.request
import urllib.parse# 創建一個 MozillaCookieJar 對象實例來保存 cookie
cookie_jar = http.cookiejar.MozillaCookieJar('cookies.txt')# 創建一個 HTTPCookieProcessor 對象并傳入 cookie_jar
cookie_processor = urllib.request.HTTPCookieProcessor(cookie_jar)# 創建一個 opener 并傳入 cookie_processor
opener = urllib.request.build_opener(cookie_processor)# 登錄信息
login_url = "https://example.com/login" ?# 替換為實際的登錄 URL
username = "your_username"
password = "your_password"# 構造表單數據
login_data = {"username": username,"password": password
}# 將表單數據編碼為 bytes
encoded_data = urllib.parse.urlencode(login_data).encode('utf-8')# 創建登錄請求
login_request = urllib.request.Request(login_url, data=encoded_data)# 發送登錄請求
response = opener.open(login_request)# 檢查登錄是否成功(可以根據響應內容或狀態碼判斷)
if response.getcode() == 200:print("登錄成功!")# 保存 cookies 到文件cookie_jar.save(ignore_discard=True, ignore_expires=True)print("Cookies 已保存到 cookies.txt")
else:print("登錄失敗!")# 打印獲取到的 Cookies
print("\n獲取到的 Cookies:")
for cookie in cookie_jar:print(f"Domain: {cookie.domain}, Name: {cookie.name}, Value: {cookie.value}")


?

示例說明

1. 登錄 URL 和表單數據:

? `login_url`是登錄頁面的 URL。

? `login_data`是需要提交的表單數據,通常包括用戶名和密碼。這些數據需要根據目標網站的登錄表單進行調整。


2. 構造 POST 請求:

? 使用`urllib.parse.urlencode`將表單數據編碼為 URL 編碼格式。

? 將編碼后的數據傳遞給`urllib.request.Request`,并指定請求方法為 POST。


3. 發送登錄請求:

? 使用`opener.open(login_request)`發送登錄請求。

? 如果登錄成功,服務器會返回登錄后的 Cookies,這些 Cookies 會被`HTTPCookieProcessor`自動保存到`cookie_jar`中。


4. 保存和打印 Cookies:

? 使用`cookie_jar.save()`將獲取到的 Cookies 保存到文件中。

? 遍歷`cookie_jar`并打印每個 Cookie 的詳細信息。


注意事項

1. 登錄失敗的原因:

? 如果登錄失敗,可能是因為表單數據不正確(如用戶名或密碼錯誤)。

? 有些網站可能使用驗證碼或其他安全機制,需要額外處理。


2. 安全性:

? 在代碼中明文存儲用戶名和密碼是不安全的。在實際應用中,應避免將敏感信息硬編碼到代碼中。


3. HTTPS 和安全問題:

? 如果登錄頁面使用 HTTPS,確保在請求中正確處理 SSL/TLS 證書。

證書驗證

當遇到一些特殊的網站時,在瀏覽器上會顯示連接不是私密連接而導致無法瀏覽該網頁。

CA證書,也稱為SSL證書,是一種數字證書,類似于駕駛證、護照或營業執照的電子副本。由于它通常配置在服務器上,因此也被稱為SSL服務器證書。SSL證書遵循SSL協議,由受信任的數字證書頒發機構(CA)頒發。在驗證服務器身份后,CA會發放SSL證書,它具備服務器身份驗證和數據傳輸加密的功能。SSL證書能夠在客戶端瀏覽器和Web服務器之間建立一條SSL安全通道(Secure Socket Layer,SSL)。SSL安全協議最初由Netscape Communication公司設計開發,主要用于對用戶和服務器進行身份認證,對傳輸的數據進行加密和隱藏,并確保數據在傳輸過程中不被篡改,即保證數據的完整性。如今,SSL協議已成為該領域的全球化標準。

需要注意的是,一些特殊的網站可能會使用自己的證書,而不是由第三方CA頒發的標準證書。

遇到這類驗證證書的網站,最簡單而暴力的方法是直接關閉證書驗證,可以在代碼中引入SSL模塊,設置關閉證書驗證即可。

關閉 SSL 證書驗證,發送一個 HTTP 請求到指定的 URL,并打印出響應的狀態碼。
?

import urllib.request
import ssl# 關閉證書驗證
ssl._create_default_https_context = ssl._create_unverified_contexturl = 'https://kyfw.12306.cn/otn/leftTicket/init'
response = urllib.request.urlopen(url)# 輸出狀態碼
print(response.getcode())

代碼解釋:

1. 導入模塊:

? `urllib.request`用于發送網絡請求。

? `ssl`用于處理 SSL 證書。


2. 關閉 SSL 證書驗證:

? `ssl._create_default_https_context = ssl._create_unverified_context`這行代碼將默認的 HTTPS 上下文替換為不驗證證書的上下文。這通常用于測試目的,因為它會忽略 SSL 證書驗證,這在生產環境中是不安全的。


3. 定義 URL:

? `url`變量存儲了需要訪問的網址。


4. 發送請求:

? 使用`urllib.request.urlopen(url)`發送請求到指定的 URL。


5. 打印狀態碼:

? `response.getcode()`獲取 HTTP 響應的狀態碼,并打印出來。


注意事項:

? 安全性:關閉 SSL 證書驗證會使你的應用容易受到中間人攻擊。在生產環境中,你應該總是驗證 SSL 證書。

? URL 有效性:確保你訪問的 URL 是有效的,否則`urlopen`可能會拋出異常。

url編碼

Python 中`urllib`模塊在發送網絡請求時,根據請求方式(GET 或 POST)以及數據編碼的要求來處理請求參數。


---

1.`urllib.request.urlopen()`方法與請求方式

? `urllib.request.urlopen()`是 Python 中用來發送網絡請求的一個方法。

? 它本身不直接區分是 GET 請求還是 POST 請求,而是通過參數`data`來判斷:

? 如果`data`參數為`None`,那么默認是 GET 請求。

? 如果`data`參數不為`None`,那么會被視為 POST 請求。


2.POST 請求時`data`的處理

? 當你想發送 POST 請求時,`data`參數不能直接傳入普通的字符串或字典,而是需要經過編碼處理。

? 這里的編碼處理是通過`urllib.parse`模塊完成的:

? 首先,需要將參數(通常是字典形式)轉換為 URL 編碼的格式(例如:`key1=value1&key2=value2`)。

? 然后,將編碼后的字符串轉換為字節類型(因為網絡傳輸需要字節類型的數據)。


3.數據編碼的必要性

? 在網絡請求中,如果需要傳遞數據(無論是 GET 的 URL 參數,還是 POST 的請求體),數據都需要被編碼成一種標準的格式,以便在網絡中傳輸。

? `urllib`要求數據必須是 ASCII 文本字符串(經過百分比編碼的格式),并且如果是 POST 請求,還需要將字符串編碼為字節類型。

? 如果不按照要求編碼,直接傳入字符串,就會導致`TypeError`錯誤。


---

舉例說明


假設你想通過 POST 請求向服務器發送以下參數:

data = {'username': 'kimi', 'password': '123456'}


你需要按照以下步驟處理:

1. 編碼參數為 URL 編碼格式:

import urllib.parse
encoded_data = urllib.parse.urlencode(data) ?# 結果是:'username=kimi&password=123456'

2. 將編碼后的字符串轉換為字節類型:

byte_data = encoded_data.encode('utf-8') ?# 結果是:b'username=kimi&password=123456'

3. 發送 POST 請求:

import urllib.request
response = urllib.request.urlopen('http://example.com/login', data=byte_data)

如果直接傳入字符串(如`'username=kimi&password=123456'`)而沒有轉換為字節類型,就會報`TypeError`錯誤。

特殊字符處理

1.`quote()`和`unquote()`的作用

? `quote()`:用于對字符串進行 URL 編碼(也稱為百分比編碼)。它會將字符串中的特殊字符(如中文、空格、`@`、`&`等)轉換為`%`加上兩位十六進制數的形式。例如:

import urllib.parse
encoded_str = urllib.parse.quote("你好,世界!")
print(encoded_str) ?# 輸出:%E4%BD%A0%E5%A5%BD%EF%BC%8C%E4%B8%96%E7%95%8C%EF%BC%81

這樣編碼后的字符串可以安全地放在 URL 中傳輸,因為 URL 只能包含 ASCII 字符。


? `unquote()`:用于對經過 URL 編碼的字符串進行解碼,將其還原為原始字符串。例如:
?

decoded_str = urllib.parse.unquote("%E4%BD%A0%E5%A5%BD%EF%BC%8C%E4%B8%96%E7%95%8C%EF%BC%81")print(decoded_str) ?# 輸出:你好,世界!

2.解決中文內容的問題


在 URL 中,中文字符是不被允許的,因為 URL 只能包含 ASCII 字符。如果直接將中文放入 URL 中,可能會導致錯誤或無法正確解析。例如:

url = "http://example.com/search?q=你好"

這種 URL 在某些情況下可能會報錯,或者服務器無法正確解析。

為了避免這種情況,可以使用`quote()`對中文內容進行編碼:

import urllib.parse
url = "http://example.com/search?q=" + urllib.parse.quote("你好")
print(url) ?# 輸出:http://example.com/search?q=%E4%BD%A0%E5%A5%BD


這樣編碼后的 URL 就可以安全地發送請求了。
---

3.與`urlencode()`的區別

? `urlencode()`是用來編碼字典形式的參數,生成`key=value&key=value`格式的查詢字符串。它主要用于處理多個參數的情況,例如:

data = {'q': '你好', 'page': 1}
encoded_data = urllib.parse.urlencode(data)
print(encoded_data) ?# 輸出:q=%E4%BD%A0%E5%A5%BD&page=1

? `quote()`是用來單獨對字符串進行編碼,適用于單個參數或 URL 中的部分內容。例如:

encoded_str = urllib.parse.quote("你好")
print(encoded_str) ?# 輸出:%E4%BD%A0%E5%A5%BD

?

?

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/72696.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/72696.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/72696.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

LabVIEW棉花穴播器排種自動監測系統

一、項目背景與行業痛點 1. 農業需求驅動 我國棉花主產區,種植面積常年超250萬公頃,傳統人工播種存在兩大核心問題: 效率瓶頸:人均日播種面積不足0.5公頃,難以匹配規模化種植需求; 精度缺陷:人…

解決diffusers加載stablediffusion模型,輸入prompt總是報錯token數超出clip最大長度限制

1. StableDiffusion1.5 在加載huggingface中的擴散模型時,輸入prompt總是會被報錯超過clip的最大長度限制。 解決方案:使用compel庫 from diffusers import AutoPipelineForText2Image import torch import pdb from compel import Compeldevice torc…

jmeter配件元素

jmeter配件元素 CSV Data Set Config名詞解釋測試場景Recycle on EOF:False配置測試結果 Recycle on EOF:True配置測試結果 Sharing mode:All Threads配置測試結果 Sharing mode:Current thread group配置測試結果 Sharing mode:Current thread配置測試結果 HTTP Header Manage…

Navicat SqlServer 設置自增主鍵

Navicat是一款優秀的數據庫管理工具&#xff0c;可以連接很多類型的數據庫。使用它可以極大的提高工作效率。 Navicat 不能設置SqlServer自增字段&#xff0c;只能通過sql語句來實現 建表時設置 create table <表名> ( <字段1-主鍵> int identity (1,1) primar…

Elasticsearch搜索引擎 3(DSL)

Elasticsearch提供了基于JSON的DSL&#xff08;Domain Specific Language&#xff09;語句來定義查詢條件&#xff0c;其JavaAPI就是在組織DSL條件。 1.DSL查詢 葉子查詢&#xff08;Leaf query clauses&#xff09;&#xff1a;在特定的字段里查詢特定值&#xff0c;屬于簡單…

final 在 java 中有什么作用?

final 在 java 中有什么作用&#xff1f; 修飾變量 修飾基本數據類型變量&#xff1a; 當用final修飾基本數據類型變量時&#xff0c;該變量就變成了常量&#xff0c;其值在初始化后不能被改變。 final int num 10; // num 20; // 這行代碼會導致編譯錯誤&#xff0c;因…

Dubbo/Hession2序列化Immutable類型的集合異常問題

問題排查 根據堆棧信息可見&#xff0c;dubbo使用默認的hession2進行序列化時出現了異常&#xff0c;異常堆棧根原因為&#xff1a;null array 位于java.util.CollSer#readResolve方法中&#xff0c;即在序列化集合時&#xff0c;集合數組為空。 向上追溯jdk.internal.ref…

目標檢測任務,如何區分兩個相近似的目標

首先&#xff0c;要了解清楚檢測的場景下&#xff0c;肉眼能否區分出目標的差異性。 如果可以區分&#xff0c;那觀察數據周圍背景的差異是否較大&#xff0c;可以先通過添加樣本來提升模型的檢測精度。添加樣本時一定要注意&#xff0c;樣本標注的準確性&#xff0c;樣本的豐…

Java面試黃金寶典1

1. 8 種基本數據類型 整數類型 byte&#xff1a; 它是最小的整數類型&#xff0c;占用 1 個字節&#xff08;8 位&#xff09;。在一些對內存使用要求極高的場景&#xff0c;比如嵌入式系統開發、數據傳輸時對數據量有嚴格限制的情況&#xff0c;會使用 byte 類型。例如&#x…

OSGEarth

OSGEarth 基于 OpenSceneGraph 構建的一個擴展庫&#xff0c;專門用于地球科學和地理信息系統&#xff08;GIS&#xff09;數據的可視化。它允許開發者創建逼真的三維地球模型&#xff0c;并在其上展示各種地理空間數據。 高端一點的表述 基于三維引擎osg開發的三維數字地球…

Word 小黑第34套

對應大貓34 設置第二頁水印&#xff0c;取消第一頁的&#xff1a;取消第二頁頁眉鏈接&#xff0c;刪除第一張水印圖片&#xff08;delete&#xff09; 調整水印圖片&#xff1a;點開頁眉頁腳 雙擊圖片 可以調整 郵件合并 -創建標簽 橫標簽數3 豎標簽5 表布局 -查看網格線 插…

2.5.1 io_uring

文章目錄 2.5.1 io_uring1. 對比1. select、poll、epoll 對比表格2. 關鍵特性說明&#xff1a;3. 應用場景 2. 異步io1. 頻繁copy2. 如何做到線程安全 3. io_uring1. 實現2. 關鍵點&#xff1a;3. 問題1. Reactor 與 Proactor 的三點不同2. epoll 與 io_uring 的區別 2.5.1 io_…

K8S學習之基礎三十六:node-exporter部署

Prometheus v2.2.1 ? 編寫yaml文件&#xff0c;包含創建ns、configmap、deployment、service # 創建monitoring空間 vi prometheus-ns.yaml apiVersion: v1 kind: Namespace metadata:name: monitoring# 創建SA并綁定權限 kubectl create serviceaccount monitor -n monito…

為什么“連接斷開可能導致鎖未釋放”

目錄 兩種典型場景可能導致鎖未及時釋放1. **數據庫未及時檢測到連接斷開**2. **應用程序未正確處理事務** 為什么說“可能因連接斷開導致死鎖”&#xff1f;如何避免此類問題&#xff1f;總結 在大多數數據庫實現中&#xff0c;如果持有鎖的連接&#xff08;或會話&#xff09…

【實戰指南】基于DevExpress輕量化主題實現WPF應用性能升級

DevExpress WPF擁有120個控件和庫&#xff0c;將幫助您交付滿足甚至超出企業需求的高性能業務應用程序。通過DevExpress WPF能創建有著強大互動功能的XAML基礎應用程序&#xff0c;這些應用程序專注于當代客戶的需求和構建未來新一代支持觸摸的解決方案。 無論是Office辦公軟件…

【C++多線程】C++異步線程池提交任務的寫法和解釋

// 提交任務到線程池 template<class F, class... Args> auto ThreadPool::enqueue(F&& f, Args&&... args) -> std::future<typename std::result_of<F(Args...)>::type> {using return_type typename std::result_of<F(Args...)>…

CSS 屬性選擇器詳解

CSS 屬性選擇器詳解 引言 CSS(層疊樣式表)是網頁設計中的重要組成部分,它用于控制網頁元素的樣式和布局。屬性選擇器是CSS選擇器的一種,它允許開發者根據元素的特定屬性來選擇和樣式化元素。本文將詳細講解CSS屬性選擇器的概念、語法以及常用屬性選擇器的使用方法。 一、…

二維前綴矩陣

1.大衣的旅行 #include<bits/stdc.h> #define int long long using namespace std; int t; int n,m,k; bool check(int mid,vector<vector<int>>pre,vector<vector<int>>a) {for(int i1; i<n; i){for(int j1; j<m; j){//枚舉以老師房間為…

python-leetcode 56.電話號碼的字母組合

題目&#xff1a; 給定一個僅包含數字的2-9的字符串&#xff0c;返回所有它可能表示的字母組合&#xff0c;答案可以按任意順序返回 給出數字到字母的映射如下&#xff08;與電話按鍵相同&#xff09;&#xff0c;注意1不對應任何字母 方法一&#xff1a;深度優先搜索&#x…

keepalived應用

Keepalived 是一個基于 VRRP&#xff08;虛擬路由冗余協議&#xff09;實現的高可用解決方案&#xff0c;常用于構建高可用性的服務器集群&#xff0c;特別是在負載均衡場景中&#xff0c;可確保服務的不間斷運行。以下為你詳細介紹它&#xff1a; 0主要功能 高可用性&#x…