Requests從入門到進階

特點

  • Keep-Alive & 連接池
  • 國際化域名和 URL
  • 帶持久 Cookie 的會話
  • 瀏覽器式的SSL認證
  • 自動內(nèi)容解碼
  • 基本/摘要式的身份認證
  • 優(yōu)雅的key/value Cookie
  • 自動解壓
  • Unicode 響應(yīng)體
  • HTTP(S) 代理支持
  • 文件分塊上傳
  • 流下載
  • 連接超時
  • 分塊請求
  • 支持 .netrc

缺點:

  • 同步阻塞模式娃惯,不支持異步和協(xié)程
  • 尚不支持HTTP2.0

官方文檔:https://requests.readthedocs.io/zh_CN/latest/

安裝

通過pip命令安裝即可:pip install requests

發(fā)送請求

發(fā)送GET請求

使用requests發(fā)送請求叽掘,只要使用request.get(url)方法填入對應(yīng)的接口地址即可谆棱,支持攜帶URL參數(shù)邓深。調(diào)用方法返回響應(yīng)對象,可以通過響應(yīng)對象的status_code偏序、text、headers等屬性,來獲取狀態(tài)碼吩案、響應(yīng)文本和響應(yīng)頭等數(shù)據(jù),示例如下帝簇。

import requests
res = requests.get('https://httpbin.org/get?name=臨淵&age=18')
print('狀態(tài)碼', res.status_code)
print('響應(yīng)文本', res.text)
print('響應(yīng)頭', res.headers)

URL只支持ASCII(美國標準碼)徘郭,在實際的傳輸過程中,中文及一些特殊字符需要經(jīng)過urlencode(URL編碼)丧肴。如上例中的接口地址會被編碼成:

https://httpbin.org/get?name=%E4%B8%B4%E6%B8%8A&age=18

requests在發(fā)送請求時會自動進行編碼残揉,運行后顯示如下。

狀態(tài)碼 200
響應(yīng)文本 {
  "args": {
    "age": "18", 
    "name": "\u4e34\u6e0a"
  }, 
  "headers": {
    "Accept": "*/*", 
    "Accept-Encoding": "gzip, deflate", 
    "Host": "httpbin.org", 
    "User-Agent": "python-requests/2.18.4"
  }, 
  "origin": "111.194.126.253, 111.194.126.253", 
  "url": "https://httpbin.org/get?name=\u4e34\u6e0a&age=18"
}

響應(yīng)頭 {'Access-Control-Allow-Credentials': 'true', 'Access-Control-Allow-Origin': '*', 'Content-Encoding': 'gzip', 'Content-Type': 'application/json', 'Date': 'Mon, 20 Jan 2020 02:33:47 GMT', 'Referrer-Policy': 'no-referrer-when-downgrade', 'Server': 'nginx', 'X-Content-Type-Options': 'nosniff', 'X-Frame-Options': 'DENY', 'X-XSS-Protection': '1; mode=block', 'Content-Length': '222', 'Connection': 'keep-alive'}

使用Params

Params又叫Query Params芋浮,即URL參數(shù)抱环,如?name=臨淵&age=18。如果參數(shù)很多纸巷,直接寫到URL中會比較長镇草,不方便查看和修改。URL參數(shù)由多組鍵值對組成瘤旨√找梗可以通過字典傳給requests請求放到的params參數(shù),即request.get(url, params={})裆站,示例如下条辟。

import requests
res = requests.get('https://httpbin.org/get', params={'name': '臨淵', 'age': '18'})
print('響應(yīng)文本轉(zhuǎn)為字典', res.json())

由于參數(shù)可能較多,一般我們可以使用變量宏胯,先把url及參數(shù)等數(shù)據(jù)組裝好羽嫡,然后在傳入請求方法中。

res.json()方法實際上是使用了json.loads(res.text)將響應(yīng)文本嘗試以JSON格式轉(zhuǎn)為字典肩袍。由于該方法存在異常(比如正常情況下返回JSON格式杭棵,500報錯時則會返回非JSON格式的報錯信息),建議使用try...except處理氛赐,修改如下魂爪。

import requests
url = 'https://httpbin.org/get'
url_params = {'name': '臨淵', 'age': '18'}
res = requests.get(url, params=url_params)
try:
    print('響應(yīng)文本轉(zhuǎn)為字典', res.json())
except:
    print('響應(yīng)文本', res.text)

url_params是自定義的變量名,一般筆者習(xí)慣使用params作為變量名艰管,來表示和請求方法參數(shù)params的對應(yīng)關(guān)系滓侍。即

params = {'name': '臨淵', 'age': '18'}
res = requests.get(url, params=params)

運行結(jié)果如下。

響應(yīng)文本轉(zhuǎn)為字典 {'args': {'age': '18', 'name': '臨淵'}, 'headers': {'Accept': '*/*', 'Accept-Encoding': 'gzip, deflate', 'Host': 'httpbin.org', 'User-Agent': 'python-requests/2.18.4'}, 'origin': '111.194.126.253, 111.194.126.253', 'url': 'https://httpbin.org/get?name=臨淵&age=18'}

使用請求頭

請求頭是鏈接和請求數(shù)據(jù)的一些輔助說明信息牲芋,常見的請求頭有:

  • Accept:客戶端能接受的內(nèi)容類型
  • Accept-Charset:瀏覽器可以接受的字符編碼
  • Accept-Encoding:瀏覽器可以支持的壓縮編碼類型
  • Accept-Languge:瀏覽器可以接受的語言
  • Referer:連接來路
  • User-Agent:發(fā)送請求的客戶端信息
  • Connection:連接類型(Keepalive保持連接/Close關(guān)閉連接)
  • X-Requested-With:XMLHttpRequest(是Ajax異步請求)
  • Cookie:服務(wù)器標記信息
  • Cache-Control:緩存機制(no-cache無緩存或max-age=緩存保存時間)
  • Expries:緩存過期時間
  • Content-Type:內(nèi)容類型(MIME類型)
  • Content-Length:數(shù)據(jù)長度

請求頭項一般不區(qū)分大小寫撩笆。Cookie是請求頭的一項(注意為單數(shù)形式捺球,不帶s)。因此在請求一些需要登錄狀態(tài)的接口時可以手動抓取到Cookie夕冲,放到請求頭中使用氮兵,示例如下。
(1)手動登錄后歹鱼,通過Chrome開發(fā)者工具抓取請求正常訪問時的請求頭信息泣栈。


