2.urllib庫的使用

urllib庫的使用

urllib庫是Python內置的HTTP請求庫,它包含了4個模塊:php

  request:最基本的HTTP請求模塊,用來模擬發送請求html

  error:異常處理模塊。出現請求錯誤後,咱們能夠捕獲異常,而後進行下一步的操做。python

  parse:工具模塊。提供了不少URL處理方法。瀏覽器

  robotparse:主要用來識網站的robots.text文件,用的比較少服務器

1.發送請求

  urllib的request模塊能夠幫助咱們方便的發送請求並獲得響應。下面咱們來看一下用法:socket

  1.urlopen()

   urlopen()參數有url、data、timeout、context、cafile、capath、cadefault,咱們只詳細瞭解三個,他們比較重要:工具

      url:要請求的網址post

      下面咱們以Python官網爲例,咱們來把它抓取下來:測試

      

import urllib.request
response
= urllib.request.urlopen("https://www.python.org/")
print(response)

 咱們充滿期待的想要看到網頁內容,卻發現是這樣:fetch

顯而易見,咱們獲得的結果是一個HTTPResponse類的對象,咱們想要獲得它的內容得使用它的read()方法,另外read()獲得的是bytes類型的數據,咱們將它解碼,方便觀看

import urllib.request
response
= urllib.request.urlopen("https://www.python.org/") print(response.read().decode("UTF-8"))

此次獲得的結果,如咱們所願,不就是網頁的源代碼嘛:

 

 下來咱們說一下這個HTTPResponse類型的對象,他有不少屬性和方法,

https://www.cnblogs.com/kissdodog/archive/2013/02/06/2906677.html   這個博客中有詳細說明,我就很少提了^_^

 

 

 

      data:data參數是可選的,但必須給bytes類型,一旦設置data參數,請求的方式就會變成POST,若是不設置則默認爲GET

      咱們經過代碼看一下:

import urllib.parse
import urllib.request
data
= bytes(urllib.parse.urlencode({"word":"hello"}),encoding="UTF-8") #咱們藉助urllib庫的parse中的urlencode方法將字典轉化爲字符串 response = urllib.request.urlopen("http://httpbin.org/post",data=data) #這個網站用來作HTTP請求測試,咱們用來進行POST請示測試 print(response.read().decode("UTF-8"))

咱們來看一下結果:

咱們能夠很清楚的看到咱們傳進的data參數出如今了form裏面,咱們知道只有POST請求才會把數據封裝到form表單中。data設置的參數會被封裝到form表單中,封裝到請求頭中傳遞給服務器。

 

 

 

      timeout:設置超時時間,單位爲秒,當超過這個時間,請求沒有獲得響應,就會拋出異常。

import urllib.request
response
= urllib.request.urlopen("http://httpbin.org/get",timeout=0.1) #咱們將這個時間設置的短一點,請求不可能這麼快獲得響應,這樣就會拋出異常 print(response.read())

 果真不出所料:

可是,咱們都知道Python有try except異常處理機制,咱們在這裏能夠用到

import socket
import urllib.request
import urllib.error
try: response = urllib.request.urlopen("http://httpbin.org/get",timeout=0.1) except urllib.error.URLError as e: if isinstance(e.reason,socket.timeout): print("超時了")

因此咱們經過設置timeout,一旦超時進行異常處理,這樣能很好的提升爬取速率

       context:用來指定SSL設置。

       cafile:CA證書。

       capath:CA證書的路徑。

       cadefault:如今已棄用,默認值爲false。

    2.Request

    咱們能夠利用urlopen()方法來發送請求,可是urlopen()中幾個參數並不能構成一個完整的請求。咱們須要藉助Request類構建對象,對象中能夠攜帶Headers等信息,從而實現完整的請求。

    咱們先來看一下Request的用法:

    

