1. 程式人生 > >python爬蟲之urllib(一)

python爬蟲之urllib(一)

Python 3 中的 urllib 庫有四個模組,分別是urllib.requesturllib.errorurllib.parseurllib.robotparser。接下來我們對這四個模組做詳細介紹       參考:https://docs.python.org/3/library/

一,urllib.request

    1.1 urllib.request.urlopen

              request.urlopen(url, data=None, [timeout, ]*, cafile=None, capath=None, cadefault=False, context=None

)

              引數含義:

               url:  開啟一個url,url可以是一個字串或者一個 Request 物件

               data:  引數必須是一個位元組物件 ,該物件指明發送到伺服器的附加資料。如果不需要傳送資料,可以是None]

               timeout:  可選的引數 timeout 引數在秒的級別規定了一個連線嘗試的阻塞等待時間(如果沒有指定該引數,

                              全域性的預設的超時時間將被啟用),這個引數實際上只對http,https,ftp連結有效

               cafile和capath:  可選的 cafile 和 capath 引數用來為https請求指明一套可信的CA證書。cafile 必須是包含了

                                       一套證書的單獨的檔案,capath則應該指定這些證書檔案的目錄。

                                       ssl.SSLContext.load_verify_locations()函式中可以找到更多資訊

                 context:  如果 context 引數被指定,它必須是一個帶有各樣SLL選項的ssl.SSLContext例項

                 cadefault:  引數已經被棄用,可以不用管了。

接下來讓我看看怎麼應用

                 我們使用 urllib.request.urlopen() 去請求百度貼吧,並獲取到它頁面的原始碼。


import urllib.request 
url = "http://tieba.baidu.com" 
response = urllib.request.urlopen(url) 
html = response.read() # 獲取到頁面的原始碼 
print(html.decode('utf-8')) # 轉化為 utf-8 編碼

                 設定請求超時,有些請求可能因為網路原因無法得到響應。因此,我們可以手動設定超時時間。

                  當請求超時,我們可以採取進一步措施,例如選擇直接丟棄該請求或者再請求一次。

import urllib.request 
url = "http://tieba.baidu.com" 
response = urllib.request.urlopen(url, timeout=1) 
print(response.read().decode('utf-8'))

                   使用 data 引數提交資料,在請求某些網頁時需要攜帶一些資料,我們就需要使用到 data 引數params 需要被轉碼成位元組流。而 params 是一個字典。我們需要使用 urllib.parse.urlencode() 將字典轉化為字串。再使用 bytes() 轉為位元組流。最後使用 urlopen() 發起請求,請求是模擬用 POST 方式提交表單資料。

import urllib.parse
import urllib.request
url = "http://xx.xx.xx.xx/chitchat"
params = { "session":"1111","question":"你好" }
data = bytes(urllib.parse.urlencode(params), encoding='utf8')
response = urllib.request.urlopen(url, data=data)
print(response.read().decode('utf-8'))

     1.2 urllib.request.Request

由上我們知道利用 urlopen() 方法可以發起簡單的請求。但這幾個簡單的引數並不足以構建一個完整的請求,如果請求中需要加入headers(請求頭)、指定請求方式等資訊,我們就可以利用更強大的Request類來構建一個請求。 按照國際慣例,先看下 Request 的構造方法:

urllib.request.Request(url, data=None, headers={}, origin_req_host=None, unverifiable=False, method=None)

  url: 引數是請求連結,這個是必傳引數,其他的都是可選引數。

  data: 引數跟 urlopen() 中的 data 引數用法相同。

  headers: 引數是指定發起的 HTTP 請求的頭部資訊。headers 是一個字典。它除了在 Request 中新增,還可以

                        通過呼叫 Request例項的 add_header() 方法來新增請求頭。

  origin_req_host: 引數指的是請求方的 host 名稱或者 IP 地址。

  unverifiable: 引數表示這個請求是否是無法驗證的,預設值是False。意思就是說使用者沒有足夠許可權來選擇接收

                                 這個請求的結果。例如我們請求一個HTML文件中的圖片,但是我們沒有自動抓取影象的許可權,

                                我們就要將 unverifiable 的值設定成 True。

   method: 引數指的是發起的 HTTP 請求的方式,有 GET、POST、DELETE、PUT等

      接下來看一個demo吧:

import urllib.parse
import urllib.request
url = 'https://fanyi.baidu.com/'
headers = {
    'User-Agent': 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'
}
values = {
    'from': 'zh',
    'to':'en',
    'query':'肥豬',
    'transtype':'translang',
    'simple_means_flag':'3'
}
data = urllib.parse.urlencode(values).encode("utf-8")
request = urllib.request.Request(url,data,headers)
response = urllib.request.urlopen(request).read().decode("utf-8")
print(response)

        1.3 urllib.request.install_opener(opener)

              urllib.request.build_opener([handler, ...])

      urllib.request.ProxyHandler(proxies=None)

             在抓取一個網站的資訊時,如果我們進行頻繁的訪問,就很有可能被網站檢測到而被遮蔽,解決這個問題的方法就是使用ip代理 。在我們接入因特網進行上網時,我們的電腦都會被分配一個全球唯一地ip地址供我們使用,而當我們頻繁訪問一個網站時,網站也正是因為發現同一個ip地址訪問多次而進行遮蔽的,所以這時候如果我們使用多個ip地址進行隨機地輪流訪問,這樣被網站檢測的概率就很小了,這時候如果我們再使用多個不同的headers,這時候就有多個ip+主機的組合,訪問時被發現率又進一步減小了

     步驟:

      1、ProxyHandler類可以使用ip代理訪問網頁

           proxy_support = urllib.request.ProxyHandler({}),其中引數是一個字典{‘型別’:'代理ip:埠號'}

      2、定製、建立一個opener

           opener = urllib.request.build_opener(proxy_support)

      3、安裝opener

           urllib.request.install_opener(opener)

            呼叫預設的opener

            opener.open(url)

對於沒有設定反爬蟲機制的網站,我們只需要直接像上面那樣引入ProxyHandler類進行處理,不需要考慮模仿瀏覽器

接下來看段例子:

import urllib.request
url="https://www.baidu.com"
for i in range(0,10000):
    html = urllib.request.urlopen(url)
    print(html.info())
    print(i)

上面程式行351行就出錯了這是由於我們在訪問的時候,網站會記下我們的ip,當我們的ip訪問量在一段時間內超過網站設定的上限值的時候,這個請求就會被拒絕了

改進後代碼:

#coding:utf-8
from urllib.request import Request
from urllib.request import urlopen
import urllib
import random

def gethtml(url,proxies):
    proxy = random.choice(proxies)
    proxy_support = urllib.request.ProxyHandler({"http":proxy})
    opener = urllib.request.build_opener(proxy_support)
    urllib.request.install_opener(opener)
    html = urlopen(url)
    return html
url = "https://www.baidu.com"
proxies=["101.53.101.172:9999","171.117.93.229:8118","119.251.60.37:21387","58.246.194.70:8080"]

for i in range(100):
    try:
        html = gethtml(url,proxies)
        print(html.info())
        print(i)
    except:
        print("故障")

        1.4 urllib.request.pathname2url(path)

urllib.request.url2pathname(path)

                   暫還未研究透

1.5  urllib.request.getproxies()

這個helper函式返回一個日程表dictionary 去代理伺服器的URL對映。掃描指定的環境變數 _proxy大小寫不敏感的方法,對所有的作業系統,當它不能找到它,從Mac OS X的Mac OSX系統配置和Windows系統登錄檔中尋找代理資訊。如果兩個大寫和小寫環境變數存在(或不一樣),小寫優先。

請注意,如果環境變數 REQUEST_METHOD已被設定,這通常表明你在CGI指令碼執行環境,此時環境變數 HTTP_PROXY(大寫 _PROXY)將被忽略。這是因為該變數可以被客戶端使用注射“代理:”HTTP頭。如果你需要使用一個HTTP代理在CGI環境中,要麼使用 ProxyHandler明確,或者確保變數名小寫(或至少是 _proxy字尾)。

          1.6  urllib.request.OpenerDirector

OpenerDirector類開啟url並通過 BaseHandler連線在一起。它管理處理程式的連線,和恢復錯誤。

          1.7   urllib.request.BaseHandler

這是對於所有已註冊的處理程式的基類

          1.8  urllib.request.HTTPRedirectHandler

一個類來處理重定向

          1.9  urllib.request.HTTPCookieProcessor(cookiejar=None)