image

請求頭中一般cookie用于驗證登錄,referer用于防止盜鏈弥姻,user-agent用于反爬秩霍。

(2)組裝字典格式的請求頭并使用
請求頭一般有一組組鍵值對組成,我們同樣使用Python中的的字典格式蚁阳,構(gòu)造出請求頭數(shù)據(jù),并傳遞給請求方法的headers參數(shù)即可鸽照。

import requests
url = 'http://www.reibang.com/shakespeare/v2/notes/9d3f991c901a/book'
headers = {
    'user-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36',
    'referer': 'http://www.reibang.com/p/9d3f991c901a',
    'cookie': '__yadk_uid=ratDswBmN3Kzid42v2gKV2q8veUvOsEd; read_mode=day; default_font=font2; locale=zh-CN; remember_user_token=W1s3NTc1NzIxXSwiJDJhJDExJFRVVTNvMlV6NjJaVTlXZjF0YWFuZi4iLCIxNTc5NTczNDg1Ljk2MzgyODYiXQ%3D%3D--feb4c1d88427a88d7321791daf2d76f7b11ed4b3; _m7e_session_core=d0065296a1834086d0279a548d932927; Hm_lvt_0c0e9d9b1e7d617b3e6842e85b9fb068=1579573487,1579587460,1579591333,1579591335; Hm_lpvt_0c0e9d9b1e7d617b3e6842e85b9fb068=1579601795; sensorsdata2015jssdkcross=%7B%22distinct_id%22%3A%221697595f5777a9-0a3caa4a8cc382-36667905-1024000-1697595f578430%22%2C%22%24device_id%22%3A%221697595f5777a9-0a3caa4a8cc382-36667905-1024000-1697595f578430%22%2C%22props%22%3A%7B%22%24latest_traffic_source_type%22%3A%22%E7%9B%B4%E6%8E%A5%E6%B5%81%E9%87%8F%22%2C%22%24latest_referrer%22%3A%22%22%2C%22%24latest_search_keyword%22%3A%22%E6%9C%AA%E5%8F%96%E5%88%B0%E5%80%BC_%E7%9B%B4%E6%8E%A5%E6%89%93%E5%BC%80%22%2C%22%24latest_utm_source%22%3A%22weixin-friends%22%2C%22%24latest_utm_medium%22%3A%22reader_share%22%2C%22%24latest_utm_campaign%22%3A%22hugo%22%2C%22%24latest_utm_content%22%3A%22note%22%7D%2C%22first_id%22%3A%22%22%7D'
}
res = requests.get(url, headers=headers)
print(res.text)

headers=headders第一個headers是請求方法的固定參數(shù)螺捐,第二個headers是我們自定義的字典變量(變量也可以使用其他名稱),執(zhí)行后打印信息如下矮燎。

{"notebook_id":26739010,"notebook_name":"Python接口測試","liked_by_user":false}

注:本例中請求頭實際并沒有登錄限制定血,只需要在請求頭添加了user-agent即可正常使用。

使用Cookies

Cookies可以作為一個整體的字符串放到請求頭的Cookie字段中诞外,當Cookies很多并且需要組裝時澜沟,使用字符串會比較長并難以維護。此時可以將Cookies拆開成一組組鍵值對峡谊,構(gòu)造為字典格式的數(shù)據(jù)茫虽,傳遞給請求方法的cookies參數(shù),示例如下既们。

import requests
url = 'http://www.reibang.com/shakespeare/v2/notes/9d3f991c901a/book'
headers = {
    'user-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36',
    'referer': 'http://www.reibang.com/p/9d3f991c901a',
}
cookies = {'Hm_lpvt_0c0e9d9b1e7d617b3e6842e85b9fb068': '1579601795',
 'Hm_lvt_0c0e9d9b1e7d617b3e6842e85b9fb068': '1579573487,1579587460,1579591333,1579591335',
 '__yadk_uid': 'ratDswBmN3Kzid42v2gKV2q8veUvOsEd',
 '_m7e_session_core': 'd0065296a1834086d0279a548d932927',
 'default_font': 'font2',
 'locale': 'zh-CN',
 'read_mode': 'day',
 'remember_user_token': 'W1s3NTc1NzIxXSwiJDJhJDExJFRVVTNvMlV6NjJaVTlXZjF0YWFuZi4iLCIxNTc5NTczNDg1Ljk2MzgyODYiXQ%3D%3D--feb4c1d88427a88d7321791daf2d76f7b11ed4b3',
 'sensorsdata2015jssdkcross': '%7B%22distinct_id%22%3A%221697595f5777a9-0a3caa4a8cc382-36667905-1024000-1697595f578430%22%2C%22%24device_id%22%3A%221697595f5777a9-0a3caa4a8cc382-36667905-1024000-1697595f578430%22%2C%22props%22%3A%7B%22%24latest_traffic_source_type%22%3A%22%E7%9B%B4%E6%8E%A5%E6%B5%81%E9%87%8F%22%2C%22%24latest_referrer%22%3A%22%22%2C%22%24latest_search_keyword%22%3A%22%E6%9C%AA%E5%8F%96%E5%88%B0%E5%80%BC_%E7%9B%B4%E6%8E%A5%E6%89%93%E5%BC%80%22%2C%22%24latest_utm_source%22%3A%22weixin-friends%22%2C%22%24latest_utm_medium%22%3A%22reader_share%22%2C%22%24latest_utm_campaign%22%3A%22hugo%22%2C%22%24latest_utm_content%22%3A%22note%22%7D%2C%22first_id%22%3A%22%22%7D'
}

res = requests.get(url, headers=headers, cookies=cookies)
print(res.text)

注:Cookies中不能擁有非ASCII字符濒析,中文應(yīng)進行URL編碼后使用。

同名參數(shù)處理:
假設(shè)url中具有同名參數(shù)啥纸,如name=臨淵号杏,age=18,age=30斯棒。由于字典中不能存在同名的鍵盾致,我們可以使用嵌套列表實現(xiàn)。示例如下荣暮。
params = [('name','臨淵'), ('age', '18'), ('age', '30')]
請求方法中的其他參數(shù)庭惜,如data、headers等穗酥,如果存在同名變量也可以這樣處理蜈块。

發(fā)送POST請求

