python的網路程式設計之requests模組

miner_k發表於2017-08-09

requests網路庫使用

傳送請求

requests.get()
requests.post()
requests.put()
requests.delete()
requests.head()
requests.options()
In [1]: import requests

In [2]: r = requests.get('https://github.com/timeline.json')
In [3]: r = requests.put("http://httpbin.org/put")
In [4]: r = requests.delete("http://httpbin.org/delete")
In [5]: r = requests.head("http://httpbin.org/get")
In [6]: r = requests.options("http://httpbin.org/get")

傳遞URL的值

你也許經常想為 URL 的查詢字串(query string)傳遞某種資料。如果你是手工構建 URL,那麼資料會以鍵/值對的形式置於 URL 中,跟在一個問號的後面。例如, httpbin.org/get?key=val。 Requests 允許你使用 params 關鍵字引數,以一個字串字典來提供這些引數。舉例來說,如果你想傳遞 key1=value1key2=value2httpbin.org/get ,那麼你可以使用如下程式碼:

In [12]: payload = {'key1':'value1','key2':'value2'}
In [13]: r = requests.get('http://httpbin.org/get',params=payload)
In [14]: print(r.url)
http://httpbin.org/get?key2=value2&key1=value1

響應內容

In [40]: import requests

In [41]: r = requests.get('https://github.com/timeline.json')

In [42]: r.text
Out[42]: u'{"message":"Hello there, wayfaring stranger. If you\u2019re reading this then you probably didn\u2019t see our blog post a couple of years back announcing that this API would go away: http://git.io/17AROg Fear not, you should be able to get what you need from the shiny new Events API instead.","documentation_url":"https://developer.github.com/v3/activity/events/#list-public-events"}'

設定編碼格式

>>> r.encoding
'utf-8'
>>> r.encoding = 'ISO-8859-1'

如果你改變了編碼,每當你訪問r.text ,Request 都將會使用 r.encoding的新值。你可能希望在使用特殊邏輯計算出文字的編碼的情況下來修改編碼。比如 HTTP 和 XML 自身可以指定編碼。這樣的話,你應該使用 r.content 來找到編碼,然後設定 r.encoding 為相應的編碼。這樣就能使用正確的編碼解析 r.text 了。

二進位制響應內容

你也能以位元組的方式訪問請求響應體,對於非文字請求:

>>> r.content
b'[{"repository":{"open_issues":0,"url":"https://github.com/...

Requests 會自動為你解碼 gzipdeflate 傳輸編碼的響應資料。

例如,以請求返回的二進位制資料建立一張圖片,你可以使用如下程式碼:

>>> from PIL import Image
>>> from io import BytesIO

>>> i = Image.open(BytesIO(r.content))

JSON響應內容

Requests 中也有一個內建的 JSON 解碼器,助你處理 JSON 資料

In [62]: r.json()
Out[62]: 
{u'documentation_url': u'https://developer.github.com/v3/activity/events/#list-public-events',
 u'message': u'Hello there, wayfaring stranger. If you\u2019re reading this then you probably didn\u2019t see our blog post a couple of years back announcing that this API would go away: http://git.io/17AROg Fear not, you should be able to get what you need from the shiny new Events API instead.'}

原始響應內容

想獲取的原始套接字響應,那麼你可以訪問r.raw。 如果你確實想這麼幹,那請你確保在初始請求中設定了 stream=True。具體你可以這麼做:

>>> r = requests.get('https://github.com/timeline.json', stream=True)
>>> r.raw
<requests.packages.urllib3.response.HTTPResponse object at 0x101194810>
>>> r.raw.read(10)
'\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x03'

但一般情況下,你應該以下面的模式將文字流儲存到檔案:

with open(filename, 'wb') as fd:
    for chunk in r.iter_content(chunk_size):
        fd.write(chunk)

使用 Response.iter_content將會處理大量你直接使用 Response.raw 不得不處理的。 當流下載時,上面是優先推薦的獲取內容方式。 Note that chunk_size can be freely adjusted to a number that may better fit your use cases.

定製請求頭

如果你想為請求新增 HTTP 頭部,只要簡單地傳遞一個dictheaders 引數就可以了。

例如,在前一個示例中我們沒有指定 content-type:

>>> url = 'https://api.github.com/some/endpoint'
>>> headers = {'user-agent': 'my-app/0.0.1'}

>>> r = requests.get(url, headers=headers)

注意: 所有的 header 值必須是 stringbytestring 或者 unicode。儘管傳遞 unicode header 也是允許的,但不建議這樣做

POST請求

傳送POST請求,data引數以字典的形式傳遞

傳送送一些編碼為表單形式的資料,data引數以字典的形式傳入

In [1]: import requests

In [2]: mydata = {"wd":"linux",'name':'redhat'}

In [3]: r = requests.post('http://httpbin.org/post',data=mydat
   ...: a)


In [5]: print r.text
{
  .......
  "form": {
    "name": "redhat", 
    "wd": "linux"
  }, 
 ......
}

傳送post請求,data引數通過元組形式傳遞

data 引數傳入一個元組列表。在表單中多個元素使用同一 key

In [1]: import requests

In [2]: payload = (('key1','value1'),('key2','value2'))

In [3]: r = requests.post('http://httpbin.org/post',data=payload)

In [4]: print r.text
{
  .......
  "form": {
    "key1": "value1", 
    "key2": "value2"
  }, 
  ......
}

