2013-10-07 51 views
1

我有一小段代碼,如下圖所示,使用的urllib2 ..我試圖將其轉換爲pycurl從pycurl代理支持中獲益。 pycurl的轉換後的代碼顯示在原始代碼之後..我想知道如何將urllib.urlopen(req).read()更改爲pycurl中類似的東西..也許使用類似strictIO的東西?從urllib2的遷移到pycurl

的urllib2代碼:

URL = 'URL' 
UN = 'UN' 
PWD = 'PWD' 
HEADERS = { 'Accept': 'application/json', 
      'Connection': 'Keep-Alive', 
      'Accept-Encoding' : 'gzip', 
      'Authorization' : 'Basic %s' % base64.encodestring('%s:%s' % (UN, PWD)) } 
req = urllib2.Request(URL, headers=HEADERS) 
    response = urllib2.urlopen(req, timeout=(KEEP_ALIVE)) 
    # header - print response.info() 
    decompressor = zlib.decompressobj(16+zlib.MAX_WBITS) 
    remainder = '' 
    while True: 
     tmp = decompressor.decompress(response.read(CHUNKSIZE)) 

的pycurl轉換與代理支持:

URL = 'URL' 
UN = 'UN' 
PWD = 'PWD' 
HEADERS = [ 'Accept : application/json', 
      'Connection : Keep-Alive', 
      'Accept-Encoding : gzip', 
      'Authorization : Basic %s' % base64.encodestring('%s:%s' % (UN, PWD)) ] 
req = pycurl.Curl() 
    req.setopt(pycurl.CONNECTTIMEOUT,KEEP_ALIVE) 
    req.setopt(pycurl.HTTPHEADER, HEADERS) 
    req.setopt(pycurl.TIMEOUT, 1+KEEP_ALIVE) 
    req.setopt(pycurl.PROXY, 'http://my-proxy') 
    req.setopt(pycurl.PROXYPORT, 8080) 
    req.setopt(pycurl.PROXYUSERPWD, "proxy_access_user : proxy_access_password") 
    req.setopt(pycurl.URL , URL) 
    response = req.perform() 
    decompressor = zlib.decompressobj(16+zlib.MAX_WBITS) 
    remainder = '' 
    while True: 
     tmp = decompressor.decompress(urllib2.urlopen(req).read(CHUNKSIZE)) 

在此先感謝。

+0

@abarnert謝謝..我會編輯這個問題。 – tkyass

回答

2

urllib2不同,它會返回一個可用於獲取數據的對象,curl需要您傳遞一個可用於存儲數據的對象。

簡單的方式做到這一點,在大多數例子中,是通過一個文件對象爲WRITEDATA選項。你可能會認爲你可以只通過一個StringIO這裏,像這樣:

# ... 
s = StringIO.StringIO() 
req.setopt(pycurl.WRITEDATA, s) 
req.perform() 
data = s.getvalue() 

不幸的是,這是行不通的,因爲文件對象必須是一個真正的文件(或至少一些與一個C級文件描述符),並且StringIO不符合條件。


你當然可以使用NamedTemporaryFile,但如果你希望保留在內存中,或更好,而不是將其存儲在內存磁盤上的文件,只是處理它在飛行 - 這將無濟於事。


的解決方案是使用WRITEFUNCTION選項,而不是:

s = StringIO.StringIO() 
req.setopt(pycurl.WRITEFUNCTION, s.write) 
req.perform() 
data = s.getvalue() 

正如你所看到的,你可以如果使用StringIO這個希望,事實上,這也正是該curlpycurl對象文檔做,但它不是真正的簡化了的東西積累的字符串(如將它們放在一個列表和''.join -ing他們,甚至只是他們串聯到一個字符串)的任何其他方式太多了。

注意,我聯繫到C級libcurl文檔,而不是pycurl文檔,因爲pycurl的文檔基本上只是說:‘FOO做同樣的事情CURLOPT_FOO’(即使有差異,喜歡這樣的事實您的WRITEFUNCTION未獲取大小,nmemb和userdata參數)。


如果你想流式傳輸數據呢?只需使用WRITEFUNCTION即可累積和處理它。您不會自己編寫循環,但curl將在內部循環並驅動該過程。例如:

z = zlib.decompressobj() 
s = [] 
def handle(chunk): 
    s.append(z.decompress(chunk)) 
    return len(chunk) 
req.setopt(pycurl.WRITEFUNCTION, handle) 
req.perform() 
s.append(z.flush()) 
data = ''.join(s) 

curl將調用函數一次每個數據塊它檢索,所以整個環路req.perform()調用中發生。(它也可能在最後再次調用它0字節,所以請確保你的回調函數可以處理該問題。我認爲z.decompress可以,但你可能想驗證一下。)

有一些方法可以限制每次寫入,放棄中間的下載,將頭部作爲寫入的一部分而不是單獨寫入,等等,但通常情況下,您不需要觸摸它們。