POST方法和GET方法本質(zhì)上一樣的鉴腻,都是HTTP請求的一種請求動作。只是通常情況下GET請求不使用請求體數(shù)據(jù)百揭,而POST使用爽哎。既然POST方法會發(fā)送請求體數(shù)據(jù),就會涉及到數(shù)據(jù)類型的問題器一】涡浚客戶端和服務(wù)端商量好,才能正常的解析和通訊祈秕。這種數(shù)據(jù)類型又稱為媒體類型渺贤,標準稱法為MIME(Multipurpose Internet Mail Extensions)類型,即多用途互聯(lián)網(wǎng)郵件擴展類型请毛。數(shù)據(jù)類型的聲明志鞍,一般放在請求頭(請求輔助信息)的Content-Type字段中,常見的有以下幾種格式方仿。

  • application/x-www-form-url-encoded:表單URL編碼格式
  • multipart/form-data:復(fù)合表單格式(支持文件上傳固棚,文件二進制
  • application/json:JSON格式
  • application/xml:XML格式

不同數(shù)據(jù)類型的請求,數(shù)據(jù)組裝方式也不同仙蚜,至于什么時候用表單此洲,什么時候用JSON格式要看接口文檔或問開發(fā)小哥哥,接口在編寫時便已確定好了需要使用的的數(shù)據(jù)(媒體)類型委粉。

發(fā)送POST請求使用requests的post方法即可呜师,格式如下。

res = requests.post(url,data={}, json={}, files={})

data贾节、json汁汗、files都是可選參數(shù)(一般同時只用其中一個)。分別用來將數(shù)據(jù)按不同格式編碼發(fā)送栗涂。

  • data參數(shù)接受字典時將數(shù)據(jù)按普通表單(application/x-www-form-url-encoded)格式發(fā)送碰酝。
  • json參數(shù)存在時將字典格式的請求數(shù)據(jù)按JSON格式(application/json)發(fā)送
  • files參數(shù)將字典格式的請求數(shù)據(jù)(可以包含打開的文件)按混合表單(multipart/form-data)格式發(fā)送。

同時使用三者之一時戴差,會自動在請求頭中添加對應(yīng)的內(nèi)容類型聲明Content-Type:...送爸。

當data參數(shù)接受字符串格式的參數(shù)是按Raw原始格式發(fā)送,不進行編碼和添加請求頭暖释。當data參數(shù)接受文件對象時按binary二進制格式發(fā)送袭厂。

發(fā)送FORM表單格式數(shù)據(jù)

Form表單指網(wǎng)頁中包含輸入框、選擇框球匕、按鈕等組成的一組用戶填寫及選擇的數(shù)據(jù)纹磺。如登錄、注冊表單亮曹。表單是最常用的一種請求數(shù)據(jù)類型橄杨,對應(yīng)的請求頭媒體類型聲明:Content-Type:application/x-www-form-urlencoded秘症。

之所以稱為urlencoded,是因為式矫,請求體數(shù)據(jù)乡摹,實際會按url編碼格式發(fā)送,如name=臨淵采转,password=123456實際上會編碼為
name=%E4%B8%B4%E6%B8%8A&password=123456作為請求體數(shù)據(jù)聪廉,后臺傳輸。

表單類型的參數(shù)同樣是由多組鍵值對組成故慈,我們同樣適用字典格式構(gòu)造請求體數(shù)據(jù)并傳遞給請求方法的data參數(shù)即可板熊,示例如下。

import requests
url = 'https://httpbin.org/post'
data = {'name': '臨淵', 'password': '123456'}
res = requests.post(url, data=data)
print(res.text)

發(fā)送POST請求只要使用requests.post()方法即可察绷,方法中的data=data干签,第一個data是請求方法的一個固定的關(guān)鍵字參數(shù),后面的data是上面我自定義的變量拆撼,即{'name': '臨淵', 'password': '123456'}容劳,使用其他變量名可以。打印結(jié)果如下情萤。

{
  "args": {}, 
  "data": "", 
  "files": {}, 
  "form": {
    "name": "\u4e34\u6e0a", 
    "password": "123456"
  }, 
  "headers": {
    "Accept": "*/*", 
    "Accept-Encoding": "gzip, deflate", 
    "Content-Length": "39", 
    "Content-Type": "application/x-www-form-urlencoded", 
    "Host": "httpbin.org", 
    "User-Agent": "python-requests/2.18.4"
  }, 
  "json": null, 
  "origin": "111.194.126.253, 111.194.126.253", 
  "url": "https://httpbin.org/post"
}

發(fā)送時,請求頭中會自動添加"Content-Type": "application/x-www-form-urlencoded"摹恨。
對于JSON格式的響應(yīng)數(shù)據(jù)筋岛,我們可以使用res.json()轉(zhuǎn)為字典格式并通過字典取值提取響應(yīng)字段的變量進行斷言。假設(shè)我們要斷言響應(yīng)結(jié)果的url為"https://httpbin.org/post"晒哄,form不為空且name和password是我們傳的值睁宰,示例如下。

res_dict = res.json()
form = res_dict.get('form') 
assert "https://httpbin.org/post" == res_dict.get('url')
assert form and "臨淵" == form.get('name') and '123456' == form.get('password')

再次運行寝凌,結(jié)果和上次一致柒傻。沒有報錯即為assert斷言通過,斷言失敗時會報AssertionError较木。

發(fā)送JSON格式數(shù)據(jù)

JSON格式是一種通用的數(shù)據(jù)格式红符,在Python中JSON實際為“符合JSON語法格式的字符串”,本質(zhì)是str類型伐债。JSON格式和Python的字典一一對應(yīng)预侯,略有不同,如JSON中的true/false/null對應(yīng)字典中的True/False/None峰锁。我們同樣可以使用字典來構(gòu)造JSON請求的數(shù)據(jù)萎馅,然后傳遞夠請求方法的json參數(shù)即可,示例如下虹蒋。

import requests
url = 'https://httpbin.org/post'
json_data = {'name': '臨淵', 'age': 18, 'on_site': True, 'favorite': None}
res = requests.post(url, json=json_data)
print(res.text)

URL參數(shù)和FORM變動格式中的數(shù)字實際都是轉(zhuǎn)為字符串格式去發(fā)送的糜芳,而JSON中可以區(qū)分數(shù)字格式和字符串格式飒货。如{"age": 18}{"age":"18"}有可能是不一樣的。響應(yīng)文本打印結(jié)果如下峭竣。

{
  "args": {}, 
  "data": "{\"name\": \"\\u4e34\\u6e0a\", \"age\": 18, \"on_site\": true, \"favorite\": null}", 
  "files": {}, 
  "form": {}, 
  "headers": {
    "Accept": "*/*", 
    "Accept-Encoding": "gzip, deflate", 
    "Content-Length": "70", 
    "Content-Type": "application/json", 
    "Host": "httpbin.org", 
    "User-Agent": "python-requests/2.18.4"
  }, 
  "json": {
    "age": 18, 
    "favorite": null, 
    "name": "\u4e34\u6e0a", 
    "on_site": true
  }, 
  "origin": "111.194.126.253, 111.194.126.253", 
  "url": "https://httpbin.org/post"
}

發(fā)送時塘辅,請求頭中會自動添加"Content-Type": "application/json"
細心的同學(xué)會發(fā)現(xiàn)邪驮,F(xiàn)ORM表單格式發(fā)送的數(shù)據(jù)會出現(xiàn)在響應(yīng)的form字段中莫辨,JSON格式的卻出現(xiàn)在data字段中。這是因為JSON和XML等格式一樣屬于Raw(原始格式)毅访,即原樣發(fā)送沮榜。但是在實際發(fā)送時仍要確保請求數(shù)據(jù)都轉(zhuǎn)為ASCII(美國標準碼)來傳輸。因此中文參數(shù)“臨淵”在傳輸是會按utf-8編碼轉(zhuǎn)換為“\u4e34\u6e0a”喻粹。由于JSON格式中只能使用雙引號蟆融,響應(yīng)中data參數(shù)是一個JSON格式的字符串,需要使用轉(zhuǎn)義字符“\”守呜。

發(fā)送XML格式的數(shù)據(jù)

上例提到XML和JSON都屬于Raw格式的數(shù)據(jù)型酥,XML和JSON在Python中實際都是不同格式的文本字符串。我們將字符串傳遞給請求方法的data參數(shù)即可原樣發(fā)送查乒,即data參數(shù)有以下3重作用:

  1. data = {} 或 [(,), (,)]:接受一個字典或嵌套列表格式的數(shù)據(jù)弥喉,會按表單Url編碼格式
  2. data = '':接受一個字符串或bytes二進制字符串,會原樣發(fā)送(需要手動添加請求頭玛迄,如果存在中文需要手動編碼)
  3. data = open('...', 'rb'):接受一個文件對象由境,按binary格式流式上傳。

發(fā)送XML格式的數(shù)據(jù)只要將XML格式的多行字符串傳遞給請求方法的data參數(shù)即可蓖议,示例如下虏杰。

import requests
url = 'https://httpbin.org/post'
xml_data = '''
<xml>
    <name>臨淵</name>
    <age>12</name>
</xml>
'''
headers = {'Content-Type': 'application/xml'}

res = requests.post(url, data=xml_data.encode('utf-8'), headers=headers)
print(res.text)

由于xml_data數(shù)據(jù)中存在非ASCII碼,需要將數(shù)據(jù)按utf-8格式編碼為bytes二進制字符串發(fā)送勒虾。由于使用Raw格式發(fā)送數(shù)據(jù)時不會自動添加請求頭纺阔,因此一般要手動在請求頭中添加內(nèi)容類型聲明,并將構(gòu)造的字典類型的請求頭變量修然,傳遞給請求方法的關(guān)鍵字參數(shù)headers笛钝。響應(yīng)結(jié)果如下。

{
  "args": {}, 
  "data": "\n<xml>\n    <name>\u4e34\u6e0a</name>\n    <age>12</name>\n</xml>\n", 
  "files": {}, 
  "form": {}, 
  "headers": {
    "Accept": "*/*", 
    "Accept-Encoding": "gzip, deflate", 
    "Content-Length": "57", 
    "Content-Type": "application/xml", 
    "Host": "httpbin.org", 
    "User-Agent": "python-requests/2.18.4"
  }, 
  "json": null, 
  "origin": "111.194.126.253, 111.194.126.253", 
  "url": "https://httpbin.org/post"
}

Raw格式的數(shù)據(jù)都會記錄在該接口響應(yīng)數(shù)據(jù)的data字段中愕宋。

Raw格式的請求(Text婆翔、JavaScript、JSON掏婶、XML啃奴、HTML等)都可以按這種方式發(fā)送。JSON請求自然也可以按原始方式發(fā)送雄妥,示例如下最蕾。

import requests
url = 'https://httpbin.org/post'
json_data_str = '''
{
    "name": "臨淵", 
    "age": 18, 
    "on_site": true, 
    "favorite": null
}
'''
headers = {'Content-Type': 'application/json'}
res = requests.post(url, data=json_data_str.encode('utf-8'), headers=headers)
print(res.text)

注意以上的json_data_str須是符合JSON格式的字符串依溯,包括必須使用雙引號,應(yīng)該使用小寫的true瘟则,無值應(yīng)該是null黎炉,由于字符串中存在中文,同樣要手動進行encode編碼醋拧,同時要手動添加請求頭指定內(nèi)容類型慷嗜。

為方便構(gòu)造請求數(shù)據(jù),也可以先構(gòu)造一個字典格式的請求數(shù)據(jù)丹壕,再使用json.dumps()庆械,將字典格式的數(shù)據(jù)轉(zhuǎn)為JSON字符串發(fā)送,示例如下菌赖。

import requests
import json

url = 'https://httpbin.org/post'
json_data = {
    'name': '臨淵', 
    'age': 18, 
    'on_site': True, 
    'favorite': None
}
headers = {'Content-Type': 'application/json'}
res = requests.post(url, data=json.dumps(json_data), headers=headers)
print(res.text)

注意以上json_data是字典格式的變量缭乘,因此要使用TrueNone。在將字典轉(zhuǎn)為JSON字符串時琉用,需要首先導(dǎo)入json庫堕绩。json.dumps()將字典格式的json_data轉(zhuǎn)換為JSON字符串,并通過默認的ensure_ascii=True參數(shù)將中文轉(zhuǎn)換為\u形式的ASCII字符(如“臨淵”會轉(zhuǎn)換為“\u4e34\u6e0a”)邑时,因此不再需要進行編碼后發(fā)送奴紧。

發(fā)送Multipart/form-data請求(文件上傳)

網(wǎng)頁上的表單有兩種,一種是不包含文件上傳晶丘,所有用戶輸入或選擇的數(shù)據(jù)都可以使用字符串格式表示黍氮,這種稱為普通表單或純文本表單,對應(yīng)MIME類型為application/x-www-form-urlencoded铣口。

另一種即包括普通輸入框等滤钱,也包含一個或多個文件上傳框觉壶。普通輸入框中的變量值可以已字符串格式編碼脑题,而上傳的文件(如圖片文件)則不一定能直接轉(zhuǎn)為字符串,要使用二進制格式铜靶。因此要使用多部分的混合格式叔遂,筆者稱之為混合表單,對應(yīng)MIME類型為multipart/form-data争剿。在表單中已艰,每個需要上傳的文件和普通輸入框一樣對應(yīng)一個指定的變量。因此同樣可以使用字典格式組裝混合表單的請求數(shù)據(jù)傳遞給請求方法的files參數(shù)即可蚕苇,示例如下哩掺。

import requests
url = 'https://httpbin.org/post'
multi_form_data = {
    'name': '臨淵',
    'age': '18',  # 不能使用int類型
    'avatar': open('/Users/apple/Pictures/robot.png', 'rb'),
    'avatar2': open('/Users/apple/Pictures/robot.jpg', 'rb'),
}

res = requests.post(url, files=multi_form_data)
print(res.text)

表單數(shù)據(jù)中的數(shù)字要使用字符串格式的數(shù)字,文件要以rb二進制格式打開傳輸涩笤,支持多個變量以及多個文件嚼吞。

文件類型的數(shù)據(jù)avatar可以只穿一個打開的文件對象open('/Users/apple/Pictures/robot.png', 'rb')盒件,也可以傳遞三個參數(shù):要保存的文件名,打開的文件及文件MIME類型舱禽,即

'avatar': ('robot.png', open('/Users/apple/Pictures/robot.png', 'rb'), 'image/png'),

比如有些接口上傳Excel文件時必須聲明文件名和MIME類型炒刁,如:

res = request.post(url, files={'upload_file': 
        ('data.xlsx', 
        open('data.xlsx', 'rb'),
        'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
    })

MIME類型參考:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Basics_of_HTTP/MIME_types

發(fā)送Binary格式數(shù)據(jù)(單文件/流式上傳)

import requests
url = 'https://httpbin.org/post'

res = requests.post(url, data=open('/Users/apple/Pictures/robot.jpg', 'rb'))
print(res.text)

JSON與字典的相互轉(zhuǎn)換

JSON(JavaScript Object Notation),即JavaScript對象標記誊稚。 是一種通用的輕量級的數(shù)據(jù)交換格式翔始。在Python中,JSON本質(zhì)上是符合JSON格式的字符串(str類型)里伯,即JSON字符串城瞎。

JSON字符串中支持Object對象、Array數(shù)組俏脊、String字符串全谤、Number數(shù)字、true/false布爾值爷贫、null空值6中數(shù)據(jù)類型认然,并支持層次嵌套。Python中的字典和JSON字符串中描述的數(shù)據(jù)類型一一對應(yīng)漫萄,對應(yīng)關(guān)系如下表所示卷员。

JSON字符串 Python
Object {...} 字典 {...}
Array [...] 列表 [...]
String "..." 字符串 '...' 或 "..."
Number 1.5或3 浮點型或整型 1.5或3
true或false True或False
null None

注意,JSON格式較為嚴格腾务,和Python字典格式略有不同:

  • 字典中的引號支持單引號和雙引號毕骡,JSON格式只支持雙引號
  • 字典中的True/False首字母大寫,JSON格式為true/false
  • 字典中的空值為None, JSON格式為null
  • 字典中可以使用#好注釋岩瘦,JSON中不允許使用任何形式的注釋
  • 字典列表最后一項后可以有逗號未巫,JSON數(shù)組最后一項后不可以有逗號

作為一種標準格式的字符串,JSON方便在不同系統(tǒng)中進行數(shù)據(jù)交換启昧,方便進進行傳輸和存儲叙凡,卻不方便從整段字符串中提取響應(yīng)的字段對應(yīng)的值。

而字典作為內(nèi)存中的一種數(shù)據(jù)結(jié)構(gòu)密末,可以很方便的對其中的數(shù)據(jù)進行提取或添加等操作握爷。因此我們常常需要在JSON字符串和字典之間相互轉(zhuǎn)換。

在接口請求中常用的轉(zhuǎn)換如下严里。

  • (1)使用字典格式構(gòu)造請求數(shù)據(jù)
  • (2)轉(zhuǎn)為JSON字符串發(fā)送請求
  • (3)服務(wù)端解析處理
  • (4)返回JSON字符串格式的響應(yīng)數(shù)據(jù)
  • (5)轉(zhuǎn)為字典格式提取相應(yīng)的字段并斷言

Python自帶的json庫提供JSON字符或JSON文件對象和字典之間的相互轉(zhuǎn)換新啼,主要方法如下:

  • json.loads(JSON字符串)/json.load(JSON文件對象):JSON字符串/文件轉(zhuǎn)字典
  • json.dumps(字典)、json.dump(字典刹碾,文件對象):字典轉(zhuǎn)JSON字符串/文件

使用示例如下燥撞。

import json
data = {
    'name': '臨淵', 
    'age': 18, 
    'on_site': True, 
    'favorite': None
}
# dict -->  JSON
data_str = json.dumps(data)
print('字典轉(zhuǎn)JSON字符串', type(data_str), data_str)
# JSON --> dict
data_dict = json.loads(data_str)
print('JSON字符串轉(zhuǎn)回字典', data_dict)
# dict --> JSON文件
with open('data.json', 'w', encoding='utf-8') as f:
    json.dump(data, f)

# JSON文件 --> dict
with open('data.json', 'r', encoding='utf-8') as f:
    data_dict = json.load(f)
print('JSON文件轉(zhuǎn)回字典', data_dict)

運行結(jié)果如下:

字典轉(zhuǎn)JSON字符串 <class 'str'> {"name": "\u4e34\u6e0a", "age": 18, "on_site": true, "favorite": null}
JSON字符串轉(zhuǎn)回字典 {'name': '臨淵', 'age': 18, 'on_site': True, 'favorite': None}
JSON文件轉(zhuǎn)回字典 {'name': '臨淵', 'age': 18, 'on_site': True, 'favorite': None}

生成的data.json文件內(nèi)容如下:

{"name": "\u4e34\u6e0a", "age": 18, "on_site": true, "favorite": null}

在使用json.dumps()將字典轉(zhuǎn)為JSON字符串時,默認為確保ASCII碼已方便HTTP傳輸會將中文進行轉(zhuǎn)換,同時默認使用單行格式物舒。如果想要更清晰的查看JSON字符串結(jié)果辆布,可以使用ensure_ascii=False不進行轉(zhuǎn)換,使用indent=2空2格縮進顯示茶鉴,sort_keys=True按key排序輸出锋玲,示例如下。

import json

data = {
    'name': '臨淵', 
    'age': 18, 
    'on_site': True, 
    'favorite': None
}
data_str = json.dumps(data, ensure_ascii=False, indent=2, sort_keys=True)
print(data_str)

輸出格式如下:

{
  "age": 18,
  "favorite": null,
  "name": "臨淵",
  "on_site": true
}

通用的請求方法

PUT/DELETE等請求方法使用requests對應(yīng)的方法即可涵叮。

  • requests.get(url, **kwargs):發(fā)送GET請求
  • requests.post(url, **kwargs):發(fā)送POST請求
  • requests.put(url, **kwargs):發(fā)送PUT請求
  • requests.delete(url, **kwargs):發(fā)送DELETE請求
  • requests.head(url, **kwargs):發(fā)送head請求
  • erquests.options(url, **kwargs):發(fā)送options請求

這些請求方法的參數(shù)和用法一致惭蹂,必選參數(shù)為url,其他參數(shù)為可選參數(shù)割粮,常用參數(shù)如下盾碗。

  • url: 字符串格式,參數(shù)也可以直接寫到url中
  • params:url參數(shù)舀瓢,字典格式
  • data: 請求數(shù)據(jù)廷雅,字典或字符串格式
  • headers: 請求頭,字典格式
  • cookies: 字典格式京髓,可以通過攜帶cookies繞過登錄
  • files: 字典格式航缀,用于混合表單(form-data)中上傳文件
  • auth: Basic Auth授權(quán),數(shù)組格式 auth=(user,password)
  • timeout: 超時時間(防止請求一直沒有響應(yīng)堰怨,最長等待時間)芥玉,數(shù)字格式,單位為秒

這些方法都源于一個通用的請求方法requests.request(method, url, **kwargs)备图。這個通用的方法通過必選參數(shù)method來指定使用的請求動作灿巧。字符串格式,不區(qū)分大小寫揽涮,即requests.get(url)相當于requests.request('get', url)抠藕。

因此我們可以用同樣結(jié)構(gòu)的的數(shù)據(jù)來組裝任何的HTTP請求,示例如下蒋困。

import requests
res = request.request(
    method='post',   # 也可以只寫'post',
    url='https://httpbin.org/post',  # 也可以只寫'https://httpbin.org/post',
    headers={}, 
    data={'name': '臨淵', 'password': '123456'}
)
print(res.text)

請求中也可以根據(jù)需求添加其他參數(shù)盾似,這一組組鍵值對參數(shù)可以使用一個統(tǒng)一的字典來表示,即:

req = {
    'method': 'post',
    'url': 'https://httpbin.org/post', 
    'headers: {}, 
    'data': {'name': '臨淵', 'password': '123456'}
    }

然后通過**req字典解包家破,可以將一個字典參數(shù)req重新還原為其中的4組參數(shù)颜说,因此上例子可以改為购岗。

import requests
req = {
    'method': 'post',
    'url': 'https://httpbin.org/post', 
    'headers: {}, 
    'data': {'name': '臨淵', 'password': '123456'}
    }
res = request.request(**req)
print(res.text)

這樣做的好處是可以將任何類型的HTTP請求數(shù)據(jù)配置到數(shù)據(jù)文件中(如JSON或Yaml文件)汰聋,然后將數(shù)據(jù)轉(zhuǎn)為字典直接發(fā)送。示例如下喊积。
data.json文件內(nèi)容:

[
    {
        "method": "get",
        "url": "https://httpbin.org/get"
    },
    {
        "method": "post",
        "url": "https://httpbin.org/post", 
        "headers": {}, 
        "data": {"name": "臨淵", "password": "123456"}
    }
]

發(fā)送請求腳本如下:

import requests
import json
with open('data.json', encoding='utf-8') as f:
    datas = json.load(f)  # 將JSON文件轉(zhuǎn)為字典

for req in datas:
    res = requests.request(**req)
    print(res.text)

SSL證書驗證

requests在請求HTTPS接口時烹困,默認驗證SSL證書躲胳,請求方法中默認參數(shù)為verify=True蔫巩,如果想要關(guān)閉證書驗證叽讳,可以設(shè)置為False壳繁,示例如下。

requests.get('https://www.baidu.com', verify=False)

不自動重定向

當遇到重定向接口枯饿,requests默認跟隨重定向酝锅,返回所重定向接口的響應(yīng)對象(<Response [200]>),對于一些單點登錄后轉(zhuǎn)向的接口奢方,有時我們需要獲取原接口響應(yīng)中的token信息搔扁,則需要使用allow_redirects=False關(guān)閉自動重定向,使用方法如下蟋字。

import requests
res = requests.get('https://httpbin.org/status/302')
print(res) 
res = requests.get('https://httpbin.org/status/302', allow_redirects=False)
print(res)

第一個自動跟隨重定向稿蹲,返回<Response [200]>,關(guān)閉重定向后返回<Response [302]>鹊奖。

代理設(shè)置

requests支持使用代理苛聘,對于HTTP和HTTPS分別使用不同的代理,使用方式如下忠聚。

import requests
proxies = {
  "http": "http://10.10.1.10:3128",
  "https": "http://10.10.1.10:1080",
}
requests.get("http://example.org", proxies=proxies)

超時設(shè)置

requests支持對請求設(shè)置超時時間设哗,以防止請求長時間無響應(yīng)而阻塞,設(shè)置方法如下两蟀。

import requests
requests.get('https://github.com', timeout=5)  # 設(shè)置整體的超時時間5s
requests.get('https://github.com', timeout=(3, 2))  # 分別設(shè)置連接和下載響應(yīng)內(nèi)容的超時時間3s,2s熬拒。

如果在超時時間內(nèi)未完成響應(yīng),則拋出TimeoutError

授權(quán)設(shè)置(身份認證)

授權(quán)是請求身份驗證的一些開放協(xié)議標準垫竞,授權(quán)協(xié)議很多澎粟,包括Basic Auth基礎(chǔ)授權(quán),Digist Auth摘要授權(quán)欢瞪,Oauth等活烙。

Basic Auth

Basic Auth基礎(chǔ)授權(quán)使用用戶名和密碼來驗證身份,在requests中使用方法如下遣鼓。

import requests
requests.get('https://api.github.com/user', auth=('githab賬號', '密碼'))

OAuth2.0

需要使用requests-oauthlib啸盏,參考鏈接:https://requests-oauthlib.readthedocs.io/en/latest/oauth2_workflow.html

會話保持及默認配置

會話Session一般指客戶端和服務(wù)端的一次連接交互過程。在使用requests.get()等方法時骑祟,每次會建立一個新的會話與服務(wù)器進行連接回懦。這樣不便于保持會話(如登錄)狀態(tài),如果想要保持會話狀態(tài)次企,可以使用同一個會話對象來請求所有接口怯晕,示例如下。

import requests
s = requests.Session()  # 新建一個會話對象
s.get('http://httpbin.org/cookies/set/sessioncookie/123456789')  # 使用該會話對象請求
r = s.get("http://httpbin.org/cookies")  # 使用同樣的會話對象請求
print(r.text)

會話對象還可以用來設(shè)置默認的請求頭等HTTP配置缸棵,示例如下舟茶。

s = requests.Session()
s.auth = ('user', 'pass')  # 在會話中設(shè)置默認授權(quán)
s.headers.update({'x-test': 'true'})  # 在會話中設(shè)置默認請求頭
s.get('http://httpbin.org/headers', headers={'x-test2': 'true'}) # 默認請求頭也會被發(fā)送

預(yù)制請求Preprared-request

假設(shè)有多個請求需要先準備好,再逐個發(fā)送,可以使用requests.Request()對象的prepare()方法生成預(yù)制請求對象吧凉,然后使用會話發(fā)送即可隧出,示例如下。

import requests
s = request.Session()
req1 = requests.Request('GET', 'https://httpbin.org/get').prepare()
req2 = requests.Request('POST', 'https://httpbin.org/post', data={'a':1}).prepare()
s.send(req1)  # 發(fā)送預(yù)制請求
s.send(req2, headers={'x-test': 'true'})  # 支持添加額外項

使用適配器

適配器用于對匹配到的指定形式的請求做特殊處理阀捅,可以直接使用requests.adapters中的HTTPAdapter給定響應(yīng)參數(shù)胀瞪,也可以繼承HTTPAdapter或BaseAdapter自定義處理方式,示例如下饲鄙。

import requests
s = requests.Session()
a = requests.adapters.HTTPAdapter(max_retries=3)  # 設(shè)置最大重試3次
s.mount('http://', a)  # 對該會話所有http://開頭的請求使用

詳細可參考API:HTTPAdapterBaseAdapter

并發(fā)請求

requests本身并不支持異步赏廓。想要并發(fā)請求常用的有多線程多進程或gevent方式。

多線程
直接使用threading的Thread對象即可傍妒,通過target指定要運行的方法幔摸,示例如下。

import requests
from threading import Thread

def print_res(res, *args, **kwargs):
    print(res.text)

s = requests.Session()
s.hooks={'response': print_res}

t1 = Thread(target=s.get, args=('https://httpbin.org/get',)) # 指定線程運行方法
t2 = Thread(target=s.post, args=('https://httpbin.org/post',), kwargs={'data': {'a': 1}})
t1.start() # 啟動線程
t2.start()
t1.join()  # 連接主線程
t2.join()  

默認線程運行無法獲取target函數(shù)的運行結(jié)果颤练,這里給會話添加了默認hooks方法既忆,來打印響應(yīng)文本(也可以通過自定義請求方法來實現(xiàn))。

如果想獲取線程結(jié)果嗦玖,需要繼承Thread并編寫自己的線程處理類患雇,示例如下。

import requests
from threading import Thread

class MyThread(Thread):
    def __init__(self, func, *args, **kwargs):  # 改變線程的使用方式宇挫,可以直接傳遞函數(shù)方法和函數(shù)參數(shù)
        super(MyThread, self).__init__()
        self.func = func
        self.args = args
        self.kwargs = kwargs
        self.result = None

    def run(self):
        self.result = self.func(*self.args, **self.kwargs)  # 為線程添加屬性result存儲運行結(jié)果

t1 = MyThread(requests.get, 'https://httpbin.org/get') 
t2 = MyThread(requests.post, 'https://httpbin.org/post', data={'a':1})
t1.start()
t2.start()
t1.join()
t2.join()
print(t1.result)  # 響應(yīng)對象
print(t2.result.text)  # 響應(yīng)對象的text屬性即響應(yīng)文本

使用gevent

pip install gevent

示例如下苛吱。

from gevent import monkey;monkey.patch_all()  # 要放import requests上面
import requests
import gevent

g1 = gevent.spawn(requests.get, 'https://httpbin.org/get')
g2 = gevent.spawn(requests.post, 'https://httpbin.org/post', data={'a': 1})

gevent.joinall([g1, g2])

print(g1.value)  # 響應(yīng)對象
print(g2.value)

使用grequests

pip install grequests

grequests封裝了gevent和requests方法,用起來更簡單器瘪,示例如下翠储。

import grequests

req_list = [
  grequests.get('https://httpbin.org/get', ),  
  grequests.post('https://httpbin.org/post', data={'a': 1})
]
res_list = grequests.map(req_list)
print(res_list)

響應(yīng)處理

res是請求返回的響應(yīng)對象(變量名隨意)。res.text會自動將二進制格式的響應(yīng)數(shù)據(jù)橡疼,使用默認編碼轉(zhuǎn)為文本(字符串)格式援所。

res響應(yīng)對象包含各種響應(yīng)的信息,常用的如下欣除。

  • res.content:二進制響應(yīng)數(shù)據(jù)
  • res.text:將二進制響應(yīng)數(shù)據(jù)按默認編碼轉(zhuǎn)為文本(字符串格式)
  • res.json():將JSON格式響應(yīng)文本(res.text)按轉(zhuǎn)為字典(W∈谩!历帚!非JSON格式響應(yīng)文本滔岳,使用此方法會報JSONDecoderError)
  • res.status_code:狀態(tài)碼
  • res.reason:狀態(tài)碼說明
  • res.headers:響應(yīng)頭
  • res.cookies:響應(yīng)Cookies(響應(yīng)Cookies中有時候不能包含所有響應(yīng)頭的Set-Cookies內(nèi)容,可以通過解析響應(yīng)頭獲韧炖巍)
  • res.encoding:當前解碼格式谱煤,可以通過修改req.encoding來解決一部分亂碼問題
  • res.apparent_encoding:明顯編碼,使用chardet庫對響應(yīng)數(shù)據(jù)分析出的編碼格式

亂碼處理

res.encoding解碼格式和res.apparent_encoding明顯編碼格式不一致時卓研,便可能出現(xiàn)亂碼趴俘,如請求百度首頁,打印res.text會發(fā)現(xiàn)有亂碼奏赘,重新設(shè)置res.encoding為明顯編碼的格式寥闪,再次打印res.text便可以修復(fù)亂碼。示例如下磨淌。

import requests
res = requests.get('https://www.baidu.com/')
print(res.text)  # 有亂碼
print('解碼格式', res.encoding)  # 解碼格式 ISO-8859-1
print('明顯編碼', res.apparent_encoding)  # 明顯編碼 utf-8

res.encoding = res.apparent_encoding # 修改解碼格式
print(res.text)  # 亂碼解決

文件下載(流式下載)

對應(yīng)資源類接口(如圖片鏈接)疲憋,想要保持文件,可以直接使用res.content按二進制保存文件即可梁只,示例如下缚柳。

import requests
res = requests.get('https://upload.jianshu.io/users/upload_avatars/7575721/5339c9d6-be6b-47cf-87cc-c0517467c6bc.jpg?imageMogr2/auto-orient/strip|imageView2/1/w/240/h/240')

with open('avatar.png', 'wb') as f:
    f.write(res.content)

對應(yīng)較大的文件,可是使用流式下載搪锣,示例如下秋忙。

import requests
res = requests.get('https://upload.jianshu.io/users/upload_avatars/7575721/5339c9d6-be6b-47cf-87cc-c0517467c6bc.jpg?imageMogr2/auto-orient/strip|imageView2/1/w/240/h/240')

with open('avatar.png', 'wb') as f:
    for data in res.iter_content(128):  # 按128字節(jié)分塊保存
        f.write(data)
with open('avatar.png', 'wb') as f:
    for data in res.iter_content(128):  # 按128字節(jié)分塊保存
        f.write(data)

Hooks使用

Hooks即鉤子方法,用于在某個框架固定的某個流程執(zhí)行是捎帶執(zhí)行(鉤上)某個自定義的方法构舟。
requests庫只支持一個response的鉤子灰追,即在響應(yīng)返回時可以捎帶執(zhí)行我們自定義的某些方法」烦可以用于打印一些信息弹澎,做一些響應(yīng)檢查或想響應(yīng)對象中添加額外的信息,示例如下努咐。

import requests
url = 'https://httpbin.org/post'

def verify_res(res, *args, **kwargs):
    print('url', res.url)
    res.status='PASS' if res.status_code == 200 else 'FAIL'

res = requests.get(url, data=data, hooks={'response': verify_res})
print(res.text)
print(res.status)

執(zhí)行結(jié)果如下苦蒿。

https://httpbin.org/post
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<title>405 Method Not Allowed</title>
<h1>Method Not Allowed</h1>
<p>The method is not allowed for the requested URL.</p>

FAIL

verfiy_res是我們自定義的方法,第一個參數(shù)為響應(yīng)對象渗稍,后面kwargs里是請求的一些配置佩迟。鉤子方法不能返回響應(yīng)對象以外的有意義值,否則會破壞后面對響應(yīng)對象的處理竿屹。

由于該接口只支持post請求音五,使用get請求時響應(yīng)狀態(tài)碼為405(請求方法不被允許),因此響應(yīng)對象被添加的status的值為FAIL羔沙。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末躺涝,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子扼雏,更是在濱河造成了極大的恐慌坚嗜,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件诗充,死亡現(xiàn)場離奇詭異苍蔬,居然都是意外死亡,警方通過查閱死者的電腦和手機蝴蜓,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進店門碟绑,熙熙樓的掌柜王于貴愁眉苦臉地迎上來俺猿,“玉大人格仲,你說我怎么就攤上這事押袍。” “怎么了宽闲?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵稿湿,是天一觀的道長。 經(jīng)常有香客問我栖疑,道長讨永,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任蔽挠,我火速辦了婚禮住闯,結(jié)果婚禮上瓜浸,老公的妹妹穿的比我還像新娘澳淑。我一直安慰自己,他們只是感情好插佛,可當我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布杠巡。 她就那樣靜靜地躺著,像睡著了一般雇寇。 火紅的嫁衣襯著肌膚如雪氢拥。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天锨侯,我揣著相機與錄音嫩海,去河邊找鬼。 笑死囚痴,一個胖子當著我的面吹牛叁怪,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播深滚,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼奕谭,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了痴荐?” 一聲冷哼從身側(cè)響起血柳,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎生兆,沒想到半個月后难捌,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡鸦难,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年栖榨,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片明刷。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡婴栽,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出辈末,到底是詐尸還是另有隱情愚争,我是刑警寧澤映皆,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站轰枝,受9級特大地震影響捅彻,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜鞍陨,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一步淹、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧诚撵,春花似錦缭裆、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至筛武,卻和暖如春缝其,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背徘六。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工内边, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人待锈。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓漠其,卻偏偏與公主長得像,于是被迫代替她去往敵國和親炉擅。 傳聞我的和親對象是個殘疾皇子辉懒,可洞房花燭夜當晚...
    茶點故事閱讀 42,786評論 2 345

推薦閱讀更多精彩內(nèi)容

  • 上一篇:8.Urllib庫基本使用下一篇:10.正則表達式基礎(chǔ) requests是python實現(xiàn)的最簡單易用的H...
    在努力中閱讀 3,328評論 2 11
  • 簡書已停更,歡迎轉(zhuǎn)到個人博客查看對應(yīng)教程:https://www.cnblogs.com/superhin/p/1...
    韓志超閱讀 25,869評論 4 54
  • 今天開始谍失,希望是一個新的起點
    有約_f02b閱讀 237評論 0 1
  • 周末結(jié)束明天開始新的一周眶俩,今天給孩子購置了一款新的學(xué)習(xí)軟件,跟課本同步孩子預(yù)習(xí)正好用上快鱼! 同事去學(xué)習(xí)帶來的學(xué)習(xí)軟件...
    大牛拉小車閱讀 251評論 0 0
  • 一個好的平臺可以給你帶去一些你原本未知的東西颠印,“創(chuàng)客”一詞我就是從“一席”這里獲知的,從此對這方面的信息有了更多的...
    殘劍閱讀 509評論 0 2