致力于打造最詳細的Requests使用(不定期補充)

Python 2.7
IDE Pycharm 5.0.3
Requests 2.10


是時候靜心下來好好研究一下Requests了

安裝方法

我這里只說在Pycharm+Anaconda2下怎么添加requests包,至于如何在Pycharm下安裝Anaconda2,請看@zhusleep 和@木子嵐的回答
然后安裝大概是這樣的,簡單快捷,不用pip,不用easy install,anaconda2就是那么強大,吼吼吼

這里寫圖片描述


使用案例

獲取Github的公共時間線,網址是https://github.com/timeline.json
如果你打開這個鏈接,那么應該是這樣的

這里寫圖片描述

ok,在沒有遇到Requests之前我們是怎么處理的呢
當然是用urllib2,urllib啦

import urllib2
url='https://github.com/timeline.json'
req=urllib2.Request(url)
response = urllib2.urlopen(req)
html = response.read()
print html

報錯了


這里寫圖片描述

難道是代碼問題?
再試

import urllib2
url='http://www.bing.com'
req=urllib2.Request(url)
response = urllib2.urlopen(req)
html = response.read()
print html

一切正常,能抓到內容,這是為什么?


這里寫圖片描述

難道網頁是動態的?那我換selenium來抓

from selenium import webdriver
url='https://github.com/timeline.json'#Github時間線
#driver = webdriver.Firefox()
driver = webdriver.PhantomJS(executable_path='phantomjs.exe')
driver.get(url)
pre = driver.find_element_by_xpath('//body/pre')
print pre.text

成功抓取,所以說,到底是什么問題呢,是不是動態網頁搞得鬼呢。。。下次知道了我再補充。

補充一

首先對410 gone做個介紹

410 gone 過時
請求資源在源服務器上不再可得并且也沒有轉發地址可用。此條件被認為是永久的。具有鏈接編輯能力的客戶端應該在用戶確認后刪除請求URI的引用。如果服務器不知道或不容易去確定條件是否是永久的,那么此404(沒有發現)狀態響應將被代替利用。響應是可緩存的,除非另外申明。410響應主要的目的是為了web維護任務,這通過告訴接收者資源已經不可得了并且告訴接收者服務器擁有者已經把那個資源的遠程連接給移除了。對有時間限制的,推銷性的服務,和對不再繼續工作在服務器站點人員的資源,這個事件(410響應)是非常普遍的。它不需要把所有長久不可得的資源標記為“gone”或者保持任意長時間—這需要服務器擁有者自己的判斷

url = 'https://github.com/timeline.json'網頁,其實urllib2并沒有處理出錯,狀態410,之后我用requests來測試狀態也是如此

import requests,os,time
url = 'https://github.com/timeline.json'
start = time.clock()
html = requests.get(url,allow_redirects=True)
end = time.clock()
print html.status_code
print html.text

結果

410
{"message":"Hello there, wayfaring stranger. If you’re reading this then you probably didn’t 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"}

但對于requests能抓到東西urllib2表示不服,但是我仍然不清楚requests為什么能抓到東西而且這個網址的確能在瀏覽器打開,github真是個神奇的地方,下次知道了再進行補充


靜態網頁和動態網頁補充

傳統爬蟲利用的是靜態下載方式,靜態下載的優勢是下載過程快,但是頁面只是一個枯燥的html,因此頁面鏈接分析中獲取的只是< a >標簽的href屬性或者高手可以自己分析js,form之類的標簽捕獲一些鏈接。在python中可以利用urllib2模塊或requests模塊實現功能。 動態爬蟲在web2.0時代則有特殊的優勢,由于網頁會使用javascript處理,網頁內容通過Ajax異步獲取。所以,動態爬蟲需要分析經過javascript處理和ajax獲取內容后的頁面。目前簡單的解決方法是通過基于webkit的模塊直接處理。PYQT4、Splinter和Selenium這三個模塊都可以達到目的。對于爬蟲而言,瀏覽器界面是不需要的,因此使用一個headless browser是非常劃算的,HtmlUnit和phantomjs都是可以使用的headless browser。


正題時間

采用requests抓取

import requests
url='https://github.com/timeline.json'
html=requests.get(url)
print html.text

成功抓取如下

