【Python3 爬蟲學習筆記】基本庫的使用 7 —— 使用requests
抓取二進位制資料
前面我們抓取知乎的一個頁面,實際上它返回的是一個HTML文件。如何抓取圖片、音訊、視訊?
圖片、音訊、視訊這些檔案本質上都是由二進位制碼組成的,由於有特定的儲存格式和對應的解析方式,我們才可以看到這些形形色色的多媒體,所以要抓取它們,就要拿到它們的二進位制碼。
抓取GItHub的站點圖示:
import requests
r = requests.get("https://github.com/favicon.ico")
print(r.text)
print(r.content)
這裡列印了Response物件的兩個屬性,一個是text,另一個是content。
如果按照以上的程式碼,text屬性會出現亂碼,content前面會出現一個b,這代表bytes型別的資料。由於圖片時二進位制資料,所以前者在列印時轉化為str型別,也就是圖片直接轉化為字串,所以會出現亂碼。
將提取的圖片儲存下來:
import requests
r = requests.get("https://github.com/favicon.ico")
with open('favicon.ico', 'wb') as f:
f.write(r.content)
這裡用了open()方法,它的第一個引數是檔名稱,第二個引數代表以二進位制寫的形式開啟,可以向檔案裡寫入二進位制資料。
執行結束之後,可以發現在資料夾中出現了名為favicon.ico的圖示。
1.3 POST請求
import requests
data = {'name':'germey', 'age' :'22'}
r = requests.post("http://httpbin.org/post", data=data)
print(r.text)
執行結果:
{
"args": {},
"data": "",
"files": {},
"form": {
"age": "22",
"name": "germey"
},
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate",
"Connection": "close",
"Content-Length" : "18",
"Content-Type": "application/x-www-form-urlencoded",
"Host": "httpbin.org",
"User-Agent": "python-requests/2.18.4"
},
"json": null,
"origin": "221.216.169.171",
"url": "http://httpbin.org/post"
}
1.4 響應
傳送請求後,得到的自然就是響應。在上面的例項中,我們使用text和content獲取了響應的內容。刺蝟,還有很多屬性和方法可以用來獲取其他資訊,比如狀態碼、響應頭、Cookies等。示例如下:
import requests
r = requests.get('http://www.jianshu.com')
print(type(r.status_code), r.status_code)
print(type(r.headers), r.headers)
print(type(r.cookies), r.cookies)
print(type(r.url), r.url)
print(type(r.history), r.history)
這裡分別列印輸出status_code屬性得到狀態碼,輸出headers屬性得到響應頭,輸出cookies屬性得到Cookies,輸出url屬性得到URL,輸出history屬性得到請求歷史。
執行結果如下:
狀態碼常用來判斷請求是否成功,而requests還提供了一個內建的狀態碼查詢物件requests.codes。
2.2 高階用法
2.2.1 檔案上傳
requests可以模擬提交一些資料。同樣也可以使用requests上傳檔案,示例如下:
import requests
files = {'file':open('favicon.ico', 'rb')}
r = requests.post("http://httpbin.org/post", files=files)
print(r.text)
2.2.2 Cookies
import requests
r = requests.get("https://www.baidu.com")
print(r.cookies)
for key, value in r.cookies.items():
print(key + '=' + value)
執行結果:
這裡首先呼叫cookies屬性即可成功得到Cookies,可以發現它是RequestCookiesJar型別。然後用items()方法將其轉化Wie元組組成的列表,便利輸出每一個Cookie的名稱和值,實現Cookie的遍歷解析。
2.2.3 會話維持
在requests中,如果直接利用get()或post()等方法的確可以做到模擬網頁的請求,但是這實際上是相當遠不同的會話,也就是說相當於你用了兩個瀏覽器打開了不同的頁面。
維持同一個會話,要開啟一個新的瀏覽器選項卡而不是新開一個瀏覽器。使用Session物件。
利用Session,可以做到模擬同一個會話而不用擔心Cookies的問題,它通常用於模擬登陸成功之後再進行下一步的操作。
一個示例
import requests
s = requests.Session()
s.get('http://httpbin.org/cookies/set/number/123456789')
r = s.get('http://httpbin.org/cookies')
print(r.text)
執行結果:
{
"cookies": {
"number": "123456789"
}
}
2.2.4 SSL證書驗證
requests提供了證書驗證的功能。當傳送HTTP請求的時候,它會檢查SSL證書,我們可以使用verify引數控制是否檢查此證書。如果不加verify引數的話,預設是True,會自動驗證。
import requests
response = requests.get('https://www.12306.cn', verify=False)
print(response.status_code)
2.2.5 代理設定
對於某些網站,在測試的時候請求幾次,能正常獲取內容。但是一旦開始大規模爬取,對於大規模且頻繁的請求,網站可能會彈出驗證碼,或者跳轉到登入認證頁面,更甚者可能會直接封禁客戶端的IP,導致一定時間段內無法訪問。
為了防止這種情況發生,需要設定代理來解決這個問題,這就需要用到proxies引數。
可以用這樣的方式設定:
import requests
proxies = {
"http":"http://10.10.1.10:2128",
"https":"http://10.10.1.10:1080",
}
requests.get("https://www.taobao.com", proxies=proxies)
這個代理可能無效,需要換成有效代理。
若代理需要使用HTTP Basic Auth,可以使用類似http://user:[email protected]:port 這樣的語法來設定代理,示例如下:
import requests
proxies = {
"http":"http://user:[email protected]:3128/",
}
requests.get("https://www.taobao.com", proxies=porxies)
除了基本的HTTP代理外,requests還支援SOCKS協議的代理。
首先需要安裝socks這個庫:
pip3 install ‘requests[socks]’
然後就可以使用SOCKS協議代理了,示例如下:
import requests
proxies = {
'http':'socks5://user:[email protected]:port',
'https':'socks5://user:[email protected]:port'
}
requests.get("https://www.taobao.com", proxies=proxies)
2.2.6 超時設定
在本機網路狀況不好或者伺服器網路響應太慢甚至無響應時,可能會等待特別久的時間才可能收到響應,甚至到最後收不到響應而報錯。為了防止伺服器不能及時響應,應該設定一個超時時間,即超過了這個時間還沒有得到響應,那就報錯。這需要用到timeout引數。這個時間的計算是發出請求到伺服器返回響應的時間。示例如下:
import requests
r = requests.get("https://www.taobao.com", timeout = 1)
print(r.status_code)
通過這樣的方式,可以將超時時間設定為1秒,如果1秒內沒有響應,就會丟擲異常。
實際上,請求分為兩個階段,即連線(connect)和讀取(read)。上面設定的timeout將用作連線和讀取這二者的timeout總和。
如果要分別指定,就可以傳入一個元組:
r = requests.get('https://www.taobao.com', timeout=(5,11,30))
如果想永遠等待,可以直接將timeout設定為None,或者不設定直接留空,因為預設是None。這樣的話,如果伺服器還在執行,但是響應特別慢,就只能慢慢等,它將永遠不會返回超時錯誤的。其用法如下:
r = requests.get("https://www.taobao.com', timeout=None)
2.2.7 身份認證
在訪問網站時,可能需要認證,此時可以使用requests自帶的身份認證功能,示例如下:
import requests
from requests.auth import HTTPBasicAuth
r = requests.get('http://localhost:5000', auth=HTTPBasicAuth('username', 'password')
print(r.status_code)
如果使用者名稱和密碼正確的話,請求時就會自動認證成功,會返回200狀態碼;如果認證失敗,則返回401狀態碼。
當然,如果引數都傳一個HTTPBasicAuth類,就顯得煩瑣,所以requests提供了一個更簡單的寫法,可以直接傳一個元組,它hi預設使用HTTPBasicAuth這個類來認證。
import requests
r = requests.get('http://localhost:5000', auth=('username', 'password'))
print(r.status_code)
此外,requests還提供了其他認證方式,如OAuth認證,不過此時需要安裝oauth包,安裝命令如下:
pip3 install requests_oauthlib
使用OAuth1認證的方法如下:
import requests
from requests_oauthlib import OAuth1
url = 'https://api.twitter.com/1.1/account/verify_credentials.json'
auth = OAuth1('YOUR_APP_KEY', 'YOUR_APP_SECRET', 'USER_OAUTH_TOKEN', 'USER_OAUTH_TOKEN_SECRET')
requests.get(url, auth=auth)
2.2.8 Prepared Request
使用urllib時,可以將請求表示為資料結構,其中各個引數都可以通過一個Request物件來表示。在requests裡同樣可以做到,這個資料結構就叫Prepared Request。示例如下:
from requests import Request, Session
url = 'http://httpbin.org/post'
data = {
'name':'germey'
}
headers = {'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36'}
s = Session()
req = Request('POST', url, data=data, headers=headers)
prepped = s.prepare_request(req)
r = s.send(prepped)
print(r.text)
這裡引入了Request,然後用url、data和headers引數構造了一個Request物件,這時需要再呼叫Session的prepare_request()方法將其轉換為一個Prepared Request物件,然後呼叫send()方法傳送即可,執行結果如下:
{
"args": {},
"data": "",
"files": {},
"form": {
"name": "germey"
},
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate",
"Connection": "close",
"Content-Length": "11",
"Content-Type": "application/x-www-form-urlencoded",
"Host": "httpbin.org",
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36"
},
"json": null,
"origin": "221.216.169.171",
"url": "http://httpbin.org/post"
}
有了Request這個物件,就可以將請求當作獨立的物件來看待,這樣在進行佇列排程時會非常方便。