Python爬蟲從入門到精通─第2課 Requests庫講解

本教程全部源碼下載連接:share.weiyun.com/5xmFeUO 密碼:fzwh6g
本教程版權歸做者GitOPEN全部,轉載請徵求做者贊成
本教程首發於GitOPEN's Homehtml

Requests庫講解

簡介與安裝

Requests是一經常使用的http請求庫,它使用python語言編寫,能夠方便地發送http請求,以及方便地處理響應結果。python

引用官方文檔中的第一句話,來對Requests庫進行一句話簡介:web

Requests 惟一的一個非轉基因的 Python HTTP 庫,人類能夠安全享用。json

翻譯一下,就是:瀏覽器

Requests庫使用簡單安全,威力無邊,老小皆宜。緩存

至於安裝,使用pip安裝,簡直不能更方便了:安全

pip install requests
複製代碼

其餘很少說,直接上手!bash

Requests庫的基本用法

體驗入門

經過用一個讀取百度首頁的例子,來體驗一下如何在不用瀏覽器的狀況下,讀取互聯網上的信息。服務器

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的用法。

入門例子剖析

HTTP狀態碼

當你須要訪問一個網頁時,你的瀏覽器(這裏是Requests庫)向網頁所在的服務器(百度服務器)發出請求;服務器會返回一個頭信息(server header),用以響應瀏覽器的請求。

經常使用HTTP請求狀態碼含義:

狀態碼 含義
200 請求成功
301 資源被永久轉移到其它URL
404 請求的資源不存在
505 內部服務器錯誤

這些狀態碼的含義沒必要死記硬背,能夠在須要的時候搜索一下。這裏方便參考,給出簡記方法:

非正常狀態碼 簡記
1xx 服務器對客戶端說:收到了
2xx 服務器對客戶端說:合做愉快
3xx 服務器對客戶端說:回頭見
4xx 服務器對客戶端說:你錯了
5xx 服務器對客戶端說:我錯了

更詳細的有關用法,只在有需求的時候查閱就能夠了。參見《HTTP狀態碼》

網頁編碼

當獲得的網頁編碼是ISO-8859-1時,咱們在瀏覽器中打開baidu.html文件,發現是頁面中凡是中文的地方都是亂碼,如圖:

當獲得的網頁編碼是utf-8時,咱們在瀏覽器中打開baidu.html文件,發現是頁面是正常的,如圖:

總結:

  • 當headers中不存在charset時,response.encoding默認認爲編碼爲ISO-8859-1
  • 當headers中存在charset時,response.encoding顯示爲headers中charset的編碼

頭信息

瀏覽器在與服務器進行交流的過程當中,會協商一些參數,用於影響頁面的渲染和展現。當瀏覽器向服務器發送請求的時候,所攜帶的信息爲請求頭信息;當服務器向瀏覽器返回響應信息的時候,攜帶的信息響應頭信息。在瀏覽器中,咱們能夠直觀的看到這些信息:

這裏咱們不作詳細的講解,有興趣的同窗能夠參考《HTTP教程》

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協議但是互聯網最基礎最重要的協議。它但是一門大的學問。咱們這裏僅僅講解一些基本概念。

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定位的資源,節省網絡帶寬

Requests庫經常使用方法入門

須要知道的7個方法:

方法名稱 意義
requests.request() 構造一個請求。它是基礎方法
requests.get() 發送Get請求獲取網頁信息, 並返回實體主體,也能夠提交數據,包含在url中
requests.post() 向指定資源提交數據進行處理請求(提交表單或者上傳文件),數據被包含在請求體中
requests.head() 相似於get請求,返回的響應中沒有具體的內容,用於獲取報頭
requests.put() 發送PUT請求的方法, 從客戶端向服務器傳送的數據取代指定的文檔的內容。
requests.patch() 發送PATCH(局部修改)請求的方法
requests.delete() 發送DELETE(刪除)請求的方法, 請求服務器刪除指定的資源

在實際編寫爬蟲的時候,最最經常使用的也就是加粗顯示的3個方法。下面,咱們在ipython中測試使用這幾個方法。

requests.head()使用方法

獲取響應頭信息,沒有返回內容體。

$ 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'}
複製代碼

requests.post()

向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"
複製代碼

requests.put()

該方法和post()方法的使用相似,只不過它能夠將原有的數據覆蓋掉。

Requests庫主要方法解析

requests.request(method,url,**kwargs)

  • method:請求方式,對應get/put/post等7種
  • url:獲取頁面的url鏈接
  • **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對象的屬性

須要記住的幾個屬性爲:

屬性名 含義
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庫的異常

異常 含義
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)
複製代碼

參考資料推薦

相關文章
相關標籤/搜索