import urllib.request
request
= urllib.request.Request("https://python.org") print(type(request)) response = urllib.request.urlopen(request) #咱們仍然使用urlopen()來發送請求,可是方法的參數不是URL,而是一個request對象,咱們將參數獨立成對象,能夠靈活的進行參數配置。 print(response.read().decode("UTF-8"))

    下面咱們看一下Request對象的參數有哪些:

    url:用於請求的URL,必傳參數,其餘都是選傳。

    data:必須傳bytes類型的。若是是字典,咱們能夠藉助urllib.parse模塊中的urlencode()進行編碼。

    headers:請求頭,是一個字典。咱們能夠直接構造,也能夠經過調用add_header()方法添加

    ps:請求頭中最常改的就是User-Agent,默認的User-Agent爲Python-urllib,咱們能夠經過修改它來僞造瀏覽器。好比咱們要假裝爲火狐瀏覽器,能夠設置爲:

    Mozilla/4.0 (compatible; MSIE 5.5; Window NT)

    origin_req_host:請求放的host名稱或IP地址

    unverifiable:用戶用沒有權限來選擇接收請求的結果。默認爲False,若是沒有權限賊爲True,不然爲False。

    method:請求使用的方法,如GET、POST和PUT

    話很少說,咱們來看一下:

    

from urllib import request,parse

url = "http://httpbin.org/post"
headers = {
    "User-Agent":"Mozilla/4.0 (compatible; MSIE 5.5; Windows NT",
    "Host":"httpbin.org"
}
dict = {
    "name":"Germey"
}
data = bytes(parse.urlencode(dict),encoding="UTF-8")
req = request.Request(url=url,data=data,headers=headers,method="POST")
response = request.urlopen(req)
print(response.read().decode("UTF-8"))

明顯的看到,咱們成功的設置了headers,method,data。

headers信息咱們還可使用add_headers來添加

from urllib import request,parse

url = "http://httpbin.org/post"
dict = {
    "name":"Germey"
}
data = bytes(parse.urlencode(dict),encoding="UTF-8")
req = request.Request(url=url,data=data,method="POST")
req.add_header("User-Agent","Mozilla/4.0 (compatible; MSIE 5.5; Windows NT")   #add_headers(key,value)
response = request.urlopen(req)
print(response.read().decode("UTF-8"))

2.處理異常

咱們已經瞭解了怎樣發送請求,可是請求不是每次都能獲得響應,可能會出現異常,不去處理它程序可能所以停掉,因此頗有必要去處理異常。

urllib的error模塊定義了由request模塊產生的異常。若是出現問題,request模塊會拋出error模塊中定義的異常。

  1.URLError

  URLError類來自error模塊,是error異常模塊的基類,由request模塊產生的異常均可以經過捕獲這個類來處理,它的屬性reason能夠返回錯誤緣由。

from urllib import request,error

try:
    response = request.urlopen("https://cuiqingcai.com/index.htm")     #咱們打開的頁面不存在
except error.URLError as e:
    print(e.reason) 

咱們打開的頁面不存在,按理說會報錯,可是咱們將異常捕獲,並輸出異常得緣由,經過這樣的操做,咱們能夠避免程序異常終止,並且異常獲得了很好的處理。

   2.HTTPError

  他是URLError的子類,專門用來處理HTTP請求錯誤。他有三個屬性:

  code:返回HTTP狀態碼,好比404表示頁面不存在,500表示服務器內部出錯

  reason:返回錯誤的緣由

  headers:返回請求頭

from urllib import request,error

try:
    response = request.urlopen("http://cuiqingcai.com/index.htm")
except error.HTTPError as e:
    print(e.reason,e.code,e.headers,sep="\n")

一樣的網頁,咱們經過捕獲HTTPError來得到reson,code和headers屬性。由於URLError是HTTPError的子類,因此咱們能夠選擇捕獲子類的錯誤,若是沒有再去捕獲父類錯誤,代碼以下:

from urllib import request,error

try:
    response = request.urlopen("http://cuiqingcai.com/index.htm")
