本教程全部源碼下載連接:share.weiyun.com/5xmFeUO 密碼:fzwh6g
本教程版權歸做者GitOPEN全部,轉載請徵求做者贊成
本教程首發於GitOPEN's Homehtml
Requests是一經常使用的http請求庫,它使用python語言編寫,能夠方便地發送http請求,以及方便地處理響應結果。python
引用官方文檔中的第一句話,來對Requests庫進行一句話簡介:web
Requests 惟一的一個非轉基因的 Python HTTP 庫,人類能夠安全享用。json
翻譯一下,就是:瀏覽器
Requests庫使用簡單安全,威力無邊,老小皆宜。緩存
至於安裝,使用pip安裝,簡直不能更方便了:安全
pip install requests
複製代碼
其餘很少說,直接上手!bash
經過用一個讀取百度首頁的例子,來體驗一下如何在不用瀏覽器的狀況下,讀取互聯網上的信息。服務器
import requests
def get_html():
response = requests.get("http://www.baidu.com")
print(response.status_code)
print(response.encoding)
html_text = response.text
with open("baidu.html", "w") as file:
file.write(html_text)
print("write finished.")
if __name__ == '__main__':
get_html()
複製代碼
屢次運行程序,控制檯下輸出的結果有兩種,而且在當前文件夾下生成了一個baidu.html
的文件,保存了從互聯網上讀取來的百度首頁的內容:cookie
# HTTP請求狀態碼
200
# 網頁編碼
ISO-8859-1
# 響應頭信息(headers)
{'Content-Length': '7610', 'Cache-Control': 'private, no-cache, no-store, proxy-revalidate, no-transform', 'Connection': 'keep-alive', 'Content-Type': 'text/html', 'Date': 'Sat, 16 Jun 2018 07:00:11 GMT', 'Keep-Alive': 'timeout=4', 'Last-Modified': 'Mon, 23 Jan 2017 13:27:29 GMT', 'Pragma': 'no-cache', 'Proxy-Connection': 'keep-alive', 'Server': 'bfe/1.0.8.18', 'Set-Cookie': 'BDORZ=27315; max-age=86400; domain=.baidu.com; path=/'}
# 文件寫入完畢
write finished.
複製代碼
200
UTF-8
{'Content-Length': '12886', 'Cache-Control': 'no-cache', 'Connection': 'keep-alive', 'Content-Type': 'text/html;charset=UTF-8', 'Keep-Alive': 'timeout=4', 'Pragma': 'no-cache', 'Proxy-Connection': 'keep-alive', 'Server': 'Apache-Coyote/1.1', 'Set-Cookie': 'andr_zz=7;domain=.baidu.com;path=/;max-age=600'}
write finished.
複製代碼
輸出的結果有兩種,是由於每一次服務器都給Requests發送的請求迴應了不一樣的響應信息。這點不重要,這個現象是爲了後面討論response.encoding
的用法。
當你須要訪問一個網頁時,你的瀏覽器(這裏是Requests庫)向網頁所在的服務器(百度服務器)發出請求;服務器會返回一個頭信息(server header),用以響應瀏覽器的請求。
經常使用HTTP請求狀態碼含義:
狀態碼 | 含義 |
---|---|
200 | 請求成功 |
301 | 資源被永久轉移到其它URL |
404 | 請求的資源不存在 |
505 | 內部服務器錯誤 |
這些狀態碼的含義沒必要死記硬背,能夠在須要的時候搜索一下。這裏方便參考,給出簡記方法:
非正常狀態碼 | 簡記 |
---|---|
1xx | 服務器對客戶端說:收到了 |
2xx | 服務器對客戶端說:合做愉快 |
3xx | 服務器對客戶端說:回頭見 |
4xx | 服務器對客戶端說:你錯了 |
5xx | 服務器對客戶端說:我錯了 |
更詳細的有關用法,只在有需求的時候查閱就能夠了。參見《HTTP狀態碼》。
當獲得的網頁編碼是ISO-8859-1
時,咱們在瀏覽器中打開baidu.html
文件,發現是頁面中凡是中文的地方都是亂碼,如圖:
當獲得的網頁編碼是utf-8
時,咱們在瀏覽器中打開baidu.html
文件,發現是頁面是正常的,如圖:
總結:
response.encoding
默認認爲編碼爲ISO-8859-1
response.encoding
顯示爲headers中charset的編碼瀏覽器在與服務器進行交流的過程當中,會協商一些參數,用於影響頁面的渲染和展現。當瀏覽器向服務器發送請求的時候,所攜帶的信息爲請求頭信息
;當服務器向瀏覽器返回響應信息的時候,攜帶的信息響應頭信息
。在瀏覽器中,咱們能夠直觀的看到這些信息:
這裏咱們不作詳細的講解,有興趣的同窗能夠參考《HTTP教程》。
HTTP請求報文由3部分組成:請求行+請求頭+請求體
獲取請求報文的方法(Chrome瀏覽器)如圖所示:
Request Headers的內容以下:
GET / HTTP/1.1
Host: www.baidu.com
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
DNT: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7
Cookie: BAIDUID=2D5F6595F31C411DF5DADEA1C10D8A81:FG=1; BIDUPSID=2D5F6595F31C411DF5DADEA1C10D8A81; PSTM=1529210459; BD_HOME=0; H_PS_PSSID=1446_21122_26350_26432; BD_UPN=123253
複製代碼
圖解爲:
Requests庫也能夠幫助咱們拿到這些信息,如下代碼在ipython中進行。
In [20]: r = requests.post('http://httpbin.org/post', data = {'username':'zhangsan','password':'123456'})
In [21]: r.request.method
Out[21]: 'POST'
In [22]: r.request.url
Out[22]: 'http://httpbin.org/post'
In [23]: r.request.headers
Out[23]: {'User-Agent': 'python-requests/2.18.4', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Length': '33', 'Content-Type': 'application/x-www-form-urlencoded'}
In [24]: r.request.body
Out[24]: 'username=zhangsan&password=123456'
複製代碼
Request Headers的字段講解:
屬性名 | 含義 |
---|---|
Accept | 請求報文經過該屬性告訴服務端,客戶端接受什麼類型的響應 |
Cookie | HTTP請求發送時,會把保存在該請求域名下的全部cookie值一塊兒發送給web服務器 |
Referer | 先前網頁的地址,當前請求網頁緊隨其後,即來路 |
Cache-Control | 指定請求和響應遵循的緩存機制 |
Connection | 表示是否須要持久鏈接(HTTP 1.1默認進行持久鏈接) |
Upgrade-Insecure-Requests | 讓瀏覽器自動升級請求 (由 http 升級成 https) |
User-Agent | 瀏覽器的瀏覽器身份標識字符串 |
Accept-Encoding | 可以接受的編碼方式列表 |
Accept-Language | 可以接受的迴應內容的天然語言列表 |
Accept-Charset | 可以接受的字符集 |
更多具體的請求字段含義,請參考維基HTTP頭字段,這裏不作詳細講解。
HTTP協議但是互聯網最基礎最重要的協議。它但是一門大的學問。咱們這裏僅僅講解一些基本概念。
HTTP協議,超文本傳輸協議,即HyperText Transfer Protocol,是互聯網上應用最爲普遍的一種網絡協議。全部的WWW文件都必須遵照這個標準。
HTTP是一個基於「請求與響應」模式的、無狀態的應用層協議。無狀態
能夠理解爲:每個請求與響應沒有上下文聯繫。
對於HTTP協議,咱們在平常使用過程當中,最直觀的就是URL,即統一資源定位符
。它的格式爲:http://host[:port][path]
。URL是經過HTTP協議存取互聯網資源的路徑,一個URL對應一個數據資源。
HTTP協議的請求方法,經常使用的有6種,Requests的幾個經常使用方法是和這個對應的:
方法名 | 含義 |
---|---|
GET | 請求獲取URL位置的資源 |
POST | 向指定資源提交數據進行處理請求(例如提交表單或者上傳文件) |
HEAD | 向服務器請求與GET請求相一致的響應,只不過響應體將不會被返回。這一方法能夠再沒必要傳輸整個響應內容的狀況下,就能夠獲取包含在響應小消息頭中的元信息。 |
PUT | 向指定資源位置上傳其最新內容,覆蓋原資源 |
DELETE | 請求服務器刪除URL定位的資源 |
PATCH | 請求局部更新URL定位的資源,節省網絡帶寬 |
須要知道的7個方法:
方法名稱 | 意義 |
---|---|
requests.request() | 構造一個請求。它是基礎方法 |
requests.get() | 發送Get請求獲取網頁信息, 並返回實體主體,也能夠提交數據,包含在url中 |
requests.post() | 向指定資源提交數據進行處理請求(提交表單或者上傳文件),數據被包含在請求體中 |
requests.head() | 相似於get請求,返回的響應中沒有具體的內容,用於獲取報頭 |
requests.put() | 發送PUT請求的方法, 從客戶端向服務器傳送的數據取代指定的文檔的內容。 |
requests.patch() | 發送PATCH(局部修改)請求的方法 |
requests.delete() | 發送DELETE(刪除)請求的方法, 請求服務器刪除指定的資源 |
在實際編寫爬蟲的時候,最最經常使用的也就是加粗顯示的3個方法。下面,咱們在ipython
中測試使用這幾個方法。
獲取響應頭信息,沒有返回內容體。
$ ipython
Python 3.6.5 (default, Mar 30 2018, 06:42:10)
Type 'copyright', 'credits' or 'license' for more information
IPython 6.4.0 -- An enhanced Interactive Python. Type '?' for help.
In [1]: import requests
In [2]: r = requests.head('http://httpbin.org/get')
In [3]: r.headers
Out[3]: {'Content-Length': '208', 'Access-Control-Allow-Credentials': 'true', 'Access-Control-Allow-Origin': '*', 'Connection': 'keep-alive', 'Content-Type': 'application/json', 'Date': 'Sat, 16 Jun 2018 10:44:44 GMT', 'Keep-Alive': 'timeout=4', 'Proxy-Connection': 'keep-alive', 'Server': 'gunicorn/19.8.1', 'Via': '1.1 vegur'}
複製代碼
向URL用POST請求發送一個字典,自動編碼爲form表單數據。
In [4]: payload = {'key1': 'value1','key2': 'value2'}
In [5]: r = requests.post('http://httpbin.org/post',data = payload)
In [6]: print(r.text)
{"args":{},"data":"","files":{},"form":{"key1":"value1","key2":"value2"},"headers":{"Accept":"*/*","Accept-Encoding":"gzip, deflate","Connection":"close","Content-Length":"23","Content-Type":"application/x-www-form-urlencoded","Host":"httpbin.org","User-Agent":"python-requests/2.18.4"},"json":null,"origin":"45.77.28.136","url":"http://httpbin.org/post"}
複製代碼
form字段:
"form":{"key1":"value1","key2":"value2"}
複製代碼
向URL用POST請求發送一個字符串,自動編碼爲data。
In [7]: abc = 'ABC'
In [8]: r = requests.post('http://httpbin.org/post',data = abc)
In [9]: print(r.text)
{"args":{},"data":"ABC","files":{},"form":{},"headers":{"Accept":"*/*","Accept-Encoding":"gzip, deflate","Connection":"close","Content-Length":"3","Host":"httpbin.org","User-Agent":"python-requests/2.18.4"},"json":null,"origin":"45.77.28.136","url":"http://httpbin.org/post"}
複製代碼
data字段:
"data":"ABC"
複製代碼
該方法和post()
方法的使用相似,只不過它能夠將原有的數據覆蓋掉。
requests.request(method,url,**kwargs
)
**kwargs
:控制訪問的參數,共13個,均爲可選項所以,將method
改成不一樣的請求方式,將等同於具體的requests請求方法。
例如:requests.request("GET",url,**kwargs)
等同於requests.get(url,**kwargs)
。
**kwargs
:控制訪問的參數,13個可用參數的具體使用方法以下:
1.params
:字典或者字節序列,做爲參數增長到url中
In 10: kv = {'key1': 'value1','key2': 'value2'}
In 11: r = requests.request('GET','[http://python123.io/ws](http://python123.io/ws)', params = kv)
In 12: print(r.url)
[https://python123.io/ws?key1=value1&key2=value2](https://python123.io/ws?key1=value1&key2=value2)
複製代碼
2.data
:字典、字節序列或者文件對象,做爲Request的內容。
In 21: kv = {'key1': 'value1','key2': 'value2'}
In 22: r = requests.request('POST','[http://python123.io/ws](http://python123.io/ws)', data = kv)
In 23: body = '主體內容'
In 24: r = requests.request('POST','[http://python123.io/ws](http://python123.io/ws)', data = body.encode('utf-8'))
複製代碼
3.json
:JSON格式的數據,做爲Request的內容。
ln 25: kv = {'key1': 'value1','key2': 'value2'}
In 26: r = requests.request('POST','[http://python123.io/ws](http://python123.io/ws)', json = kv)
複製代碼
4.headers
:字典,用來指定請求頭。⭐️
In 27: hd = {'User-Agent': 'Chrome/10'}
In 28: r = requests.request('POST','[http://python123.io/ws](http://python123.io/ws)', headers = hd)
複製代碼
5.cookies
:字典或者CookieJar,Request中的cookie。⭐️
6.auth
:元祖,支持HTTP認證功能。
7.files
:字典類型,傳輸文件。
In 35: fs = {'file': open('baidu.html','rb')}
In 36: r = requests.request('POST','[http://python123.io/ws](http://python123.io/ws)', files = fs)
複製代碼
8.timeout
:設定超時時間,單位,秒。⭐️
In 37: r = requests.request('GET','[http://python123.io/ws](http://python123.io/ws)', timeout = 10)
複製代碼
9.proxies
:字典類型,設定訪問代理服務器,能夠增長登陸認證。⭐️
使用這個字段,能夠隱藏本身的ip,防止服務器識別爬蟲。
In 40: pxs = {
...: 'http': 'http://user:pass@10.10.10.10:1234',
...: 'https': 'https://10.10.10.10:4321'}
In 41: r = requests.request('GET', '[http://www.baidu.com](http://www.baidu.com)', proxies = pxs)
複製代碼
10.allow_redirects
:它的值爲True/False,默認爲True,重定向開關。表示,是否容許對url進行重定向。
11.stream
:True/False,默認值爲True,獲取的內容是否當即下載。默認是當即下載的。
12.verify
:True/False,默認爲True,認證SSL證書開關。是否對SSL證書進行認證。
13.cert
:本地SSL證書路徑。
須要記住的幾個屬性爲:
屬性名 | 含義 |
---|---|
response.status_code | HTTP響應狀態碼 |
response.encoding | 從HTTP中charset推斷的網頁編碼方式,若是charset不存在,返回ISO-8859-1 |
response.apparent_encoding | 從響應內容中分析出的內容編碼方式 |
response.content | 二進制形式的響應內容,如請求的鏈接是一個圖片等二進制文件,返回的內容用response.content |
response.text | 字符串形式的響應內容,如請求的鏈接是一個網頁,其內容爲html等字符串形式內容,返回的內容用response.text |
在爬蟲實踐中,若是是反覆循環迭代大量信息,不建議使用response.apparent_encoding來推斷網頁編碼,由於這個操做很是耗時。所以,一般的作法是,咱們在編寫爬蟲時,提早肯定網頁的編碼方式,而後設置給response.encoding。
異常 | 含義 |
---|---|
requests.ConnectionError | 網絡鏈接出現異常,如拒絕鏈接等 |
requests.HTTPError | HTTP錯誤異常 |
requests.URLRequired | URL缺失異常 |
requests.TooManyRedirects | 請求超過了設定的最大重定向次數 |
requests.ConnectTimeout | 鏈接遠程服務器超時異常 |
requests.Timeout | 請求URL超時,產生超時異常 |
動手試一試:
在下面的通用代碼中,用Exception這個父類,捕捉了全部可能出現的異常。若是將url = "http://www.baidu.com"
中的網址寫錯了,例如將http://
去掉,將會報錯requests.exceptions.MissingSchema
:
出現異常,類型爲:<class 'requests.exceptions.MissingSchema'>,內容爲:Invalid URL 'www.baidu.com': No schema supplied. Perhaps you meant http://www.baidu.com?
複製代碼
import requests
def get_html(url):
try:
r = requests.get(url, timeout=30)
r.raise_for_status()
r.encoding = r.apparent_encoding
return r.text
except Exception as e:
print("出現異常,類型爲:{},內容爲:{}", type(e), str(e))
if __name__ == '__main__':
url = "http://www.baidu.com"
result = get_html(url)
print(result)
複製代碼
該實驗在ipython下進行。
In [1]: import requests
In [2]: r = requests.get("https://item.jd.com/3446665.html")
In [3]: r.status_code
Out[3]: 200
In [4]: r.encoding
Out[4]: 'gbk'
In [5]: r.text[:500]
Out[5]: '<!DOCTYPE HTML>\n<html lang="zh-CN">\n<head>\n <!-- shouji -->\n <meta http-equiv="Content-Type" content="text/html; charset=gbk" />\n <title>【LG27UD58】LG 27UD58-B 27英寸4K IPS硬屏 低閃屏濾藍光LED背光液晶顯示器【行情 報價 價格 評測】-京東</title>\n <meta name="keywords" content="LG27UD58,LG27UD58,LG27UD58報價,LG27UD58報價"/>\n <meta name="description" content="【LG27UD58】京東JD.COM提供LG27UD58正品行貨,幷包括LG27UD58網購指南,以及LG27UD58圖片、27UD58參數、27UD58評論、27UD58心得、27UD58技巧等信息,網購LG27UD58上京東,放心又輕鬆" />\n <meta name="format-detection" con'
複製代碼
該實驗在pycharm編輯器中編寫並執行:
import requests
import os
def get_pic(url):
# Linux、Unix系統路徑
# 若是是Windows系統應該寫 file_dir = ".//pics//"
file_dir = './pics/'
filename = url.split("/")[-1]
file_path = file_dir + filename
try:
if not os.path.exists(file_dir):
os.mkdir(file_dir)
if not os.path.exists(file_path):
r = requests.get(url, timeout=30)
r.raise_for_status()
with open(file_path, 'wb') as f:
f.write(r.content)
print('文件保存成功')
else:
print('圖片已經存在')
except Exception as e:
print("出現異常,類型爲:{},內容爲:{}".format(type(e), str(e)))
if __name__ == '__main__':
url = "http://image.ngchina.com.cn/2018/0616/20180616123038195.jpg"
get_pic(url)
複製代碼