1. 程式人生 > >小白學 Python 爬蟲(18):Requests 進階操作

小白學 Python 爬蟲(18):Requests 進階操作

人生苦短,我用 Python

前文傳送門:

小白學 Python 爬蟲(1):開篇

小白學 Python 爬蟲(2):前置準備(一)基本類庫的安裝

小白學 Python 爬蟲(3):前置準備(二)Linux基礎入門

小白學 Python 爬蟲(4):前置準備(三)Docker基礎入門

小白學 Python 爬蟲(5):前置準備(四)資料庫基礎

小白學 Python 爬蟲(6):前置準備(五)爬蟲框架的安裝

小白學 Python 爬蟲(7):HTTP 基礎

小白學 Python 爬蟲(8):網頁基礎

小白學 Python 爬蟲(9):爬蟲基礎

小白學 Python 爬蟲(10):Session 和 Cookies

小白學 Python 爬蟲(11):urllib 基礎使用(一)

小白學 Python 爬蟲(12):urllib 基礎使用(二)

小白學 Python 爬蟲(13):urllib 基礎使用(三)

小白學 Python 爬蟲(14):urllib 基礎使用(四)

小白學 Python 爬蟲(15):urllib 基礎使用(五)

小白學 Python 爬蟲(16):urllib 實戰之爬取妹子圖

小白學 Python 爬蟲(17):Requests 基礎使用

超時設定

前面我們在介紹 urllib 的時候也介紹過超時,我們現在來看下在 Requests 中的超時應該怎麼寫。

import requests

r = requests.get("https://www.geekdigging.com/", timeout = 1)
print(r.status_code)

具體的執行結果小編就不貼了。

注意

timeout 僅對連線過程有效,與響應體的下載無關。 timeout 並不是整個下載響應的時間限制,而是如果伺服器在 timeout 秒內沒有應答,將會引發一個異常(更精確地說,是在 timeout 秒內沒有從基礎套接字上接收到任何位元組的資料時)If no timeout is specified explicitly, requests do not time out.

代理設定

和 urllib 一樣,多的介紹就不說了,直接上程式碼:

import requests

proxies = {
  "http": "http://10.10.1.10:3128",
  "https": "http://10.10.1.10:1080",
}

requests.get("https://www.geekdigging.com/", proxies=proxies)

當然,直接執行這個示例可能不行,因為這個代理可能是無效的,可以自己找一些免費的代理進行測試。

而 Requests 除了支援 HTTP 代理,還支援 Socket 代理,因為這是一個可選的功能,在 Requests 的標準庫中並未包含,所以在使用前需要先安裝。

pip install requests[socks]

安裝好依賴以後,使用 SOCKS 代理和使用 HTTP 代理一樣簡單:

import requests

proxies_socket = {
    'http': 'socks5://user:pass@host:port',
    'https': 'socks5://user:pass@host:port'
}

requests.get("https://www.geekdigging.com/", proxies = proxies_socket)

Cookies

前面我們使用 urllib 處理 Cookies 的時候,寫法比較複雜,而使用 Requests 會使證件事情變得非常簡單,獲取和設定 Cookies 只需一步就能完成。先看一個簡單的示例:

import requests

r = requests.get("https://www.csdn.net")
print(type(r.cookies), r.cookies)
for key, value in r.cookies.items():
    print(key + '=' + value)

結果如下:

<class 'requests.cookies.RequestsCookieJar'> <RequestsCookieJar[<Cookie dc_session_id=10_1575798031732.659641 for .csdn.net/>, <Cookie uuid_tt_dd=10_19615575150-1575798031732-646184 for .csdn.net/>, <Cookie acw_tc=2760827715757980317314369e26895215355a996a74e112d9936f512dacd1 for www.csdn.net/>]>
dc_session_id=10_1575798031732.659641
uuid_tt_dd=10_19615575150-1575798031732-646184
acw_tc=2760827715757980317314369e26895215355a996a74e112d9936f512dacd1

在 Requests 中我們使用 cookies 屬性就可以直接得到 Cookies 。通過列印我們可以發現它的型別是 requests.cookies.RequestsCookieJar ,然後用 items() 方法將其轉化為元組組成的列表,遍歷輸出每一個 Cookie 的名稱和值,實現 Cookie 的遍歷解析。

通過 Cookies 維持會話狀態

因為知乎是需要登入才能訪問的,我們選址知乎作為測試的站點,首先直接訪問知乎,看下返回的狀態碼。

import requests

r = requests.get('https://www.zhihu.com')
print(r.status_code)

結果如下:

400

狀態碼 400 的含義是請求無效(Bad request)。

我們開啟瀏覽器,登入知乎,開啟 F12 開發者模式,看下我們登入後的 Cookies 是什麼。

我們將這段內容 copy 下來,加到訪問頭中:

import requests

headers = {
    'cookie': '_zap=7c875737-af7a-4d55-b265-4e3726f8bd30; _xsrf=MU9NN2kHxdMZBVlENJkgnAarY6lFlPmu; d_c0="ALCiqBcc8Q-PTryJU9ro0XH9RqT4NIEHsMU=|1566658638"; UM_distinctid=16d16b54075bed-05edc85e15710b-5373e62-1fa400-16d16b54076e3d; tst=r; q_c1=1a9d0d0f293f4880806c995d7453718f|1573961075000|1566816770000; Hm_lvt_98beee57fd2ef70ccdd5ca52b9740c49=1574492254,1574954599,1575721552,1575721901; tgw_l7_route=f2979fdd289e2265b2f12e4f4a478330; CNZZDATA1272960301=1829573289-1568039631-%7C1575793922; capsion_ticket="2|1:0|10:1575798464|14:capsion_ticket|44:M2FlYTAzMDdkYjIzNDQzZWJhMDcyZGQyZTZiYzA1NmU=|46043c1e4e6d9c381eb18f5dd8e5ca0ddbf6da90cddf10a6845d5d8c589e7754"; z_c0="2|1:0|10:1575798467|4:z_c0|92:Mi4xLXNyV0FnQUFBQUFBc0tLb0Z4enhEeVlBQUFCZ0FsVk53eFRhWGdBSlc3WFo1Vk5RUThBMHMtanZIQ2tYcGFXV2pn|02268679f394bd32662a43630236c2fd97e439151b0132995db7322736857ab6"; Hm_lpvt_98beee57fd2ef70ccdd5ca52b9740c49=1575798469',
    'host': 'www.zhihu.com',
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36'
}

