C:\Users\Tony>pip3 install requests
MicroPython 已經實作了 requests 的子集, 稱為 urequests (不可用 requests), 直接匯入即可使用 :
import urequests
此模組所實作的方法可用 dir() 顯示 :
>>> import urequests
>>> dir(urequests)
['Response', 'patch', '__name__', 'request', 'delete', 'get', 'head', 'post', 'put', 'usocket']
可見 HTTP 的主要方法 GET, POST, HEAD, PUT, DELETE 等都有支援.
雖然 urequests 並非完全實作 requests, 用法仍可參考官網文件 :
# Requests: HTTP for Humans
下列文件則有許多範例 :
# HTTPS POST using urequests.py and Guru Mediation Error
# Python爬虫利器一之Requests库的用法
# Wemos D1 mini User's Guide (PDF) (搜尋 HTTP Request)
本系列測試紀錄前十一篇參考 :
# MicroPython on ESP8266 (二) : 數值型別測試
# MicroPython on ESP8266 (三) : 序列型別測試
# MicroPython on ESP8266 (四) : 字典與集合型別測試
# MicroPython on ESP8266 (五) : WiFi 連線與 WebREPL 測試
# MicroPython on ESP8266 (六) : 檔案系統測試
# MicroPython on ESP8266 (七) : 時間日期測試
# MicroPython on ESP8266 (八) : GPIO 測試
# MicroPython on ESP8266 (九) : PIR 紅外線移動偵測
# MicroPython on ESP8266 (十) : socket 模組測試
# MicroPython on ESP8266 (十一) : urllib.urequest 模組測試
MicroPython 文件參考 :
# MicroPython tutorial for ESP8266 (官方教學)
# http://docs.micropython.org/en/latest/micropython-esp8266.pdf
# http://docs.micropython.org/en/latest/pyboard/library/usocket.html#class-socket
# http://docs.micropython.org/en/v1.8.7/esp8266/library/usocket.html#module-usocket
# https://gist.github.com/xyb/9a4c8d7fba92e6e3761a (驅動程式)
使用 urequests 模組只要使用 import 匯入, 就可以用 get() 或 post() 等方法提出 GET 或 POST 方法了, 其傳回值是一個 Response 物件, 回應內容就放在其 text 屬性中, 例如 :
>>> import urequests
>>> r=urequests.get("http://micropython.org/ks/test.html")
>>> r
<Response object at 3fff21e0>
>>> type(r)
<class 'Response'> #get() 方法傳回 Response 物件
>>> type(r.text)
<class 'str'> #text 屬性存放的是 str 類型 (字串, utf-8 編碼)
>>> r.text #顯示 text 內容
'<!DOCTYPE html>\n<html lang="en">\n <head>\n <title>Test</title>\n </head>\n <body>\n <h1>Test</h1>\n It\'s working if you can read this!\n </body>\n</html>\n'
>>> print(r.text) #用 print() 格式化輸出
<!DOCTYPE html>
<html lang="en">
<head>
<title>Test</title>
</head>
<body>
<h1>Test</h1>
It's working if you can read this!
</body>
</html>
>>>
這比直接處理 HTTP 協定要簡單省事多了.
除了直接用 text 屬性來讀取回應內容外, 也可以用 Response 物件的 content 屬性, 此屬性存放的是從 socket 讀取的原始二進位回應資料 (bytes 型態) :
>>> type(r.content)
<class 'bytes'> #content 屬性存的是 byte 串流 (已轉為 ASCII)
>>> r.content #讀取二進位回應資料
b'<!DOCTYPE html>\n<html lang="en">\n <head>\n <title>Test</title>\n </head>\n <body>\n <h1>Test</h1>\n It\'s working if you can read this!\n </body>\n</html>\n'
>>> print(r.content) #byte 資料用 print() 不會格式化
b'<!DOCTYPE html>\n<html lang="en">\n <head>\n <title>Test</title>\n </head>\n <body>\n <h1>Test</h1>\n It\'s working if you can read this!\n </body>\n</html>\n'
另外, Response 物件還有一個存放 socket 物件的 raw 屬性, 也可以透過此物件的 read() 方法讀取回應資料 (也是 bytes 類型) :
>>> r=urequests.get("http://micropython.org/ks/test.html")
>>> type(r.raw)
<class 'socket'> #raw 存放的是 socket 物件
>>> r.raw
<socket state=3 timeout=-1 incoming=3fff9ba8 off=0>
>>> r.raw.read() #讀取全部回應資料 (=r.content)
b'<!DOCTYPE html>\n<html lang="en">\n <head>\n <title>Test</title>\n </head>\n <body>\n <h1>Test</h1>\n It\'s working if you can read this!\n </body>\n</html>\n'
>>> r.raw.read(20) #read() 已讀完全部緩衝區, 故為空
b''
>>> r=urequests.get("http://micropython.org/ks/test.html") #重新 get
>>> r.raw.read(20) #讀取前面 20 個字元
b'<!DOCTYPE html>\n<htm'
>>>
Response 物件的 status_code 屬性儲存回應狀態, 正常是 200; 而 encoding 屬性存放編碼格式 :
>>> r.status_code
200
>>> r.encoding
'utf-8'
但是 MicroPython 的 urequests 模組的 Response 物件沒有實作 url 與 headers 等屬性 :
>>> r.url #顯示請求之 url
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Response' object has no attribute 'url'
>>> r.headers #顯示全部標頭
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Response' object has no attribute 'headers'
>>> r.headers['content-type']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Response' object has no attribute 'headers'
>>> r.cookies
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Response' object has no attribute 'cookies'
而在 CPython 中執行結果如下 :
Python 3.6.1 (v3.6.1:69c0db5, Mar 21 2017, 18:41:36) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import requests
>>> r=requests.get("http://micropython.org/ks/test.html")
>>> r.url #顯示請求之 url
'http://micropython.org/ks/test.html'
>>> r.headers #顯示全部標頭
{'Server': 'nginx/1.8.1', 'Date': 'Sun, 18 Jun 2017 23:19:41 GMT', 'Content-Type': 'text/html', 'Last-Modified': 'Tue, 03 Dec 2013 00:16:26 GMT', 'Transfer-Encoding': 'chunked', 'Connection': 'keep-alive', 'Vary': 'Accept-Encoding', 'ETag': 'W/"529d22da-b4"', 'Content-Encoding': 'gzip'}
>>> r.headers['content-type'] #顯示指定標頭
'text/html'
>>>
雖然 MicroPython 未實作 headers 屬性, 但可以利用 httpbin.org 所提供的 get/post 方法取得, 它會把請求標頭放在回應訊息內容中以 JSON 格式傳回來, 這就要用到 Response 物件的 json() 方法來處理回應內容了.
>>> r=urequests.get("http://micropython.org/ks/test.html")
>>> r.json()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "urequests.py", line 30, in json
ValueError: syntax error in JSON
但如果使用 httpbin.org 的 GET 測試網頁 http://httpbin.org/get , 其回應內容為 JSON 格式, 這樣呼叫 Response 物件的 json() 方法就不會出現錯誤訊息, 而是將 JSON 字串轉成 dict 物件傳回. 如果用瀏覽器連線 http://httpbin.org/get 會得到如下回應 :
{ "args": {}, "headers": { "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", "Accept-Encoding": "gzip, deflate, sdch", "Accept-Language": "zh-TW,zh;q=0.8,en-US;q=0.6,en;q=0.4", "Connection": "close", "Cookie": "_gauges_unique_month=1; _gauges_unique_year=1; _gauges_unique=1; _gauges_unique_day=1", "Host": "httpbin.org", "Upgrade-Insecure-Requests": "1", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 OPR/45.0.2552.898" }, "origin": "12.174.116.121", "url": "http://httpbin.org/get" }
httpbin.org 伺服器會將請求訊息的標頭組成 JSON 字串後放在回應訊息中傳回來. 因此若測試 http://httpbin.org/get 的話, 呼叫 json() 方法就不會報錯了 :
>>> import urequests
>>> r=urequests.get('http://httpbin.org/get')
>>> r.json() #可執行 json() 了
{'url': 'http://httpbin.org/get', 'headers': {'Host': 'httpbin.org', 'Connection': 'close'}, 'args': {}, 'origin': '1.172.116.121'}
GET 方法要傳遞參數的話是在網址後面用 ? 帶領參數字串. 例如在瀏覽器傳遞 a, b 參數給 GET 測試網頁 httpbin.org/get 的 URL 如下 :
# http://httpbin.org/get?a=1&b=2
瀏覽器會收到如下回應 :
{ "args": { "a": "1", "b": "2" }, "headers": { "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", "Accept-Encoding": "gzip, deflate, sdch", "Accept-Language": "zh-TW,zh;q=0.8,en-US;q=0.6,en;q=0.4", "Connection": "close", "Cookie": "_gauges_unique_month=1; _gauges_unique_year=1; _gauges_unique=1; _gauges_unique_day=1; _gauges_unique_hour=1", "Host": "httpbin.org", "Upgrade-Insecure-Requests": "1", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 OPR/45.0.2552.898" }, "origin": "12.174.116.121", "url": "http://httpbin.org/get?a=1&b=2" }
可見參數 a, b 會放在 args 屬性中傳回來.
在 MicroPython 測試結果如下 :
>>> import urequests
>>> r=urequests.get("http://httpbin.org/get?a=1&b=2") #傳遞參數 a, b
>>> r.text #傳回 JSON 格式字串
'{\n "args": {\n "a": "1", \n "b": "2"\n }, \n "headers": {\n "Connection": "close", \n "Host": "httpbin.org"\n }, \n "origin": "223.141.198.23", \n "url": "http://httpbin.org/get?a=1&b=2"\n}\n'
>>> r.json() #呼叫 json() 方法轉成 dict 物件
{'url': 'http://httpbin.org/get?a=1&b=2', 'headers': {'Host': 'httpbin.org', 'Connection': 'close'}, 'args': {'a': '1', 'b': '2'}, 'origin': '223.141.198.23'}
>>> type(r.json())
<class 'dict'> #傳回值是 dict 物件
>>> r.json()['args'] #擷取 dict 物件之項目 args
{'a': '1', 'b': '2'}
>>> r.json()['args']['a'] #擷取 dict 內的屬性
'1'
以上是 GET 方法的測試, 接下來看 POST 方法, 參考 requests 官方網站的教學文件 :
# http://docs.python-requests.org/en/latest/user/quickstart/#post-a-multipart-encoded-file
亦即只要呼叫 urequests.post() 方法並將要傳遞的參數設給的 data 參數即可. 在 CPython 中, 這個 data 是一個 dict 物件, 傳遞的參數是放在回應訊息的 form 屬性中傳回 :
Python 3.6.1 (v3.6.1:69c0db5, Mar 21 2017, 18:41:36) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import requests
>>> data={'a':'1','b':'2'} #dict 物件
>>> r=requests.post("http://httpbin.org/post", data=data)
>>> r.json()
{'args': {}, 'data': '', 'files': {}, 'form': {'a': '1', 'b': '2'}, 'headers': {'Accept': '*/*', 'Accept-Encoding': 'gzip, deflate', 'Connection': 'close', 'Content-Length': '7', 'Content-Type': 'application/x-www-form-urlencoded', 'Host': 'httpbin.org', 'User-Agent': 'python-requests/2.13.0'}, 'json': None, 'origin': '12.174.116.121', 'url': 'http://httpbin.org/post'}
但在 MicroPython 用 dict 物件傳送參數卻不行, 會出現 "object with buffer protocol required" 錯誤訊息. 測試結果如下 :
>>> data={'a':'1','b':'2'} #dict 物件 (在 MicroPython 不行)
>>> r=urequests.post("http://httpbin.org/post", data=data)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "urequests.py", line 104, in post
File "urequests.py", line 74, in request
TypeError: object with buffer protocol required
我找到下面這篇文章, 發現其 data 不是直接用 dict 物件, 而是其字串型態 :
# HTTPS POST using urequests.py and Guru Mediation Error
我將 data 改成 dict 物件的字串結果 OK, 所傳遞的參數是放在 data 屬性中傳回來 (而不是在 form 屬性中), 而且屬性值是字串而非 dict 物件, 這樣在實際應用的後端程式 (PHP 等) 必須另外進行字串處理以擷取參數. :
>>> data="{'a':'1','b':'2'}" #dict 物件的字串
>>> r=urequests.post("http://httpbin.org/post", data=data)
>>> r.text
'{\n "args": {}, \n "data": "{\'a\':\'1\',\'b\':\'2\'}", \n "files": {}, \n "form": {}, \n "headers": {\n "Connection": "close", \n "Content-Length": "17", \n "Host": "httpbin.org"\n }, \n "json": null, \n "origin": "223.141.198.23", \n "url": "http://httpbin.org/post"\n}\n'
>>> r.json() #轉成 dict 物件
{'files': {}, 'headers': {'Content-Length': '17', 'Host': 'httpbin.org', 'Connection': 'close'}, 'args': {}, 'form': {}, 'origin': '223.141.198.23', 'data': "{'a':'1','b':'2'}", 'json': None, 'url': 'http://httpbin.org/post'}
>>> r.json()['data'] #data 是個字串 (不是 dict 物件)
"{'a':'1','b':'2'}"
# Building a Slack button with ESP8266/MicroPython (使用 D1 mini)
測試結果如下 :
>>> data={'a':'1','b':'2'} #dict 物件
>>> r=urequests.post("http://httpbin.org/post", json=data) #傳遞給 json 參數
>>> r.json()
{'files': {}, 'headers': {'Content-Length': '20', 'Host': 'httpbin.org', 'Connection': 'close'}, 'args': {}, 'form': {}, 'origin': '223.141.170.57', 'data': '{"a": "1", "b": "2"}', 'json': {'a': '1', 'b': '2'}, 'url': 'http://httpbin.org/post'}
>>> r.json()['json']['a'] #json 屬性是 dict 物件
'1'
雖然改用 json 屬性傳遞參數, 但 data 屬性還是在, 可見 data 是似乎指所有傳遞給伺服器的參數字串. 從此例可知, 若要使用 dict 物件傳資料, 則要使用 json 參數; 使用 data 參數的話, 必須將 dict 物件字串化 (序列化). 否則必須借助 json 模組的 dumps() 方法將其序列化, 參考 :
# Python爬虫利器一之Requests库的用法
測試結果如下 :
>>> import json #匯入 json 模組
>>> import urequests
>>> data={'a':'1','b':'2'} #使用 dict 物件
>>> r=urequests.post('http://httpbin.org/post', data=json.dumps(data)) #dict 物件序列化
>>> r.json()
{'files': {}, 'headers': {'Content-Length': '20', 'Host': 'httpbin.org', 'Connection': 'close'}, 'args': {}, 'form': {}, 'origin': '12.174.116.121', 'data': '{"a": "1", "b": "2"}', 'json': {'a': '1', 'b': '2'}, 'url': 'http://httpbin.org/post'}
可見這與上面使用 json 參數結果是一樣的.
另外, 除了上面測試過的 data 與 json 參數外, 呼叫 urequests.post() 方法時也可以將額外的請求標頭以 dict 物件傳遞給 urequests.post() 的 headers 參數, 參考 :
# HTTP POST with Micropython and an ESP8266
但要注意, 這個 headers 參數必須是一個 dict 物件, 不可序列化, 測試結果如下 :
>>> import urequests
>>> data="{'a':'1','b':'2'}"
>>> headers={'content-type': 'application/json'} #dict 物件
>>> r=urequests.post("http://httpbin.org/post", data=data, headers=headers)
>>> r.json()
{'files': {}, 'headers': {'Host': 'httpbin.org', 'Content-Length': '17', 'Content-Type': 'application/json', 'Connection': 'close'}, 'args': {}, 'form': {}, 'origin': '223.141.170.52', 'data': "{'a':'1','b':'2'}", 'json': None, 'url': 'http://httpbin.org/post'}
與上面沒有傳 headers 參數比較, 可知除原有的標頭外, 還多了一個 Content-Type 標頭.
最後, 我在下面這篇發現作者使用了 urequests.request() 方法來提出 GET 與 POST 請求, 而不是我們上面使用的 get() 與 post() 方法, 參考 :
# Send data requests http post. **SOLVED**
其實在 requests 官網就有此 request() 物件的說明, 參考 :
# http://docs.python-requests.org/en/master/api/#main-interface
在 CPython 中可以用 params, data 或 json 傳遞參數, 用 params 傳遞的話, 參數會放在 args 屬性中傳回, 例如 :
Python 3.6.1 (v3.6.1:69c0db5, Mar 21 2017, 18:41:36) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import requests
>>> r=requests.request("GET","http://httpbin.org/get?a=1&b=2")
>>> r.json()
{'args': {'a': '1', 'b': '2'}, 'headers': {'Accept': '*/*', 'Accept-Encoding': 'gzip, deflate', 'Connection': 'close', 'Host': 'httpbin.org', 'User-Agent': 'python-requests/2.13.0'}, 'origin': '12.174.116.121', 'url': 'http://httpbin.org/get?a=1&b=2'} #參數放在 args 與 url 屬性中傳回
>>> data={'a':'1','b':'2'} #dict 物件
>>> r=requests.request("GET","http://httpbin.org/get", params=data) #以 params 傳送
>>> r.json()
{'args': {'a': '1', 'b': '2'}, 'headers': {'Accept': '*/*', 'Accept-Encoding': 'gzip, deflate', 'Connection': 'close', 'Host': 'httpbin.org', 'User-Agent': 'python-requests/2.13.0'}, 'origin': '12.174.116.121', 'url': 'http://httpbin.org/get?a=1&b=2'} #參數放在 args 與 url 屬性中傳回
但是用 data 或 json 的話就很奇怪, 參數似乎沒有傳遞給伺服器 (why?) :
>>> import requests
>>> data={'a':'1','b':'2'}
>>> r=requests.request("GET","http://httpbin.org/get", json=data)
>>> r.json() #args 參數是空的, 沒有 json 參數
{'args': {}, 'headers': {'Accept': '*/*', 'Accept-Encoding': 'gzip, deflate', 'Connection': 'close', 'Content-Length': '20', 'Content-Type': 'application/json', 'Host': 'httpbin.org', 'User-Agent': 'python-requests/2.13.0'}, 'origin': '12.174.116.121', 'url': 'http://httpbin.org/get'}
>>> r=requests.request("GET","http://httpbin.org/get", data=data)
>>> r.json() #args 參數是空的, 沒有 data 參數
{'args': {}, 'headers': {'Accept': '*/*', 'Accept-Encoding': 'gzip, deflate', 'Connection': 'close', 'Content-Length': '7', 'Content-Type': 'application/x-www-form-urlencoded', 'Host': 'httpbin.org', 'User-Agent': 'python-requests/2.13.0'}, 'origin': '12.174.116.121', 'url': 'http://httpbin.org/get'}
在 MicroPython 中 GET 方法則只能在 URL 中附帶字串, 不能使用 params 參數 (未實作), 而 json 與 data 參數雖可用, 但也跟 CPython 一樣沒有傳送出去 (why?), 例如 :
>>> import urequests
>>> data="{'a':'1','b':'2'}"
>>> r=urequests.request("GET","http://httpbin.org/get", params=data)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unexpected keyword argument 'params' #無 params 參數
可見 MicroPython 未實作 params 參數. 而用 data 參數的話雖可執行, 但參數未傳遞出去 :
>>> import urequests
>>> data="{'a':'1','b':'2'}" #須為字串
>>> r=urequests.request("GET","http://httpbin.org/get", data=data)
>>> r.json()
{'url': 'http://httpbin.org/get', 'headers': {'Content-Length': '17', 'Host': 'httpbin.org', 'Connection': 'close'}, 'args': {}, 'origin': '12.174.116.121'}
可見 data 參數沒傳送出去, args 屬性為空, 而 data 屬性無蹤影. 用 json 參數亦然 :
>>> import urequests
>>> data={'a':'1','b':'2'} #須為 dict 物件
>>> r=urequests.request("GET","http://httpbin.org/get", json=data)
>>> r.json()
{'url': 'http://httpbin.org/get', 'headers': {'Content-Length': '20', 'Host': 'httpbin.org', 'Connection': 'close'}, 'args': {}, 'origin': '12.174.116.121'}
只有使用 URL 字串附帶參數才行, 例如 :
>>> import urequests
>>> r=urequests.request('GET','http://httpbin.org/get?a=1&b=2') #'GET' 要大寫
>>> r.json()
{'url': 'http://httpbin.org/get?a=1&b=2', 'headers': {'Host': 'httpbin.org', 'Connection': 'close'}, 'args': {'a': '1', 'b': '2'}, 'origin': '12.174.116.121'}
可見參數是放在 args 屬性中傳回來. 總之, 不論 CPython 或 MicroPython, 使用 URL 字串傳送參數是萬無一失的.
而 POST 方法也是 params 參數未實作, 只能用 data 或 json 參數, 測試結果如下 :
>>> import urequests
>>> data={'a':'1','b':'2'} #json 參數須用 dict 物件
>>> r=urequests.request("POST","http://httpbin.org/post", json=data)
>>> r.json()
{'files': {}, 'headers': {'Content-Length': '20', 'Host': 'httpbin.org', 'Connection': 'close'}, 'args': {}, 'form': {}, 'origin': '12.174.116.121', 'data': '{"a": "1", "b": "2"}', 'json': {'a': '1', 'b': '2'}, 'url': 'http://httpbin.org/post'}
>>> data="{'a':'1','b':'2'}" #data 參數須用字串
>>> r=urequests.request("POST","http://httpbin.org/post", data=data)
>>> r.json()
{'files': {}, 'headers': {'Content-Length': '17', 'Host': 'httpbin.org', 'Connection': 'close'}, 'args': {}, 'form': {}, 'origin': '12.174.116.121', 'data': "{'a':'1','b':'2'}", 'json': None, 'url': 'http://httpbin.org/post'}
總之, 比起 urllib.urequest 來說, urequests 模組比較簡單易用, 其中又以直接呼叫 get() 與 post() 最方便. 使用 GET 方法必須使用 URL 附帶參數方式傳遞; 而用 POST 方法則可用 data 或 json 參數傳遞.
參考 :最後, 我在下面這篇發現作者使用了 urequests.request() 方法來提出 GET 與 POST 請求, 而不是我們上面使用的 get() 與 post() 方法, 參考 :
# Send data requests http post. **SOLVED**
其實在 requests 官網就有此 request() 物件的說明, 參考 :
# http://docs.python-requests.org/en/master/api/#main-interface
在 CPython 中可以用 params, data 或 json 傳遞參數, 用 params 傳遞的話, 參數會放在 args 屬性中傳回, 例如 :
Python 3.6.1 (v3.6.1:69c0db5, Mar 21 2017, 18:41:36) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import requests
>>> r=requests.request("GET","http://httpbin.org/get?a=1&b=2")
>>> r.json()
{'args': {'a': '1', 'b': '2'}, 'headers': {'Accept': '*/*', 'Accept-Encoding': 'gzip, deflate', 'Connection': 'close', 'Host': 'httpbin.org', 'User-Agent': 'python-requests/2.13.0'}, 'origin': '12.174.116.121', 'url': 'http://httpbin.org/get?a=1&b=2'} #參數放在 args 與 url 屬性中傳回
>>> data={'a':'1','b':'2'} #dict 物件
>>> r=requests.request("GET","http://httpbin.org/get", params=data) #以 params 傳送
>>> r.json()
{'args': {'a': '1', 'b': '2'}, 'headers': {'Accept': '*/*', 'Accept-Encoding': 'gzip, deflate', 'Connection': 'close', 'Host': 'httpbin.org', 'User-Agent': 'python-requests/2.13.0'}, 'origin': '12.174.116.121', 'url': 'http://httpbin.org/get?a=1&b=2'} #參數放在 args 與 url 屬性中傳回
但是用 data 或 json 的話就很奇怪, 參數似乎沒有傳遞給伺服器 (why?) :
>>> import requests
>>> data={'a':'1','b':'2'}
>>> r=requests.request("GET","http://httpbin.org/get", json=data)
>>> r.json() #args 參數是空的, 沒有 json 參數
{'args': {}, 'headers': {'Accept': '*/*', 'Accept-Encoding': 'gzip, deflate', 'Connection': 'close', 'Content-Length': '20', 'Content-Type': 'application/json', 'Host': 'httpbin.org', 'User-Agent': 'python-requests/2.13.0'}, 'origin': '12.174.116.121', 'url': 'http://httpbin.org/get'}
>>> r=requests.request("GET","http://httpbin.org/get", data=data)
>>> r.json() #args 參數是空的, 沒有 data 參數
{'args': {}, 'headers': {'Accept': '*/*', 'Accept-Encoding': 'gzip, deflate', 'Connection': 'close', 'Content-Length': '7', 'Content-Type': 'application/x-www-form-urlencoded', 'Host': 'httpbin.org', 'User-Agent': 'python-requests/2.13.0'}, 'origin': '12.174.116.121', 'url': 'http://httpbin.org/get'}
在 MicroPython 中 GET 方法則只能在 URL 中附帶字串, 不能使用 params 參數 (未實作), 而 json 與 data 參數雖可用, 但也跟 CPython 一樣沒有傳送出去 (why?), 例如 :
>>> import urequests
>>> data="{'a':'1','b':'2'}"
>>> r=urequests.request("GET","http://httpbin.org/get", params=data)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unexpected keyword argument 'params' #無 params 參數
可見 MicroPython 未實作 params 參數. 而用 data 參數的話雖可執行, 但參數未傳遞出去 :
>>> import urequests
>>> data="{'a':'1','b':'2'}" #須為字串
>>> r=urequests.request("GET","http://httpbin.org/get", data=data)
>>> r.json()
{'url': 'http://httpbin.org/get', 'headers': {'Content-Length': '17', 'Host': 'httpbin.org', 'Connection': 'close'}, 'args': {}, 'origin': '12.174.116.121'}
可見 data 參數沒傳送出去, args 屬性為空, 而 data 屬性無蹤影. 用 json 參數亦然 :
>>> import urequests
>>> data={'a':'1','b':'2'} #須為 dict 物件
>>> r=urequests.request("GET","http://httpbin.org/get", json=data)
>>> r.json()
{'url': 'http://httpbin.org/get', 'headers': {'Content-Length': '20', 'Host': 'httpbin.org', 'Connection': 'close'}, 'args': {}, 'origin': '12.174.116.121'}
只有使用 URL 字串附帶參數才行, 例如 :
>>> import urequests
>>> r=urequests.request('GET','http://httpbin.org/get?a=1&b=2') #'GET' 要大寫
>>> r.json()
{'url': 'http://httpbin.org/get?a=1&b=2', 'headers': {'Host': 'httpbin.org', 'Connection': 'close'}, 'args': {'a': '1', 'b': '2'}, 'origin': '12.174.116.121'}
可見參數是放在 args 屬性中傳回來. 總之, 不論 CPython 或 MicroPython, 使用 URL 字串傳送參數是萬無一失的.
而 POST 方法也是 params 參數未實作, 只能用 data 或 json 參數, 測試結果如下 :
>>> import urequests
>>> data={'a':'1','b':'2'} #json 參數須用 dict 物件
>>> r=urequests.request("POST","http://httpbin.org/post", json=data)
>>> r.json()
{'files': {}, 'headers': {'Content-Length': '20', 'Host': 'httpbin.org', 'Connection': 'close'}, 'args': {}, 'form': {}, 'origin': '12.174.116.121', 'data': '{"a": "1", "b": "2"}', 'json': {'a': '1', 'b': '2'}, 'url': 'http://httpbin.org/post'}
>>> data="{'a':'1','b':'2'}" #data 參數須用字串
>>> r=urequests.request("POST","http://httpbin.org/post", data=data)
>>> r.json()
{'files': {}, 'headers': {'Content-Length': '17', 'Host': 'httpbin.org', 'Connection': 'close'}, 'args': {}, 'form': {}, 'origin': '12.174.116.121', 'data': "{'a':'1','b':'2'}", 'json': None, 'url': 'http://httpbin.org/post'}
總之, 比起 urllib.urequest 來說, urequests 模組比較簡單易用, 其中又以直接呼叫 get() 與 post() 最方便. 使用 GET 方法必須使用 URL 附帶參數方式傳遞; 而用 POST 方法則可用 data 或 json 參數傳遞.
# Micropython on ESP8266 Workshop Documentation (搜尋 HTTP Request)
# MICROPYTHON ON THE ESP8266: KICKING THE TIRES
# micropython/micropython-lib (MicroPython 的第三方模組)
# ESP8266 and MicroPython - Part 1
# https://requestb.in/
# Send data requests http post. **SOLVED**
2017-08-31 補充 :
urequests 以 POST 方法傳遞參數時, 不論是用 data 或 json, 字典的元素都要用雙引號括起來, 不要用單引號, 實際用法參考 :
# MicroPython on ESP8266 (二十一) : 使用 ThingTweet 傳送推文
請教您:我用ESP8266的WeMos D1 Mini 開發版,3個功能:
回覆刪除1.max7219+3個按鈕控制8位的數碼管。
2.自動連接Wifi使用network跟ubinascii模組。
3.檢查是否連線中,並發送line訊息通知,使用requests模組。
3個個別執行都可以,整合成一個就不行,會出現錯誤(還是亂碼)
交互測試最就是2個可以同時執行,網路找好久應該是記憶體不足
因為是亂碼所以無法確定。
會是這個原因嗎?
改用EPS32能解決嗎?
謝謝
我也不確定, 但有可能是記憶體溢位, D1 Mini 的 SRAM 是 160K, ESP32 則有 512K, 差了三倍, ESP32 開發板也不貴, 程式都一樣, 試試看即知, 我也想知道答案, 請您不吝告知, THANK YOU!
回覆刪除