??我叫不三不四,很高興見到大家,歡迎一起學習交流和進步
今天來講一講爬蟲
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
?
?
?