except error.HTTPError as e:
    print(e.reason,e.code,e.headers,sep="\n")
except error.URLError as e:
    print(e.reason)
else:
    print("Request Successfully")

可是有時候reason屬性返回的不是字符串,而是一個對象:

from urllib import request,error

try:
    response = request.urlopen("http://cuiqingcai.com/index.htm",timeout=0.01)
except error.HTTPError as e:
    print(e.reason,e.code,e.headers,sep="\n")
    print(type(e.reason))
except error.URLError as e:
    print(e.reason)
    print(type(e.reason))
else:
    print("Request Successfully")

咱們能夠很清楚的看到e.reson是一個socket.timeout對象,咱們簡單的記住就好了,請求超時後,返回的錯誤爲timed out,是socket.timeout類的對象

學了處理異常後,經過捕獲異常並處理,可使咱們的程序更加的穩健。

3.解析連接

前面提到了urllib庫裏的parse模塊,他提供了不少處理連接的方法,實現了URL各部分的抽取、合併、以及連接轉化。

  1.urlparse()  

    該方法能夠實現URL的識別和分段,共有三個參數,返回的結果是一個元組咱們能夠經過屬性或索引拿到相應的值

    urlstring:待解析的URL,必選項

    scheme:默認的協議,若是連接沒有帶協議會解析出默認協議,不然解析出連接帶的協議

    allow_fragments:是否忽略fragment,若是爲false,fragment部分就會被忽略,會被解析成path、params或query的一部分

    urlparse()會把URL解析成6個部分,標準的連接格式以下:

    scheme://netloc/path;params?query#fragment

    協議://域名/訪問路徑;參數?查詢條件#錨點

    查詢條件通常用做GET類型的URL,錨點用於定位頁面內部的下拉位置

from urllib.parse import urlparse

result = urlparse("http://www.baidu.com/index.html;user?id=5#comment")
print(type(result),result,sep="\n")

  2.urlunparse()

   該方法接受一個可迭代對象,長度必須是6,對可迭代對象進行遍歷,構造URL

  

from urllib.parse import urlunparse

data = ["http","www.baidu.com","index.html","user","a=6","comment"]
print(urlunparse(data))

  3.urlsplit()

  該方法與urlparse()方法相似,只不過它再也不單獨解析params,params合併到path中,返回的也是個元組,長度爲5

  

from urllib.parse import urlsplit

result = urlsplit("http://www.baidu.com/index.html;user?a=6#comment")
print(result)

 

  4.urlunsplit()

  參照urlunparse(),可是長度爲5

  5.urljoin()

   有兩個參數,第一個爲base_url(基礎連接),第二個爲new_url(新的連接),該方法會解析base_url的scheme,netloc和path,若是新的連接存在就是用新的連接的部分,若是不存在就補充。

from urllib.parse import urljoin

print(urljoin("http://www.baidu.com","FAQ.html"))
print(urljoin("http://www.baidu.com","https://cuiqingcai.com/FAQ.html"))
print(urljoin("http://www.baidu.com/about.html","https://cuiqingcai.com/FAQ.html"))
print(urljoin("http://www.baidu.com/about.html","http://cuiqingcai.com/FAQ.html?question=2"))
print(urljoin("http://www.baidu.com?wd=abc","https://cuiqingcai.com/index.php"))
print("http://www.baidu.com","?category=2#comment")
print("www.baidu.com","?category=2#comment")
print("www.baidu.com#comment","?category=2")

  6.urlencode() 

   在構造GET請求的參數時,能夠將字典類型的數據轉化爲GET請求參數

  

from urllib.parse import urlencode

params = {
    "name":"heesch",
    "age":18
}
base_url = "http://baidu.com?"
url = base_url + urlencode(params)
print(url)

  7.parse_qs()

   與urlencode()相反,將GET請求的參數化爲字典的形式

  

