request 模塊
Requests: 讓 HTTP 服務人類
雖然Python的標準庫中 urllib 模塊已經包含了平常我們使用的大多數功能,但是它的 API 使用起來讓人感覺不太好,而 Requests 自稱 "HTTP for Humans",說明使用更簡潔方便。
Requests 唯一的一個非轉基因的 Python HTTP 庫,人類可以安全享用:)
Requests 繼承了urllib的所有特性。Requests支持HTTP連接保持和連接池,支持使用cookie保持會話,支持文件上傳,支持自動確定響應內容的編碼,支持國際化的 URL 和 POST 數據自動編碼。
requests 的底層實現其實就是 urllib
Requests的文檔非常完備,中文文檔也相當不錯。Requests能完全滿足當前網絡的需求,支持Python 2.6--3.5,而且能在PyPy下完美運行。
開源地址:https://github.com/kennethreitz/requests
中文文檔 API: http://docs.python-requests.org/zh_CN/latest/index.html
安裝方式
利用 pip 安裝 或者利用 easy_install 都可以完成安裝:
$ pip install requests
$ easy_install requests
基本GET請求(headers參數 和 parmas參數)
1. 最基本的GET請求可以直接用get方法
response = requests.get("http://www.baidu.com/")
# 也可以這麼寫
# response = requests.request("get", "http://www.baidu.com/")
2. 添加 headers 和 查詢參數
如果想添加 headers,可以傳入headers參數來增加請求頭中的headers信息。如果要將參數放在url中傳遞,可以利用 params 參數。
import requests
kw = {'wd':'長城'}
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"}
# params 接收一個字典或者字符串的查詢參數,字典類型自動轉換爲url編碼,不需要urlencode()
response = requests.get("http://www.baidu.com/s?", params = kw, headers = headers)
# 查看響應內容,response.text 返回的是Unicode格式的數據
print (response.text)
# 查看響應內容,response.content返回的字節流數據
print (respones.content)
# 查看完整url地址
print (response.url)
# 查看響應頭部字符編碼
print (response.encoding)
# 查看響應碼
print (response.status_code)
使用response.text 時,Requests 會基於 HTTP 響應的文本編碼自動解碼響應內容,大多數 Unicode 字符集都能被無縫地解碼。
使用response.content 時,返回的是服務器響應數據的原始二進制字節流,可以用來保存圖片等二進制文件。
小栗子
通過requests獲取新浪首頁
#coding=utf-8
import requests
response = requests.get("http://www.sina.com")
print(response.request.headers)
print(response.content.decode())
通過requests獲取網絡上圖片的大小
from io import BytesIO,StringIO
import requests
from PIL import Image
img_url = "http://imglf1.ph.126.net/pWRxzh6FRrG2qVL3JBvrDg==/6630172763234505196.png"
response = requests.get(img_url)
f = BytesIO(response.content)
img = Image.open(f)
print(img.size)
理解一下 BytesIO 和StringIO
很多時候,數據讀寫不一定是文件,也可以在內存中讀寫。
StringIO顧名思義就是在內存中讀寫str。
BytesIO 就是在內存中讀寫bytes類型的二進制數據
例子中如果使用StringIO 即f = StringIO(response.text)會產生"cannot identify p_w_picpath file"的錯誤
當然上述例子也可以把圖片存到本地之後再使用Image打開來獲取圖片大小
Cookies 和 Sission
Cookies
如果一個響應中包含了cookie,那麼我們可以利用 cookies參數拿到:
import requests
response = requests.get("http://www.baidu.com/")
# 7\. 返回CookieJar對象:
cookiejar = response.cookies
# 8\. 將CookieJar轉爲字典:
cookiedict = requests.utils.dict_from_cookiejar(cookiejar)
print (cookiejar)
print (cookiedict)
運行結果:
<RequestsCookieJar[<Cookie BDORZ=27315 for .baidu.com/>]>
{'BDORZ': '27315'}
session
基本POST請求(data參數)
1. 最基本post方法
response = requests.post("http://www.baidu.com/", data = data)
2. 傳入data數據
對於 POST 請求來說,我們一般需要爲它增加一些參數。那麼最基本的傳參方法可以利用 data 這個參數。
import requests
formdata = {
"type":"AUTO",
"i":"i love python",
"doctype":"json",
"xmlVersion":"1.8",
"keyfrom":"fanyi.web",
"ue":"UTF-8",
"action":"FY_BY_ENTER",
"typoResult":"true"
}
url = "http://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule&smartresult=ugc&sessionFrom=null"
headers={ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36"}
response = requests.post(url, data = formdata, headers = headers)
print (response.text)
# 如果是json文件可以直接顯示
print (response.json())
運行結果
{"type":"EN2ZH_CN","errorCode":0,"elapsedTime":3,"translateResult":[[{"src":"i love python","tgt":"我喜歡python"}]],"smartResult":{"type":1,"entries":["","肆文","","","高德納","",""]}}
{'type': 'EN2ZH_CN', 'errorCode': 0, 'elapsedTime': 3, 'translateResult': [[{'src': 'i love python', 'tgt': '我喜歡python'}]], 'smartResult': {'type': 1, 'entries': ['', '肆文', '', '', '高德納', '', '']}}
代理(proxies參數)
如果需要使用代理,你可以通過爲任意請求方法提供 proxies 參數來配置單個請求:
import requests
# 根據協議類型,選擇不同的代理
proxies = {
"http": "http://12.34.56.79:9527",
"https": "http://12.34.56.79:9527",
}
response = requests.get("http://www.baidu.com", proxies = proxies)
print response.text
也可以通過本地環境變量 HTTP_PROXY 和 HTTPS_PROXY 來配置代理:
export HTTP_PROXY="http://12.34.56.79:9527"
export HTTPS_PROXY="https://12.34.56.79:9527"
私密代理驗證(特定格式) 和 Web客戶端驗證(auth 參數)
私密代理
import requests
# 如果代理需要使用HTTP Basic Auth,可以使用下面這種格式:
proxy = { "http": "mr_mao_hacker:[email protected]:16816" }
response = requests.get("http://www.baidu.com", proxies = proxy)
print (response.text)
web客戶端驗證
如果是Web客戶端驗證,需要添加 auth = (賬戶名, 密碼)
import requests
auth=('test', '123456')
response = requests.get('http://192.168.199.107', auth = auth)
print (response.text)
Cookies 和 Sission
Cookies
如果一個響應中包含了cookie,那麼我們可以利用 cookies參數拿到:
import requests
response = requests.get("http://www.baidu.com/")
# 7\. 返回CookieJar對象:
cookiejar = response.cookies
# 8\. 將CookieJar轉爲字典:
cookiedict = requests.utils.dict_from_cookiejar(cookiejar)
print (cookiejar)
print (cookiedict)
運行結果:
<RequestsCookieJar[<Cookie BDORZ=27315 for .baidu.com/>]>
{'BDORZ': '27315'}
session
在 requests 裏,session對象是一個非常常用的對象,這個對象代表一次用戶會話:從客戶端瀏覽器連接服務器開始,到客戶端瀏覽器與服務器斷開。
會話能讓我們在跨請求時候保持某些參數,比如在同一個 Session 實例發出的所有請求之間保持 cookie 。
實現人人網登錄
import requests
# 1\. 創建session對象,可以保存Cookie值
ssion = requests.session()
# 2\. 處理 headers
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"}
# 3\. 需要登錄的用戶名和密碼
data = {"email":"[email protected]", "password":"alarmchime"}
# 4\. 發送附帶用戶名和密碼的請求,並獲取登錄後的Cookie值,保存在ssion裏
ssion.post("http://www.renren.com/PLogin.do", data = data)
# 5\. ssion包含用戶登錄後的Cookie值,可以直接訪問那些登錄後纔可以訪問的頁面
response = ssion.get("http://www.renren.com/410043129/profile")
# 6\. 打印響應內容
print (response.text)
處理HTTPS請求 SSL證書驗證
Requests也可以爲HTTPS請求驗證SSL證書:
要想檢查某個主機的SSL證書,你可以使用 verify 參數(也可以不寫)
import requests
response = requests.get("https://www.baidu.com/", verify=True)
# 也可以省略不寫
# response = requests.get("https://www.baidu.com/")
print (r.text)
運行結果:
<!DOCTYPE html>
<!--STATUS OK--><html> <head><meta http-equiv=content-type
content=text/html;charset=utf-8><meta http-equiv=X-UA-Compatible
content=IE=Edge>百度一下,你就知道 ....
如果SSL證書驗證不通過,或者不信任服務器的安全證書,則會報出SSLError,據說 12306 證書是自己做的:
來測試一下:
import requests
response = requests.get("https://www.12306.cn/mormhweb/")
print (response.text)
果然:
SSLError: ("bad handshake: Error([('SSL routines', 'ssl3_get_server_certificate', 'certificate verify failed')],)",)
如果我們想跳過 12306 的證書驗證,把 verify 設置爲 False 就可以正常請求了。
r = requests.get("https://www.12306.cn/mormhweb/", verify = False)
添加更多的Header信息
在 HTTP Request 中加入特定的 Header,來構造一個完整的HTTP請求消息。
可以通過調用Request.add_header() 添加/修改一個特定的header 也可以通過調用Request.get_header()來查看已有的header。
添加一個特定的header
隨機添加/修改User-Agent
root@ubuntu:/data/server/spider# cat spider_ua.py
import urllib.request
import random
url = "http://www.itcast.cn"
ua_list = [
"Mozilla/5.0 (Windows NT 6.1; ) Apple.... ",
"Mozilla/5.0 (X11; CrOS i686 2268.111.0)... ",
"Mozilla/5.0 (Macintosh; U; PPC Mac OS X.... ",
"Mozilla/5.0 (Macintosh; Intel Mac OS... "
]
user_agent = random.choice(ua_list)
print(user_agent)
request = urllib.request.Request(url)
request.add_header("User-Agent",user_agent)
response = urllib.request.urlopen(request)
html = response.read()
print(html)
接下來,讓我們真正邁向我們的爬蟲之路吧!
urllib庫的基本使用
所謂網頁抓取,就是把URL地址中指定的網絡資源從網絡流中讀取出來,保存到本地。 在Python中有很多庫可以用來抓取網頁,我們先學習urllib。
在 python2 中,urllib 被分爲urllib,urllib2等
urlopen
我們先來段代碼:
# urllib_request.py
# 導入urllib.request 庫
import urllib.request
# 向指定的url發送請求,並返回服務器響應的類文件對象
response = urllib.request.urlopen("http://www.baidu.com")
# 類文件對象支持文件對象的操作方法,如read()方法讀取文件全部內容,返回字符串
html = response.read()
# 打印字符串
print (html)
執行寫的python代碼,將打印結果
Power@PowerMac ~$: python urllib_request.py
實際上,如果我們在瀏覽器上打開百度主頁, 右鍵選擇“查看源代碼”,你會發現,跟我們剛纔打印出來的是一模一樣。也就是說,上面的4行代碼就已經幫我們把百度的首頁的全部代碼爬了下來。
一個基本的url請求對應的python代碼真的非常簡單。
Request
在我們第一個例子裏,urlopen()的參數就是一個url地址;
但是如果需要執行更復雜的操作,比如增加HTTP報頭,必須創建一個 Request 實例來作爲urlopen()的參數;而需要訪問的url地址則作爲 Request 實例的參數。
我們編輯urllib_request.py
# urllib_request.py
import urllib.request
# url 作爲Request()方法的參數,構造並返回一個Request對象
request = urllib.request.Request("http://www.baidu.com")
# Request對象作爲urlopen()方法的參數,發送給服務器並接收響應
response = urllib.request.urlopen(request)
html = response.read().decode()
print (html)
運行結果是完全一樣的:
新建Request實例,除了必須要有 url 參數之外,還可以設置另外兩個參數:
data(默認空):是伴隨 url 提交的數據(比如要post的數據),同時 HTTP 請求將從 "GET"方式 改爲 "POST"方式。
headers(默認空):是一個字典,包含了需要發送的HTTP報頭的鍵值對。
這兩個參數下面會說到。
User-Agent
但是這樣直接用urllib給一個網站發送請求的話,確實略有些唐突了,就好比,人家每家都有門,你以一個路人的身份直接闖進去顯然不是很禮貌。而且有一些站點不喜歡被程序(非人爲訪問)訪問,有可能會拒絕你的訪問請求。
但是如果我們用一個合法的身份去請求別人網站,顯然人家就是歡迎的,所以我們就應該給我們的這個代碼加上一個身份,就是所謂的User-Agent頭。
瀏覽器 就是互聯網世界上公認被允許的身份,如果我們希望我們的爬蟲程序更像一個真實用戶,那我們第一步,就是需要僞裝成一個被公認的瀏覽器。用不同的瀏覽器在發送請求的時候,會有不同的User-Agent頭。 urllib默認的User-Agent頭爲:Python-urllib/x.y(x和y是Python主版本和次版本號,例如 Python-urllib/2.7)
#urllib_request.py
import urllib.request
url = "http://www.itcast.cn"
#IE 9.0 的 User-Agent,包含在 ua_header裏
ua_header = {"User-Agent" : "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0;"}
# url 連同 headers,一起構造Request請求,這個請求將附帶 IE9.0 瀏覽器的User-Agent
request = urllib.request.Request(url, headers = ua_header)
# 向服務器發送這個請求
response = urllib.request.urlopen(request)
html = response.read()
print (html)
添加更多的Header信息
在 HTTP Request 中加入特定的 Header,來構造一個完整的HTTP請求消息。
可以通過調用Request.add_header() 添加/修改一個特定的header 也可以通過調用Request.get_header()來查看已有的header。
添加一個特定的header
# urllib_headers.py
import urllib.request
url = "http://www.itcast.cn"
#IE 9.0 的 User-Agent
header = {"User-Agent" : "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0;"}
request = urllib.request.Request(url, headers = header)
#也可以通過調用Request.add_header() 添加/修改一個特定的header
request.add_header("Connection", "keep-alive")
# 也可以通過調用Request.get_header()來查看header信息
# request.get_header(header_name="Connection")
response = urllib.request.urlopen(request)
print (response.code) #可以查看響應狀態碼
html = response.read().decode()
print (html)
隨機添加/修改User-Agent
# urllib_add_headers.py
import urllib
import random
url = "http://www.itcast.cn"
ua_list = [
"Mozilla/5.0 (Windows NT 6.1; ) Apple.... ",
"Mozilla/5.0 (X11; CrOS i686 2268.111.0)... ",
"Mozilla/5.0 (Macintosh; U; PPC Mac OS X.... ",
"Mozilla/5.0 (Macintosh; Intel Mac OS... "
]
user_agent = random.choice(ua_list)
request = urllib.request.Request(url)
#也可以通過調用Request.add_header() 添加/修改一個特定的header
request.add_header("User-Agent", user_agent)
# get_header()的字符串參數,第一個字母大寫,後面的全部小寫
request.get_header("User-agent")
response = urllib.request.urlopen(requestr)
html = response.read()
print (html)