urllib庫的使用

1. urllib庫的簡介

urllib庫是Python中一個最基本的網絡請求庫。可以模擬瀏覽器的行為,向指定的服務器發送一個請求,并可以保存服務器返回的數據。

2. urlopen函數:

在Python3的urllib庫中,所有和網絡請求相關的方法,都被集到urllib.request模塊下面了,以先來看下urlopen函數基本的使用:

from urllib import request
resp = request.urlopen('http://www.baidu.com')
print(resp.read())

實際上,使用瀏覽器訪問百度,右鍵查看源代碼。你會發現,跟我們剛才打印出來的數據是一模一樣的。也就是說,上面的三行代碼就已經幫我們把百度的首頁的全部代碼爬下來了。一個基本的url請求對應的python代碼真的非常簡單。
以下對urlopen函數的進行詳細講解:

  1. url:請求的url
  2. data:請求的data,如果設置了這個值,那么將變成post請求。
  3. 返回值:返回值是一個http.client.HTTPResponse對象,這個對象是一個類文件句柄對象。有read(size)readlinereadlines以及getcode等方法。

3. urlretrieve函數:

這個函數可以方便的將網頁上的一個文件保存到本地(媒體文件的下載)。以下代碼可以非常方便的將百度的首頁下載到本地:

from urllib import request
request.urlretrieve('http://www.baidu.com/','baidu.html')

4. urlencode函數:

用瀏覽器發送請求的時候,如果url中包含了中文或者其他特殊字符,那么瀏覽器會自動的給我們進行編碼。而如果使用代碼發送請求,那么就必須手動的進行編碼,這時候就應該使用urlencode函數來實現。urlencode可以把字典數據轉換為URL編碼的數據。示例代碼如下:

from urllib import parse
data = {'name':'爬蟲基礎','greet':'hello world','age':100}
qs = parse.urlencode(data)
print(qs)

5. parse_qs函數:

可以將經過編碼后的url參數進行解碼。示例代碼如下:

from urllib import parse
qs = "name=%E7%88%AC%E8%99%AB%E5%9F%BA%E7%A1%80&greet=hello+world&age=100"
print(parse.parse_qs(qs))

6. urlparse和urlsplit:

有時候拿到一個url,想要對這個url中的各個組成部分進行分割,那么這時候就可以使用urlparse或者是urlsplit來進行分割。示例代碼如下:

from urllib import request,parse

url = 'http://www.baidu.com/s?username=zhangsan'

result = parse.urlsplit(url)
# result = parse.urlparse(url)

print('scheme:',result.scheme)
print('netloc:',result.netloc)
print('path:',result.path)
print('query:',result.query)

urlparseurlsplit基本上是一模一樣的。唯一不一樣的地方是,urlparse里面多了一個params屬性,而urlsplit沒有這個params屬性。比如有一個url為:url = 'http://www.baidu.com/s;hello?wd=python&username=abc#1'
那么urlparse可以獲取到hello,而urlsplit不可以獲取到。url中的params也用得比較少。

7. request.Request類:

如果想要在請求的時候增加一些請求頭,那么就必須使用request.Request類來實現。比如要增加一個User-Agent,示例代碼如下:

from urllib import request

headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36'
}
req = request.Request("http://www.baidu.com/",headers=headers)
resp = request.urlopen(req)
print(resp.read())

8. ProxyHandler處理器(代理設置)

很多網站會檢測某一段時間某個IP的訪問次數(通過流量統計,系統日志等),如果訪問次數多的不像正常人,它會禁止這個IP的訪問。
所以我們可以設置一些代理服務器,每隔一段時間換一個代理,就算IP被禁止,依然可以換個IP繼續爬取。
urllib中通過ProxyHandler來設置使用代理服務器,下面代碼說明如何使用自定義opener來使用代理:

from urllib import request

# 這個是沒有使用代理的
# resp = request.urlopen('http://httpbin.org/get')
# print(resp.read().decode("utf-8"))

# 這個是使用了代理的
handler = request.ProxyHandler({"http":"218.66.161.88:31769"})

opener = request.build_opener(handler)
req = request.Request("http://httpbin.org/ip")
resp = opener.open(req)
print(resp.read())

常用的代理有:

9. 什么是cookie:

在網站中,http請求是無狀態的。也就是說即使第一次和服務器連接后并且登錄成功后,第二次請求服務器依然不能知道當前請求是哪個用戶。cookie的出現就是為了解決這個問題,第一次登錄后服務器返回一些數據(cookie)給瀏覽器,然后瀏覽器保存在本地,當該用戶發送第二次請求的時候,就會自動的把上次請求存儲的cookie數據自動的攜帶給服務器,服務器通過瀏覽器攜帶的數據就能判斷當前用戶是哪個了。cookie存儲的數據量有限,不同的瀏覽器有不同的存儲大小,但一般不超過4KB。因此使用cookie只能存儲一些小量的數據。

cookie的格式:

Set-Cookie: NAME=VALUE;Expires/Max-age=DATE;Path=PATH;Domain=DOMAIN_NAME;SECURE