{"message":"Hello there, wayfaring stranger. If you’re reading this then you probably didn’t 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"}

Requests會自動解碼來自服務器的內容。大多數unicode字符集都能被無縫地解碼。請求發出后,Requests會基于HTTP頭部對響應的編碼作出有根據的推測。當你訪問r.text 之時,Requests會使用其推測的文本編碼。

感覺requests非常的簡便和易讀,感覺和selenium差不多,直接來個get(url)就完事了,之后抓到的直接用.text打印。


二進制響應(對于非文本)

若是對文本進行操作,返回的還是str類型,和上述的并沒有什么卵區別。

import requests
url='https://github.com/timeline.json'
html_content = requests.get(url).content
print type(html_content)
print html_content
<type 'str'>
{"message":"Hello there, wayfaring stranger. If you’re reading this then you probably didn’t 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"}

如果是對圖像進行操作請看
我們導入PIL模塊的Image,還有StringIO來讀,試試,測試網站是一個貓奴網站網址http://placekitten.com/500/700,網頁打開后應該是這樣的。

StringIO介紹(亂入)
因為文件對象和StringIO大部分的方法都是一樣的,比如read, readline, readlines, write, writelines都是有的,這樣,StringIO就可以非常方便的作為"內存文件對象"。

這里寫圖片描述

首先我們用傳統的urllib2進行抓取試試,

import urllib2
from PIL import Image
from StringIO import StringIO
url = 'http://placekitten.com/500/700'
req = urllib2.Request(url)
response = urllib2.urlopen(req)
html = response.read()
print type(html)
print html
i = Image.open(StringIO(html))
i.show()
<type 'str'>
???? ?JFIF ??  ? ?  ?? ;CREATOR: gd-jpeg v1.0 (using IJG JPEG v62), quality = 65
?? C ......省略n亂碼

使用的效果如圖

這里寫圖片描述

然后我們使用requests,content來抓取。

from PIL import Image
from StringIO import StringIO
import requests
url = 'http://placekitten.com/500/700'
html_content = requests.get(url).content#<type 'str'>
html_text = requests.get(url).text#<type 'unicode'>
print type(html_content)
print html_content
print type(html_text)
print html_text
i = Image.open(StringIO(html_content))
i.show()
<type 'str'>
???? ?JFIF ??  ? ?  ?? ;CREATOR: gd-jpeg v1.0 (using IJG JPEG v62), quality = 65
?? C ......省略n亂碼
<type 'unicode'>
???? ?JFIF ??  ? ?  ?? ;CREATOR: gd-jpeg v1.0 (using IJG JPEG v62), quality = 65
?? C ......省略n亂碼

效果和上述的一樣,可以成功運行,但是,如果將str流換成這樣

i = Image.open(StringIO((html_text)))

顯然會報錯,可以參考@青南的小世界 --requests的content與text導致lxml的解析問題

UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-3: ordinal not in range(128)

req.text返回的是Unicode型的數據,使用req.content返回的是bytes型的數據。也就是說,在使用req.content的時候,已經自帶了將源代碼轉化成比特數組,然后再將比特數組轉化成一個比特對象。


響應json內容

Requests中也有一個內置的JSON解碼器,助你處理JSON數據

import requests
url='https://github.com/timeline.json'
html_json = requests.get(url).json()
print type(html_json)
print html_json

返回的是一個dict類型