傳送post請求,data引數通過string形式來傳遞

In [1]: import json

In [2]: import requests

In [4]: mydata = {'wd':'linux','name':'redhat'}

In [7]: r = requests.post('http://httpbin.org/post',data=json.
   ...: dumps(mydata))

In [8]: print r.text
{
  "args": {}, 
  "data": "{\"wd\": \"linux\", \"name\": \"redhat\"}", 
  "files": {}, 
  "form": {},        #提交的表單是空
  "headers": {
    "Accept": "*/*", 
    "Accept-Encoding": "gzip, deflate", 
    "Connection": "close", 
    "Content-Length": "33", 
    "Host": "httpbin.org", 
    "User-Agent": "python-requests/2.6.0 CPython/2.7.5 Linux/3.10.0-327.el7.x86_64"
  }, 
  "json": {                    # json程式碼中是傳輸的值
    "name": "redhat",  
    "wd": "linux"
  }, 
  "origin": "122.112.217.181", 
  "url": "http://httpbin.org/post"
}

傳送post請求,json引數通過dict形式來傳遞

In [5]: import requests

In [6]: payload = {'key1':'value1','key2':'value2'}

In [7]: r = requests.post('http://httpbin.org/post',json=payload)

In [8]: print r.text
{
  "args": {}, 
  "data": "{\"key2\": \"value2\", \"key1\": \"value1\"}", 
  "files": {}, 
  "form": {}, 
  .......
  "json": {
    "key1": "value1", 
    "key2": "value2"
  }, 
  "origin": "122.112.217.181", 
  "url": "http://httpbin.org/post"
}

POST一個多部分編碼(Multipart-Encoded)的檔案

Requests 使得上傳多部分編碼檔案變得很簡單:

>>> url = 'http://httpbin.org/post'
>>> files = {'file': open('report.xls', 'rb')}

>>> r = requests.post(url, files=files)
>>> r.text
{
  ...
  "files": {
    "file": "<censored...binary...data>"
  },
  ...
}

你可以顯式地設定檔名,檔案型別和請求頭:

>>> url = 'http://httpbin.org/post'
>>> files = {'file': ('report.xls', open('report.xls', 'rb'), 'application/vnd.ms-excel', {'Expires': '0'})}

>>> r = requests.post(url, files=files)
>>> r.text
{
  ...
  "files": {
    "file": "<censored...binary...data>"
  },
  ...
}

如果你想,你也可以傳送作為檔案來接收的字串:

>>> url = 'http://httpbin.org/post'
>>> files = {'file': ('report.csv', 'some,data,to,send\nanother,row,to,send\n')}

>>> r = requests.post(url, files=files)
>>> r.text
{
  ...
  "files": {
    "file": "some,data,to,send\\nanother,row,to,send\\n"
  },
  ...
}

如果你傳送一個非常大的檔案作為 multipart/form-data 請求,你可能希望將請求做成資料流。預設下 requests 不支援, 但有個第三方包requests-toolbelt是支援的。你可以閱讀 toolbelt 文件 來了解使用方法。

在一個請求中傳送多檔案參考 高階用法 一節。

警告
我們強烈建議你用二進位制模式(binary mode)開啟檔案。這是因為 Requests 可能會試圖為你提供 Content-Length header,在它這樣做的時候,這個值會被設為檔案的位元組數(bytes)。如果用文字模式(text mode)開啟檔案,就可能會發生錯誤。

響應狀態碼

In [9]: r.status_code
Out[9]: 200

如果傳送了一個錯誤請求(一個 4XX 客戶端錯誤,或者 5XX 伺服器錯誤響應),我們可以通過Response.raise_for_status() 來丟擲異常:

>>> bad_r = requests.get('http://httpbin.org/status/404')
>>> bad_r.status_code
404

>>> bad_r.raise_for_status()
Traceback (most recent call last):
  File "requests/models.py", line 832, in raise_for_status
    raise http_error
requests.exceptions.HTTPError: 404 Client Error

但是,由於我們的例子中 r 的 status_code 是 200 ,當我們呼叫 raise_for_status() 時,得到的是:

>>> r.raise_for_status()
None

響應頭

In [15]: r.headers
Out[15]: {'content-length': '537', 'via': '1.1 vegur', 'x-powered-by': 'Flask', 'server': 'meinheld/0.6.1', 'connection': 'keep-alive', 'x-processed-time': '0.000684022903442', 'access-control-allow-credentials': 'true', 'date': 'Mon, 21 Aug 2017 14:14:20 GMT', 'access-control-allow-origin': '*', 'content-type': 'application/json'}

socket原生網路庫使用

server1:原始socket API

#!/usr/bin/python
#coding=utf-8

import socket

s = socket.socket()
host = '127.0.0.1'     #監聽的地址。如果讓所有人訪問設定為0.0.0.0
port = 8080            #監聽的埠
s.bind((host,port))

s.listen(20)

while True:
    c,addr = s.accept()
    print '連線地址:',addr
    c.send("歡迎訪問....")
    c.close()

client1:

#!/usr/bin/python
#coding=utf-8

import socket

host = '122.112.217.181'    #伺服器的IP地址
port = 8080                 #伺服器監聽的埠
s = socket.socket()

s.connect((host,port))

print s.recv(1024)

s.close()

參考連結

Requests模組使用指南

相關文章