參數意義:

  • NAME:cookie的名字。
  • VALUE:cookie的值。
  • Expires:cookie的過期時間。
  • Path:cookie作用的路徑。
  • Domain:cookie作用的域名。
  • SECURE:是否只在https協議下起作用。

10. 使用cookielib庫和HTTPCookieProcessor模擬登錄:

Cookie 是指網站服務器為了辨別用戶身份和進行Session跟蹤,而儲存在用戶瀏覽器上的文本文件,Cookie可以保持登錄信息到用戶下次與服務器的會話。
這里以人人網為例。人人網中,要訪問某個人的主頁,必須先登錄才能訪問,登錄說白了就是要有cookie信息。那么如果我們想要用代碼的方式訪問,就必須要有正確的cookie信息才能訪問。解決方案有兩種,第一種是使用瀏覽器訪問,然后將cookie信息復制下來,放到headers中。示例代碼如下:

from urllib import request

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36',
    'Cookie': 'anonymid=jacdwz2x-8bjldx; depovince=GW; _r01_=1; _ga=GA1.2.1455063316.1511436360; _gid=GA1.2.862627163.1511436360; wp=1; JSESSIONID=abczwY8ecd4xz8RJcyP-v; jebecookies=d4497791-9d41-4269-9e2b-3858d4989785|||||; ick_login=884e75d4-f361-4cff-94bb-81fe6c42b220; _de=EA5778F44555C091303554EBBEB4676C696BF75400CE19CC; p=61a3c7d0d4b2d1e991095353f83fa2141; first_login_flag=1; ln_uact=970138074@qq.com; ln_hurl=http://hdn.xnimg.cn/photos/hdn121/20170428/1700/main_nhiB_aebd0000854a1986.jpg; t=3dd84a3117737e819dd2c32f1cdb91d01; societyguester=3dd84a3117737e819dd2c32f1cdb91d01; id=443362311; xnsid=169efdc0; loginfrom=syshome; ch_id=10016; jebe_key=9c062f5a-4335-4a91-bf7a-970f8b86a64e%7Ca022c303305d1b2ab6b5089643e4b5de%7C1511449232839%7C1; wp_fold=0'
}

url = 'http://www.renren.com/880151247/profile'

req = request.Request(url,headers=headers)
resp = request.urlopen(req)
with open('renren.html','w') as fp:
    fp.write(resp.read().decode('utf-8'))

但是每次在訪問需要cookie的頁面都要從瀏覽器中復制cookie比較麻煩。在Python處理Cookie,一般是通過http.cookiejar模塊和urllib模塊的HTTPCookieProcessor處理器類一起使用。http.cookiejar模塊主要作用是提供用于存儲cookie的對象。而HTTPCookieProcessor處理器主要作用是處理這些cookie對象,并構建handler對象。

11. http.cookiejar模塊:

該模塊主要的類有CookieJar、FileCookieJar、MozillaCookieJar、LWPCookieJar。這四個類的作用分別如下:

  • CookieJar:管理HTTP cookie值、存儲HTTP請求生成的cookie、向傳出的HTTP請求添加cookie的對象。整個cookie都存儲在內存中,對CookieJar實例進行垃圾回收后cookie也將丟失。
  • FileCookieJar (filename,delayload=None,policy=None):從CookieJar派生而來,用來創建FileCookieJar實例,檢索cookie信息并將cookie存儲到文件中。filename是存儲cookie的文件名。delayloadTrue時支持延遲訪問訪問文件,即只有在需要時才讀取文件或在文件中存儲數據。
  • MozillaCookieJar (filename,delayload=None,policy=None):從FileCookieJar派生而來,創建與Mozilla瀏覽器 cookies.txt兼容的FileCookieJar實例。
  • LWPCookieJar (filename,delayload=None,policy=None):從FileCookieJar派生而來,創建與libwww-perl標準的 Set-Cookie3文件格式兼容的FileCookieJar實例。

登錄人人網:

利用http.cookiejarrequest.HTTPCookieProcessor登錄人人網。相關示例代碼如下:

from urllib import request,parse
from http.cookiejar import CookieJar

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36'
}

def get_opener():
    cookiejar = CookieJar()
    handler = request.HTTPCookieProcessor(cookiejar)
    opener = request.build_opener(handler)
    return opener

def login_renren(opener):
    data = {"email": "123456789@qq.com", "password": "abc123456789"}
    data = parse.urlencode(data).encode('utf-8')
    login_url = "http://www.renren.com/PLogin.do"
    req = request.Request(login_url, headers=headers, data=data)
    opener.open(req)

def visit_profile(opener):
    url = 'http://www.renren.com/880151247/profile'
    req = request.Request(url,headers=headers)
    resp = opener.open(req)
    with open('renren.html','w') as fp:
        fp.write(resp.read().decode("utf-8"))

if __name__ == '__main__':
    opener = get_opener()
    login_renren(opener)
    visit_profile(opener)

12. 保存cookie到本地:

保存cookie到本地,可以使用cookiejarsave方法,并且需要指定一個文件名:

from urllib import request
from http.cookiejar import MozillaCookieJar