<type 'dict'>
{
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.'}

不了解json的可以看下大概是個啥

JSON(JavaScript Object Notation) 是一種輕量級的數據交換格式。它基于ECMAScript的一個子集。 JSON采用完全獨立于語言的文本格式,但是也使用了類似于C語言家族的習慣(包括C、C++、C#、Java、JavaScript、Perl、Python等)。這些特性使JSON成為理想的數據交換語言。 易于人閱讀和編寫,同時也易于機器解析和生成(一般用于提升網絡傳輸速率)。

這里寫圖片描述

OK,這里和Python中的字典并沒有什么實質性區別,就當做輕量級字典結構來處理吧

查看所有鍵、值、(鍵,值)對:dict.keys()、dict.values()、dict.items();返回值的類型為列表

import requests
url='https://github.com/timeline.json'
html_json = requests.get(url).json()
print type(html_json)
print html_json.keys()
for key in html_json:#遍歷字典,默認為鍵
    print key
for values in html_json.values():
    print values
<type 'dict'>
#--------------------------------#
[u'documentation_url', u'message']
#--------------------------------#
documentation_url
message
#--------------------------------#
https://developer.github.com/v3/activity/events/#list-public-events
Hello there, wayfaring stranger. If you’re reading this then you probably didn’t 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.

好吧,又跑題了。。。。


定制請求頭

如果你想為請求添加HTTP頭部,只要簡單地傳遞一個 dict 給 headers 參數就可以了。

這里需要導入json,凡是和字典有關的,應該想到json,不然我上面寫那么多json干啥。。。

import requests,json
url = 'https://api.github.com/some/endpoint'
payload = {'some': 'data'}
headers = {'content-type': 'application/json'}
html_json = requests.post(url,data=json.dumps(payload),headers=headers)
print html_json
print html_json.text
<Response [404]>
{"message":"Not Found","documentation_url":"https://developer.github.com/v3"}

so,WTF,為什么模擬實驗不成功呢@逆向行駛--Python Requests-學習筆記(4)-定制請求頭和POST ,404錯誤,指定的網頁不存在啊喂,換了個網址,這個http://httpbin.org/post

import requests,json
url = 'http://httpbin.org/post'
payload = {'some': 'data'}
headers = {'content-type': 'application/json'}
html_json = requests.post(url,data=json.dumps(payload),headers=headers)
print html_json
print html_json.text
<Response [200]>
{
  "args": {}, 
  "data": "{\"some\": \"data\"}", 
  "files": {}, 
  "form": {}, 
  "headers": {
    "Accept": "*/*", 
    "Accept-Encoding": "gzip, deflate", 
    "Content-Length": "16", 
    #增加了Content-Type
    "Content-Type": "application/json", 
    "Host": "httpbin.org", 
    "User-Agent": "python-requests/2.10.0"
  }, 
  #增加了json
  "json": {
    "some": "data"
  }, 
  
  "origin": "221.212.116.44", 
  "url": "http://httpbin.org/post"
}

增加Form

form 標簽:用于創建 HTML 表單。

import requests,json
url = 'http://httpbin.org/post'
payload = {'key1': 'values1','key2': 'values2'}
html_json = requests.post(url,data=payload)
print html_json
print html_json.text

結果就是

<Response [200]>
{
  "args": {}, 
  "data": "", 
  "files": {}, 
  #增加了表單
  "form": {
    "key1": "values1", 
    "key2": "values2"
  }, 
  "headers": {
    "Accept": "*/*", 
    "Accept-Encoding": "gzip, deflate", 
    "Content-Length": "25", 
    "Content-Type": "application/x-www-form-urlencoded", 
    "Host": "httpbin.org", 
    "User-Agent": "python-requests/2.10.0"
  }, 
  "json": null, 
  "origin": "221.212.116.44", 
  "url": "http://httpbin.org/post"
}

POST一個多部分編碼(Multipart-Encoded)的文件

這里我添加了一個以前寫的記錄在txt文件中的一段話

import requests,json
url = 'http://httpbin.org/post'
files = {'file':open('Inception.txt','rb')}
html_file = requests.post(url,files=files)
print html_file
print html_file.text
<Response [200]>
{
  "args": {}, 
  "data": "", 
  "files": {
    "file": "\r\n-------------------------------------\u6211\u662f\u5206\u5272\u7ebf-----------------------------------------\r\nInception .............此處省略n個"
  }, 
  "form": {}, 
  "headers": {
    "Accept": "*/*", 
    "Accept-Encoding": "gzip, deflate", 
    "Content-Length": "32796", 
    "Content-Type": "multipart/form-data; boundary=a4ba16fec9054637b7cb6f264013988b", 
    "Host": "httpbin.org", 
    "User-Agent": "python-requests/2.10.0"
  }, 
  "json": null, 
  "origin": "221.212.116.44", 
  "url": "http://httpbin.org/post"
}

既然剛學了json,那我就把它用json保存下來,然后再用字典查詢的方法,看看能不能把上傳的file是不是本地的file
再上述程序下添加:

print html_file.json()
print html_file.json()['files']['file']#字典取value的結構

結果就是

{u'files': {u'file': u'\r\n-------------------------------------\u6211\u662f\u5206\u5272\u7ebf---------.........省略n個
-------------------------------------我是分割線-----------------------------------------
Inception 情節邏輯完全解析 (有不明白地方的進,沒看過的別進)...省略n個字符

所以證明了,我上傳成功了,只是被編碼為unicode而已,而print自帶將unicode轉為utf-8的,so,驗證成功,推薦個轉碼小工具編碼轉換工具


另一個題外話

當我自己寫一個新的txt(測試那個txt是機器寫的),像這樣,再上傳,在抓下來,發現已經被bsae64編碼了,


這里寫圖片描述
import requests,json
url = 'http://httpbin.org/post'
files = {'file':open('post_file.txt','rb')}
html_file = requests.post(url,files=files)
print html_file.text
print html_file.json()['files']['file']

結果是這樣的

{
  "args": {}, 
  "data": "", 
  "files": {
    "file": "data:application/octet-stream;base64,1eLKx9K7uPay4srUo6ENCnRoaXMgaXMgYSB0ZXN0o6E="
  }, 
  "form": {}, 
  "headers": {
    "Accept": "*/*", 
    "Accept-Encoding": "gzip, deflate", 
    "Content-Length": "181", 
    "Content-Type": "multipart/form-data; boundary=6cd3e994e14d428e9df61d7e1aade15e", 
    "Host": "httpbin.org", 
    "User-Agent": "python-requests/2.10.0"
  }, 
  "json": null, 
  "origin": "221.212.116.44", 
  "url": "http://httpbin.org/post"
}

data:application/octet-stream;base64,1eLKx9K7uPay4srUo6ENCnRoaXMgaXMgYSB0ZXN0o6E=

并未如我所愿,直接打印出我上傳的txt中的文件,而是還需要在解碼,先看看內容是不是我想要的,上小工具Base64在線編碼解碼 UTF-8

這里寫圖片描述

OK,說明的確是我想要的,只是被編碼了而已,那就嘗試自己解碼

print base64.b64decode('1eLKx9K7uPay4srUo6ENCnRoaXMgaXMgYSB0ZXN0o6E=')

結果是

????????????
this is a test??

so ,WTF,又出什么幺蛾子!!


這里寫圖片描述

說好的base64解碼呢!!!怎么中文和感嘆號又是亂碼!難道和我寫入txt時候編碼有關。。。神煩編碼。。。

再進行測試

import base64
s = '1eLKx9K7uPay4srUo6ENCnRoaXMgaXMgYSB0ZXN0o6E='
h ='這是一個測試!this is a test!'
f = base64.b64encode(h)
print f
print base64.b64decode(f)

輸出

6L+Z5piv5LiA5Liq5rWL6K+V77yBdGhpcyBpcyBhIHRlc3Qh
這是一個測試!this is a test!

這就可行??
再放到那個工具下看看

這里寫圖片描述

好吧,我感覺自己受到了侮辱
這里寫圖片描述

不弄了,下次知道再說

補充二

上述出現亂碼的問題出在我編輯txt文件時候采用的ANSI編碼

這里寫圖片描述

多虧[Python爬蟲] 中文編碼問題:raw_input輸入、文件讀取、變量比較等str、unicode、utf-8轉換問題 的啟發,我才看到原來是這樣,所以我就把文件保存格式轉化成utf-8,問題順利解決,而且都不用進行base64解碼

import requests

url = 'http://httpbin.org/post'
files = {'file':open('post_file.txt','rb')}
html_file = requests.post(url,files=files)
print html_file.text
print html_file.json()['files']['file']

運行結果如下

{
  "args": {}, 
  "data": "", 
  "files": {
    "file": "\ufeff\u8fd9\u662f\u4e00\u4e2a\u6d4b\u8bd5!\r\nthis is a test!"
  }, 
  "form": {}, 
  "headers": {
    "Accept": "*/*", 
    "Accept-Encoding": "gzip, deflate", 
    "Content-Length": "188", 
    "Content-Type": "multipart/form-data; boundary=c95fbf7e4012470792ca6db843c0b3d1", 
    "Host": "httpbin.org", 
    "User-Agent": "python-requests/2.10.0"
  }, 
  "json": null, 
  "origin": "183.248.200.49", 
  "url": "http://httpbin.org/post"
}

這是一個測試!
this is a test!

我們可以看到files添加部分變成了

\ufeff\u8fd9\u662f\u4e00\u4e2a\u6d4b\u8bd5!\r\nthis is a test!

這是典型的unicode啊,而print unicode碼是直接進行utf-8轉化的,驗證想法;

print type(html_file.json()['files']['file'])

果然

<type 'unicode'>

響應status狀態,響應header

就是字典的操作而已啦。。。。

import requests
url = 'http://httpbin.org/get'

html = requests.get(url)
print html.status_code
print html.headers
print html.headers.get('Content-Length')
print html.headers['Content-Length']#采用字典形式
200
{'Content-Length': '239', 'Server': 'nginx', 'Connection': 'keep-alive', 'Access-Control-Allow-Credentials': 'true', 'Date': 'Sun, 24 Jul 2016 09:05:02 GMT', 'Access-Control-Allow-Origin': '*', 'Content-Type': 'application/json'}
239
239

如果返回404,那就是無法get到網頁了,也可以用這個模擬一下

import requests
url = 'http://httpbin.org/status/404'
html = requests.get(url)
print html.status_code
404

訪問Cookies

獲取cookies,以自己學校的教務處為例

這里寫圖片描述
import requests
url ='http://yjsymis.hrbeu.edu.cn/gsmis/Image.do'
html = requests.get(url)
print html.cookies['JSESSIONID']

因為采取的是驗證碼的cookies,所以每次都不一樣

2D5E260E4BB9C58E9CD21792F42D14BA

要想發送你的cookies到服務器,可以使用 cookies 參數:

import requests
url = 'http://httpbin.org/cookies'
html = requests.get(url)
cookies = dict(cookies_new = 'new one')
html_cookies = requests.get(url,cookies=cookies)
print html_cookies.text
{
  "cookies": {
    "cookies_new": "new one"
  }
}

補充三:處理登錄和cookie

cookie簡介:使用cookie跟蹤用戶是否已登錄狀態信息,一旦網站驗證了你的登錄權限,它就會將他們保存在你的瀏覽器的cookie中,里面通常包含一個服務器生成的令牌,登錄有效時限和狀態跟蹤信息。

首先是三個頁面,正常來說,我們進行操作的是登錄頁面

http://pythonscraping.com/pages/cookies/login.html
這里寫圖片描述

但是,如果采用post填充表格的話,其實可以省去登錄頁面,一個post加上登錄所需的賬號密碼即可進行填充表單。

登陸后歡迎頁面是(直接輸入網址因為沒有登錄信息所以顯示未登錄狀態)

http://pythonscraping.com/pages/cookies/welcome.php
這里寫圖片描述

最后利用剛才登錄好的cookies,再獲取登錄簡介后的頁面

http://pythonscraping.com/pages/cookies/profile.php
這里寫圖片描述

完整操作如下

import requests

url = 'http://pythonscraping.com/pages/cookies/welcome.php'
#構造表單params
params = {'username': 'mrlevo', 'password': 'password'}
#先進行提交表單,填充賬號密碼
r = requests.post('http://pythonscraping.com/pages/cookies/welcome.php',params) 
#在利用登錄后的cookies進行get內容操作
r = requests.get('http://pythonscraping.com/pages/cookies/profile.php',cookies = r.cookies)
print r.text

IDE輸出結果

Hey mrlevo! Looks like you're still logged into the site!

所出現的效果和自己手動操作瀏覽器是一樣的,但是簡略了很多。

如果剛開始就不需要cookies而且網站比較復雜,它會暗自調整cookie時候,采用session函數進行解決,他能持續跟蹤會話信息,比如cookie,header,甚至運行HTTP協議的信息,比如HTTPAdapter

例子如下,效果同上

import requests

url = 'http://pythonscraping.com/pages/cookies/welcome.php'
#構造表單params
params = {'username': 'mrlevo', 'password': 'password'}
#先進行提交表單,填充賬號密碼
r = requests.Session().post(url,params)
#在利用登錄后的cookies進行get內容操作
r = requests.Session().get('http://pythonscraping.com/pages/cookies/profile.php',cookies = r.cookies)
print r.text

補充四:HTTP基本接入認證

在cookie出現之前,處理網站登錄最常用的方法是用HTTP基本接入認證,測試網址采用Python網絡數據采集[美]Ryan Mitchell這本書采用的例子

http://pythonscraping.com/pages/auth/login.php

出現的效果是這樣的,需要進行用戶名的登錄驗證

這里寫圖片描述
import requests
from requests.auth import AuthBase
from requests.auth import HTTPBasicAuth

url = 'http://pythonscraping.com/pages/auth/login.php'
auth = HTTPBasicAuth('mrlevo','password')
r = requests.post(url = url,auth = auth)
print r.text

在IDE中輸出效果是

<p>Hello mrlevo.</p><p>You entered password as your password.</p>

重定向,請求歷史與超時

首先使用自己的圖書館登錄系統來試驗一下。

import requests
url = 'http://lib.hrbeu.edu.cn/'
html = requests.get(url)
print html.status_code
print html.history
200
[]

第二個返回了空列表,導演,這和網上的寫的不一樣啊。
原來,還有這么一段話,并不是所有網頁都會處理重定向的,例子中用了Github,我抖機靈的以為,所有網頁都會和例子中的一樣。。下面是正經例子

import requests
url = 'http://github.com'
html = requests.get(url)
print html.status_code
print html.history

標準答案

200
[<Response [301]>]

使用GET或OPTIONS時,Requests會自動處理位置重定向。Github將所有的HTTP請求重定向到HTTPS。可以使用響應對象的 history 方法來追蹤重定向。

老老實實抄原話

Response.history 是一個:class:Request 對象的列表,為了完成請求而創建了這些對象。這個對象列表按照從最老到最近的請求進行排序。如果你使用的是GET或OPTIONS,那么你可以通過 allow_redirects 參數禁用重定向處理:

import requests
url = 'http://github.com'
html = requests.get(url,allow_redirects=False)
print html.status_code
print html.history
301
[]

順便說一下301錯誤
301代表永久性轉移(Permanently Moved),301重定向是網頁更改地址后對搜索引擎友好的最好方法,只要不是暫時搬移的情況,都建議使用301來做轉址。

如果你使用的是POST,PUT,PATCH,DELETE或HEAD,你也可以啟用重定向:

順便說下重定向是啥-from 百度百科

這里寫圖片描述
import requests
url = 'http://github.com'
html = requests.get(url,allow_redirects=True)
print html.status_code
print html.url
print html.history
200
https://github.com/
[<Response [301]>]

超時這個反而是最好理解的,如果在timeout時間還未做出響應,那就拋出錯誤,你時間設置的越短,響應需要越快才能不報錯,也是對時間的有效利用和防止一直不斷獲取

import requests
url = 'http://github.com'
html = requests.get(url,allow_redirects=True,timeout=1)
print html.status_code
200

時間設置短一點的話,

import requests
url = 'http://github.com'
html = requests.get(url,allow_redirects=True,timeout=0.1)
print html.status_code

拋出如下錯誤

requests.exceptions.ConnectTimeout: HTTPConnectionPool(host='github.com', port=80): Max retries exceeded with url: / (Caused by ConnectTimeoutError(<requests.packages.urllib3.connection.HTTPConnection object at 0x0000000003584550>, 'Connection to github.com timed out. (connect timeout=0.1)'))

timeout 僅對連接過程有效,與響應體的下載無關。

也就是說,你如果requests一個圖片網站,圖片下載并不和timeout時間有關,而是和連接到圖片網址的時間有關


錯誤與異常

遇到網絡問題(如:DNS查詢失敗、拒絕連接等)時,Requests會拋出一個ConnectionError 異常。

比如說,我們來訪問谷歌

import requests
url = 'http://google.com'
html = requests.get(url,allow_redirects=True)
print html.status_code

很放心的拋出了ConnectionError

ConnectionError: HTTPConnectionPool(host='google.com', port=80): Max retries exceeded with url: / (Caused by NewConnectionError('<requests.packages.urllib3.connection.HTTPConnection object at 0x0000000003328550>: Failed to establish a new connection: [Errno 10060] ',))

遇到罕見的無效HTTP響應時,Requests則會拋出一個 HTTPError 異常。

這個等我遇到了我再放上例子

若請求超時,則拋出一個 Timeout 異常。若請求超過了設定的最大重定向次數,則會拋出一個 TooManyRedirects 異常。所有Requests顯式拋出的異常都繼承自 requests.exceptions.RequestException 。


Requests的一些編碼問題

在嘗試用Requests+BeautifulSoup進行練習的時候發現,其解碼方式和urllib2有點區別。
比如說,我采集網易主頁http://www.163.com/網易采用的是gbk編碼方式,使用urllib2時候,我們一般進行decode處理
就像這樣

import urllib2
url='http://www.163.com'
html_url = urllib2.urlopen(urllib2.Request(url))
print html_url.read().decode('gbk')

來達到編碼轉換的目的,而requests則不是,剛開始我想當然的以為可以這樣進行編碼解碼,其實不然,需要這樣

html.encoding = 'gbk'

來規定編碼方式,完整如下

import requests
from bs4 import BeautifulSoup
url='http://www.163.com'
html = requests.get(url)
html.encoding = 'gbk'
bs = BeautifulSoup(html.text,'lxml')
print bs.prettify()

(這里編碼查看建議使用360瀏覽器,點擊頁面,右鍵,編碼,就可以看到編碼格式,當然你可以看打開檢查元素查看,其余的功能還是谷歌和firefox強一些,所以說,我現在有四個瀏覽器,各取所需吧,并不是說谷歌和firefox最好,只是某些方面)


這里寫圖片描述

值得注意的是,當頁面是utf-8編碼的時候,以http://www.feng.com/為例,采用urllib2不需要進行解碼操作,本身IDE編碼格式就是utf-8,但是,requests則仍要進行編碼規定,(具體原因我還不是很清楚,下次補充),不然會亂碼,那是相當的亂,不忍直視的亂,像這樣↓

<!-- ??
é|?é?μ?????¨?o??£??o??1????  -->

只要改這個就可以了

html.encoding = 'utf-8'

其余不變(url當然得換),就可以輸出中文操作,哎,又漲了點姿勢



更新

1.于2016.7.24 18:12第一次撰寫
2.于2016.7.25 10:25第二次撰寫
3.于2016.7.27 14:13第三次撰寫
4.于2016.7.28 11:02第四次撰寫
5.于2016.8.31 14:18第五次撰寫


致謝

Python網絡數據采集[美]Ryan Mitchell
原--Python Requests快速入門
轉--Python Requests快速入門
轉--HTTP Get,Post請求詳解
轉--python模塊之StringIO使用示例
@青南的小世界 --requests的content與text導致lxml的解析問題
@mmc2015--python的【字典dict】:創建、訪問、更新、刪除;查看鍵、值、鍵值對;遍歷;排序
@我們都是從菜鳥開始--HTML table、form表單標簽的介紹
@廖雪峰--base64
@上帝在云端--python爬蟲 - Urllib庫及cookie的使用
@百度百科--網頁重定向
@Eastmount--[Python爬蟲] 中文編碼問題:raw_input輸入、文件讀取、變量比較等str、unicode、utf-8轉換問題
A&Q--使用requests庫抓取頁面的時候的編碼問題

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,923評論 6 535
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,740評論 3 420
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,856評論 0 380
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,175評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,931評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,321評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,383評論 3 443
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,533評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,082評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,891評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,067評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,618評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,319評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,732評論 0 27
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,987評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,794評論 3 394
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,076評論 2 375

推薦閱讀更多精彩內容

  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,796評論 18 139
  • 如果你把上篇多線程和多進程的文章搞定了,那么要恭喜你了 。你編寫爬蟲的能力上了一個嶄新的臺階。不過,我們還不能沾沾...
    猴哥愛讀書閱讀 3,382評論 2 31
  • 基礎知識 HTTP協議 我們瀏覽網頁的瀏覽器和手機應用客戶端與服務器通信幾乎都是基于HTTP協議,而爬蟲可以看作是...
    腩啵兔子閱讀 1,501評論 0 17
  • 當一切理想幻滅,我還仍然相信美好時,似乎就注定我會擁有我所渴望的生活。 14年研究生落榜,也曾淚水盈盈。沒有...
    納蘭紫瀟閱讀 458評論 4 4
  • 1、首先創建一個bundle工程,名稱為:LibraryResources 2、因為bundle默認是OS系統的,...
    百事星空閱讀 1,260評論 0 3