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庫抓取頁面的時候的編碼問題