cookiejar = MozillaCookieJar("cookie.txt")
handler = request.HTTPCookieProcessor(cookiejar)
opener = request.build_opener(handler)

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36'
}
req = request.Request('http://httpbin.org/cookies',headers=headers)

resp = opener.open(req)
print(resp.read())
cookiejar.save(ignore_discard=True,ignore_expires=True)

13. 從本地加載cookie:

從本地加載cookie,需要使用cookiejarload方法,并且也需要指定方法:

from urllib import request
from http.cookiejar import MozillaCookieJar

cookiejar = MozillaCookieJar("cookie.txt")
cookiejar.load(ignore_expires=True,ignore_discard=True)
handler = request.HTTPCookieProcessor(cookiejar)
opener = request.build_opener(handler)

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36'
}
req = request.Request('http://httpbin.org/cookies',headers=headers)

resp = opener.open(req)
print(resp.read())

14. 處理HTTPS請求 SSL證書驗證

現在隨處可見 https 開頭的網站,urllib可以為 HTTPS 請求驗證SSL證書,就像web瀏覽器一樣,如果網站的SSL證書是經過CA認證的,則能夠正常訪問,如:https://www.baidu.com/ 等...

如果SSL證書驗證不通過,或者操作系統不信任服務器的安全證書,比如瀏覽器在訪問12306網站如:https://www.12306.cn/mormhweb/ 的時候,會警告用戶證書不受信任。(據說 12306 網站證書是自己做的,沒有通過CA認證)

urllib在訪問的時候則會報出SSLError:

from urllib import request

url = "https://www.12306.cn/mormhweb/"

headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"}

request = request.Request(url, headers = headers)

response = request.urlopen(request)

print(response.read())

運行結果:

urllib.URLError: <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:590)>

所以,如果以后遇到這種網站,我們需要單獨處理SSL證書,讓程序忽略SSL證書驗證錯誤,即可正常訪問。

from urllib import request
# 1. 導入Python SSL處理模塊
import ssl

# 2. 表示忽略未經核實的SSL證書認證
context = ssl._create_unverified_context()

url = "https://www.12306.cn/mormhweb/"

headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"}

request = request.Request(url, headers = headers)

# 3. 在urlopen()方法里 指明添加 context 參數
response = request.urlopen(request, context = context)

print(response.read())

關于CA:

CA(Certificate Authority)是數字證書認證中心的簡稱,是指發放、管理、廢除數字證書的受信任的第三方機構,如北京數字認證股份有限公司、上海市數字證書認證中心有限公司等...

CA的作用是檢查證書持有者身份的合法性,并簽發證書,以防證書被偽造或篡改,以及對證書和密鑰進行管理。

現實生活中可以用身份證來證明身份, 那么在網絡世界里,數字證書就是身份證。和現實生活不同的是,并不是每個上網的用戶都有數字證書的,往往只有當一個人需要證明自己的身份的時候才需要用到數字證書。

普通用戶一般是不需要,因為網站并不關心是誰訪問了網站,現在的網站只關心流量。但是反過來,網站就需要證明自己的身份了。

比如說現在釣魚網站很多的,比如你想訪問的是www.baidu.com, 但其實你訪問的是www.daibu.com, 所以在提交自己的隱私信息之前需要驗證一下網站的身份,要求網站出示數字證書。

一般正常的網站都會主動出示自己的數字證書,來確保客戶端和網站服務器之間的通信數據是加密安全的。

15. urllib 的異常錯誤處理

在我們用urlopenopener.open方法發出一個請求時,如果urlopenopener.open不能處理這個response,就產生錯誤。

這里主要說的是URLErrorHTTPError,以及對它們的錯誤處理。

URLError

URLError 產生的原因主要有:

  1. 沒有網絡連接
  2. 服務器連接失敗
  3. 找不到指定的服務器
    我們可以用try except語句來捕獲相應的異常。下面的例子里我們訪問了一個不存在的域名:
from urllib import request

requset_info = urllib2.Request('http://www.ajkfhafwjqh.com')

try:
    request.urlopen(requset_info, timeout=5)
except urllib.URLError, err:
    print(err)

運行結果如下:

<urlopen error [Errno 8] nodename nor servname provided, or not known>

urlopen error,錯誤代碼8,錯誤原因是沒有找到指定的服務器。

HTTPError

HTTPError是URLError的子類,我們發出一個請求時,服務器上都會對應一個response應答對象,其中它包含一個數字"響應狀態碼"。

如果urlopen或opener.open不能處理的,會產生一個HTTPError,對應相應的狀態碼,HTTP狀態碼表示HTTP協議所返回的響應的狀態。

注意,urllib可以為我們處理重定向的頁面(也就是3開頭的響應碼),100-299范圍的號碼表示成功,所以我們只能看到400-599的錯誤號碼。

from urllib import request

req = request.Request('http://blog.baidu.com/itcast')

try:
    request.urlopen(req)
except urllib.HTTPError, err:
    print err.code
    print(err)

運行結果如下:

404
HTTP Error 404: Not Found

HTTP Error,錯誤代號是404,錯誤原因是Not Found,說明服務器無法找到被請求的頁面。
通常產生這種錯誤的,要么url不對,要么ip被封。

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