r = requests.get('https://www.zhihu.com', headers = headers)
print(r.text)

執行結果如下:

結果太長了,小編就直接截個圖。

有一點需要注意的是,這裡的請求頭增加了 UA 和 host ,不然也是無法訪問的。

當然除了直接貼這麼一串字串,也是可以通過構造 cookies 的引數來設定 cookies ,這樣需要構建一個 RequestsCookieJar 物件,步驟相對會複雜一點,結果是一樣的。

# 構建 RequestsCookieJar 物件
cookies = '_zap=7c875737-af7a-4d55-b265-4e3726f8bd30; _xsrf=MU9NN2kHxdMZBVlENJkgnAarY6lFlPmu; d_c0="ALCiqBcc8Q-PTryJU9ro0XH9RqT4NIEHsMU=|1566658638"; UM_distinctid=16d16b54075bed-05edc85e15710b-5373e62-1fa400-16d16b54076e3d; tst=r; q_c1=1a9d0d0f293f4880806c995d7453718f|1573961075000|1566816770000; Hm_lvt_98beee57fd2ef70ccdd5ca52b9740c49=1574492254,1574954599,1575721552,1575721901; tgw_l7_route=f2979fdd289e2265b2f12e4f4a478330; CNZZDATA1272960301=1829573289-1568039631-%7C1575793922; capsion_ticket="2|1:0|10:1575798464|14:capsion_ticket|44:M2FlYTAzMDdkYjIzNDQzZWJhMDcyZGQyZTZiYzA1NmU=|46043c1e4e6d9c381eb18f5dd8e5ca0ddbf6da90cddf10a6845d5d8c589e7754"; z_c0="2|1:0|10:1575798467|4:z_c0|92:Mi4xLXNyV0FnQUFBQUFBc0tLb0Z4enhEeVlBQUFCZ0FsVk53eFRhWGdBSlc3WFo1Vk5RUThBMHMtanZIQ2tYcGFXV2pn|02268679f394bd32662a43630236c2fd97e439151b0132995db7322736857ab6"; Hm_lpvt_98beee57fd2ef70ccdd5ca52b9740c49=1575798469'

jar = requests.cookies.RequestsCookieJar()

for cookie in cookies.split(';'):
    key, value = cookie.split('=', 1)
    jar.set(key, value)

headers_request = {
    'host': 'www.zhihu.com',
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36'
}

r = requests.get('https://www.zhihu.com', cookies = jar, headers = headers)
print(r.text)

結果是可以訪問成功的,小編這裡就不貼了。

簡單講一下實現思路,將上面複製下來的 cookies 使用 split() 進行切割,然後使用 set() 方法將 key 和 value 賦值到 RequestsCookieJar 這個物件中,然後在訪問知乎的時候將 RequestsCookieJar 賦值給 cookies 引數即可。需要注意的是這裡的 header 引數不能少,只是原來 header 裡面的 cookies 無需再設定了。

會話維持

接下來這一個是大招,這個功能在 urllib 中是沒有的。

先想像一個場景,我們在爬取一個網站的資料,其中有一部分需要使用 GET 請求,有一部分需要使用 POST 請求。但是我們在程式中寫一個 get() 再寫一個 post() ,實際上是兩個不同的會話。

可能有的同學要說了,老師,我們前面講的會話維持是通過 Cookies 來做的,可以在每次請求的時候新增上 Cookies 。

沒問題,這樣確實是可以的,但是這麼幹有些麻煩。 Requests 為我們提供了更加簡潔高效的方法—— Session 。

我們還是通過前面介紹過的 https://httpbin.org/ 來進行演示,我們可以通過訪問連結:https://httpbin.org/cookies/set/number/123456789 來設定一個 Cookies ,名稱叫做 number ,內容是 123456789 。

首先看直接使用 Requests 的示例:

import requests

requests.get('https://httpbin.org/cookies/set/number/123456789')
r = requests.get('https://httpbin.org/cookies')
print(r.text)

結果如下:

{
  "cookies": {}
}

我們直接呼叫兩次 get() 方法,並沒有在第二次呼叫的時候獲得 Cookies 。接下來我們換 Session 再看一下:

import requests

s = requests.Session()
s.get('https://httpbin.org/cookies/set/number/123456789')
r = s.get('https://httpbin.org/cookies')
print(r.text)

結果如下:

{
  "cookies": {
    "number": "123456789"
  }
}

顯而易見,我們成功獲取到了之前設定的 Cookies 。

所以,利用 Session 可以做到模擬同一個會話而不用手動再去設定 Cookies,它在我們平時的使用中使用的極其廣泛,因為它可以模擬在同一個瀏覽器中訪問同一個站點的不同的頁面,這在我們爬取很多需要登入的網頁時,極大的方便了我們程式碼的書寫。

示例程式碼

本系列的所有程式碼小編都會放在程式碼管理倉庫 Github 和 Gitee 上,方便大家取用。

示例程式碼-Github

示例程式碼-Gi