从urllib2迁移到pycurl

时间:2013-10-07 18:15:55

标签: python urllib2 pycurl

我有一段代码,如下所示,使用urllib2 ..我正在尝试将其转换为pycurl以受益于pycurl代理支持。转换后的pycurl代码显示在原始代码之后。我想知道如何将urllib.urlopen(req).read()更改为pycurl中类似的东西..也许使用类似strinIO的东西?

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))

提前感谢。

1 个答案:

答案 0 :(得分:2)

urllib2不同,curl返回一个可用于获取数据的对象,StringIO需要您传递一个可用于存储数据的对象。

在大多数示例中使用的简单方法是将文件对象作为WRITEDATA选项传递。你可能认为你可以在这里传递一个# ... s = StringIO.StringIO() req.setopt(pycurl.WRITEDATA, s) req.perform() data = s.getvalue() ,如下所示:

StringIO

不幸的是,这不起作用,因为文件对象必须是真实文件(或至少具有C级文件描述符的东西),并且s = StringIO.StringIO() req.setopt(pycurl.WRITEFUNCTION, s.write) req.perform() data = s.getvalue() 不符合条件。


您当然可以使用NamedTemporaryFile,但是如果您希望将文件保留在内存中,或者更好的是,不要将其存储在磁盘上的内存中,而只是在飞行中处理它 - 这无济于事。


解决方案是改为使用WRITEFUNCTION选项:

StringIO

正如您所看到的,如果您愿意,可以使用pycurl - 事实上,这正是来自''.join的{​​{3}}对象文档的内容确实 - 但它并没有真正简化任何其他积累字符串的方式(比如将它们放在列表中并libcurl - 或者只是将它们连接到字符串上)。

请注意,我链接到了C级pycurl文档,而不是pycurl文档,因为WRITEFUNCTION的文档基本上只是说“FOO与CURLOPT_FOO做同样的事情”(即使存在 差异,例如您的WRITEFUNCTION未获得size,nmemb和userdata参数这一事实。


如果您想动态传输数据怎么办?只需使用一个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()将为其检索的每个数据块调用一次函数,因此整个循环在z.decompress调用内发生。 (它也可能在最后用0字节再次调用它,所以请确保你的回调函数可以处理它。我认为{{1}}可以,但你可能想要验证它。)

有一些方法可以限制每次写入的大小,在中间中止下载,将标题作为写入的一部分而不是单独写入,等等,但通常你不需要触及那些。 / p>