from urllib.parse import parse_qs
query = "name=heesch&age=18"
print(parse_qs(query))

  8.parse_qsl()

  他是將GET請求的參數轉化爲元組組成的列表

  

from urllib.parse import parse_qsl
query = "name=heesch&age=18"
print(parse_qsl(query))

  9.quote()

   將內容轉化爲URL編碼的格式,URL中帶有中文參數時,有時可能會致使亂碼的問題。

  

from urllib.parse import quote

keyword = "壁紙"
url = "http://www.baidu.com" + quote(keyword)
print(url)

  10.unquote()

   與quote相反,將URL進行解碼

  

from urllib.parse import unquote

url = "http://www.baidu.com%E5%A3%81%E7%BA%B8"
print(unquote(url))

 4.分析Robots協議

  1.Robots協議

    Robots協議也稱做爬蟲協議、機器人協議,用來告訴爬蟲和搜索引擎哪些頁面能夠爬取,哪些不能夠抓取。一般是一個叫作robots.txt的文本文件,放在網站的根目錄下

    當搜索爬蟲訪問一個站點是,首先會檢查這個站點的根目錄下是否存在robots.txt文件,若是存在,搜索爬蟲則會根據其中定義的爬取範圍來爬取。若是沒有,則搜索爬蟲會訪問全部可直接訪問的站點。

   下面看一個robots.text樣例:

User-agent:*
Disallow:/
Allow:/public/

   User-agent:設置爬蟲的名稱,* 表示該協議對任何爬蟲都有效

      Dislalow:制定了不容許抓取的目錄,若爲/ 表示不容許抓取任何頁面

    Allow:和Disallow一塊兒出現,限制訪問路徑

  2.常見爬蟲

  

  3.robotparse

   瞭解完Robots協議以後,咱們可使用robotparser模塊來解析robot.txt。該模塊提供一個類RobotFileParse,它能夠根據robots.txt文件來判斷一個爬蟲是否有權限來爬取這個頁面

    聲明:urllib.robotparser.RobotFileParser(url="")

    這個類經常使用的方法:

    set_url():設置robots.txt文件的連接。若是建立RobotFileParse對象時傳入連接,就不須要用這個方法進行設置了

    read():讀取robots.text文件並分析,不會返回結果,可是執行了讀取操做,若是不執行,下面的方法判斷都爲false

    parse():用來解析robots.txt文件

    can_fetch():有兩個參數,第一個是User-agent,第二個是要抓取的URL,返回的結果爲True或False,用來判斷是否能抓取這個頁面

    mtime():返回上次抓取robot.txt的時間,對於長時間分析或抓取的搜索爬蟲須要按期檢查

    modified():將當前時間設置爲上次抓取和分析robots.txt的時間

咱們先用can_fetch()方法來判斷網頁是否能抓取:

from urllib.robotparser import RobotFileParser

rp = RobotFileParser()
rp.set_url("http://jianshu.com/robot.txt")
rp.read()
print(rp.can_fetch("*","http://www.jianshu.com/p/b67554025d7d"))
print(rp.can_fetch("*","http://www.jianshu.com/search?q=python&page=1&type=collections"))

兩個false,都不讓抓取。

咱們再用parse()方法來判斷網頁是否能抓取:

from urllib.robotparser import RobotFileParser
from urllib import request,parse

url = "https://www.jianshu.com/robots.txt"
headers = {
    "User-Agent":"Mozilla/4.0 (compatible; MSIE 5.5; Windows NT",
}
rp = RobotFileParser()
req = request.Request(url=url,headers=headers,method="GET")
rp.parse(request.urlopen(req).read().decode("UTF-8").split("\n"))
print(rp.can_fetch("*","http://www.jianshu.com/p/b67554025d7d"))
print(rp.can_fetch("*","http://www.jianshu.com/search?q=python&page=1&type=collections"))

咱們學完robotparser模塊後,咱們能夠方便的判斷哪些一面能夠抓取,哪些頁面不能抓取。

相關文章
相關標籤/搜索