<span id="7ztzv"></span>
<sub id="7ztzv"></sub>

<span id="7ztzv"></span><form id="7ztzv"></form>

<span id="7ztzv"></span>

        <address id="7ztzv"></address>

            11.9. 全部放在一起

            你已經看到了構造一個智能的 HTTP web 客戶端的所有片斷。現在讓我們看看如何將它們整合到一起。

            例 11.17. openanything 函數

            這個函數定義在 openanything.py 中。

            
            def openAnything(source, etag=None, lastmodified=None, agent=USER_AGENT):
                # non-HTTP code omitted for brevity
                if urlparse.urlparse(source)[0] == 'http':                                       1
                    # open URL with urllib2                                                     
                    request = urllib2.Request(source)                                           
                    request.add_header('User-Agent', agent)                                      2
                    if etag:                                                                    
                        request.add_header('If-None-Match', etag)                                3
                    if lastmodified:                                                            
                        request.add_header('If-Modified-Since', lastmodified)                    4
                    request.add_header('Accept-encoding', 'gzip')                                5
                    opener = urllib2.build_opener(SmartRedirectHandler(), DefaultErrorHandler()) 6
                    return opener.open(request)                                                  7
            
            1 urlparse 是一個解析 URL 的便捷的工具模塊。它的主要函數也叫 urlparse,接受一個 URL 并將其拆分為 tuple (scheme (協議), domain (域名), path (路徑), params (參數), query string parameters (請求字符串參數), fragment identifier (片段效驗符))。當然,你唯一需要注意的就是 scheme,確認你處理的是一個 HTTP URL (urllib2 才能處理)。
            2 通過調用函數使用 User-Agent 向 HTTP 服務器確定你的身份。如果沒有 User-Agent 被指定,你會使用一個默認的,就是定義在早期的 openanything.py 模塊中的那個。你從來不會使用到默認的定義在 urllib2 中的那個。
            3 如果給出了 ETag,要在 If-None-Match 頭信息中發送它。
            4 如果給出了最近修改日期,要在 If-Modified-Since 頭信息中發送它。
            5 如果可能要告訴服務器你要獲取壓縮數據。
            6 使用兩個 自定義 URL 處理器創建一個 URL 開啟器:SmartRedirectHandler 終于處理 301302 重定向,而 DefaultErrorHandler 用于處理 304, 404 以及其它的錯誤條件。
            7 就是這樣!打開 URL 并返回一個類文件對象給調用者。

            例 11.18. fetch 函數

            這個函數定義在 openanything.py 中。

            
            def fetch(source, etag=None, last_modified=None, agent=USER_AGENT):  
                '''Fetch data and metadata from a URL, file, stream, or string'''
                result = {}                                                      
                f = openAnything(source, etag, last_modified, agent)              1
                result['data'] = f.read()                                         2
                if hasattr(f, 'headers'):                                        
                    # save ETag, if the server sent one                          
                    result['etag'] = f.headers.get('ETag')                        3
                    # save Last-Modified header, if the server sent one          
                    result['lastmodified'] = f.headers.get('Last-Modified')       4
                    if f.headers.get('content-encoding', '') == 'gzip':           5
                        # data came back gzip-compressed, decompress it          
                        result['data'] = gzip.GzipFile(fileobj=StringIO(result['data']])).read()
                if hasattr(f, 'url'):                                             6
                    result['url'] = f.url                                        
                    result['status'] = 200                                       
                if hasattr(f, 'status'):                                          7
                    result['status'] = f.status                                  
                f.close()                                                        
                return result                                                    
            
            1 首先,你用 URL、ETag hash、Last-Modified 日期和 User-Agent 調用 openAnything 函數。
            2 讀取從服務器返回的真實數據。這可能是被壓縮的;如果是,將在后面進行解壓縮。
            3 保存從服務器返回的 ETag hash,這樣主調程序下一次就能把它傳遞給你,然后再傳遞給 openAnything,放到 If-None-Match 頭信息里發送給遠程服務器。
            4 也要保存 Last-Modified 數據。
            5 如果服務器說它發送的是壓縮數據,就執行解壓縮。
            6 如果你的服務器返回一個 URL 就保存它,并在查明之前假定狀態代碼為 200
            7 如果其中一個自定義 URL 處理器捕獲了一個狀態代碼,也要保存下來。

            例 11.19. 使用 openanything.py

            >>> import openanything
            >>> useragent = 'MyHTTPWebServicesApp/1.0'
            >>> url = 'http://diveintopython.org/redir/example301.xml'
            >>> params = openanything.fetch(url, agent=useragent)              1
            >>> params                                                         2
            {'url': 'http://diveintomark.org/xml/atom.xml', 
            'lastmodified': 'Thu, 15 Apr 2004 19:45:21 GMT', 
            'etag': '"e842a-3e53-55d97640"', 
            'status': 301,
            'data': '<?xml version="1.0" encoding="iso-8859-1"?>
            <feed version="0.3"
            <-- rest of data omitted for brevity -->'}
            >>> if params['status'] == 301:                                    3
            ...     url = params['url']
            >>> newparams = openanything.fetch(
            ...     url, params['etag'], params['lastmodified'], useragent)    4
            >>> newparams
            {'url': 'http://diveintomark.org/xml/atom.xml', 
            'lastmodified': None, 
            'etag': '"e842a-3e53-55d97640"', 
            'status': 304,
            'data': ''}                                                        5
            
            1 第一次獲取資源時,你沒有 ETag hash 或 Last-Modified 日期,所以你不用使用這些參數。 (它們是可選參數。)
            2 你獲得了一個 dictionary,它包括幾個有用的頭信息、HTTP 狀態代碼和從服務器返回的真實數據。openanything 在內部處理 gzip 壓縮;在本級別上你不必關心它。
            3 如果你得到一個 301 狀態代碼,表示是個永久重定向,你需要把你的 URL 更新為新地址。
            4 第二次獲取相同的資源時,你已經從以往獲得了各種信息:URL (可能被更新了)、從上一次訪問獲得的 ETag、從上一次訪問獲得的 Last-Modified 日期,當然還有 User-Agent
            5 你重新獲取了這個 dictionary,但是數據沒有改變,所以你得到了一個 304 狀態代碼而沒有數據。
            <span id="7ztzv"></span>
            <sub id="7ztzv"></sub>

            <span id="7ztzv"></span><form id="7ztzv"></form>

            <span id="7ztzv"></span>

                  <address id="7ztzv"></address>

                      亚洲欧美在线