一個類來處理HTTP cookie。

          1.10  urllib.request.HTTPPasswordMgr

保持一個數據庫 (realm, uri) -> (user, password)對映。

         1.11  urllib.request.HTTPPasswordMgrWithDefaultRealm

保持一個數據庫 (realm, uri) -> (user, password)對映。一個領域 None被認為是一個全方位領域,如果沒有其他搜尋領域

         1.12  urllib.request.HTTPPasswordMgrWithPriorAuth

一個變體 HTTPPasswordMgrWithDefaultRealm還有一個數據庫 uri -> is_authenticated的對映。可以使用BasicAuth處理程式來確定當傳送身份驗證憑證立即而不是等待 401響應。

         1.13  urllib.request.AbstractBasicAuthHandler(password_mgr=None)

這是mixin類,幫助與HTTP身份驗證,遠端主機和代理。果有password_mgr,應該是相容 HTTPPasswordMgr的。請參閱部分 HTTPPasswordMgr物件必須支援的介面資訊。如果passwd_mgr還提供了 is_authenticated和 update_authenticated方法(見 HTTPPasswordMgrWithPriorAuth物件),然後處理程式將使用 is_authenticated結果對於一個給定的URI來決定是否傳送請求的身份驗證憑證。如果 is_authenticated返回 TrueURI,憑證傳送。如果 is_authenticated是 False憑證不傳送,然後如果 401收到響應請求傳送身份驗證憑證。如果身份驗證成功, update_authenticated被稱為設定 is_authenticated TrueURI,這樣後續請求的URI或任何super-URIs將自動包括身份驗證憑證。

在新的3.5版本:新增 is_authenticated支援。

        1.14  urllib.request.HTTPBasicAuthHandler(password_mgr=None)

與遠端主機處理身份驗證。如果有password_mgr,應該是相容HTTPPasswordMgr的。請參閱部分 HTTPPasswordMgr物件必須支援的介面資訊。HTTPBasicAuthHandler將提高 ValueError當面對一個錯誤的身份驗證方案。

        1.15  urllib.request.ProxyBasicAuthHandler(password_mgr=None)

處理與代理身份的驗證。如果有password_mgr,應該是相容 HTTPPasswordMgr的。請參閱部分 HTTPPasswordMgr物件必須支援的介面資訊。

       1.16  urllib.request.AbstractDigestAuthHandler(password_mgr=None)

這是mixin類,幫助與HTTP身份驗證,遠端主機和代理。password_mgr,如果有,應該是相容的 HTTPPasswordMgr;請參閱部分 HTTPPasswordMgr物件必須支援的介面資訊

       1.17  urllib.request.HTTPDigestAuthHandler(password_mgr=None)

與遠端主機處理身份驗證。如果有password_mgr,應該是相容 HTTPPasswordMgr的;請參閱部分 HTTPPasswordMgr物件必須支援的介面資訊。摘要式身份驗證處理程式和基本身份驗證處理器都是補充說,摘要式身份驗證總是嘗試第一次。如果主機返回一個40 x再次迴應,它傳送到基本身份驗證處理程式來處理。這個處理程式方法將提高 ValueError當面對除了消化或基本身份驗證方案。

3.3版本的變化:提高 ValueError不支援的身份驗證方案。

      1.18  urllib.request.ProxyDigestAuthHandler(password_mgr=None)

處理與代理身份驗證。如果有password_mgr,應該是相容 HTTPPasswordMgr的;請參閱部分 HTTPPasswordMgr物件必須支援的介面資訊

      1.19 urllib.request.HTTPHandler

一個類來處理HTTP url

     1.20  urllib.request.HTTPSHandler(debuglevel=0, context=None, check_hostname=None)

一個類來處理開放的HTTPS url。在context 文和check_hostname有相同的意義 http.client.HTTPSConnection.

3.2版本的變化:context and check_hostname被補充。

     1.21  urllib.request.FileHandler

開啟本地檔案

     1.22  urllib.request.DataHandler

開放資料的url

     1.23  urllib.request.FTPHandler

開放的FTP url

     1.24 urllib.request.CacheFTPHandler

開啟FTP url,保持開啟的FTP連線快取來減少延遲

    1.25  urllib.request.UnknownHandler

全方位類處理未知的url。

    1.26 urllib.request.HTTPErrorProcessor

HTTP錯誤響應過程。