6

给定一个标准urllib.request对象,这样检索:

req = urllib.urlopen('http://example.com')

如果我通过 读取其内容req.read(),则请求对象将为空。

然而,与普通的类文件对象不同,请求对象没有seek方法,因为我确信这是极好的原因。

但是,就我而言,我有一个函数,我希望它对请求做出某些确定,然后“安然无恙地”返回该请求,以便可以再次读取它。

我知道一种选择是重新请求它。但我希望能够避免对相同的 url 和内容发出多个 HTTP 请求。

我能想到的唯一其他选择是让函数返回提取的内容和请求对象的元组,并理解调用此函数的任何内容都必须以这种方式获取内容。

那是我唯一的选择吗?

4

2 回答 2

3

将缓存委托给一个StringIO对象(代码未经测试,只是为了给出想法):

import urllib
from io import StringIO


class CachedRequest(object):
    def __init__(self, url):
        self._request = urllib.urlopen(url)
        self._content = None

    def __getattr__(self, attr):
        # if attr is not defined in CachedRequest, then get it from
        # the request object.
        return getattr(self._request, attr)

    def read(self):
        if self._content is None:
            content = self._request.read()
            self._content = StringIO()
            self._content.write(content)
            self._content.seek(0)
            return content
        else:
            return self._content.read()

    def seek(self, i):
        self._content.seek(i)

如果代码实际上需要一个真实的Request对象(即isinstance检查类型的调用),那么子类Request,你甚至不必实现__getattr__.

请注意,函数可能会检查确切的类(在这种情况下,您不能什么都不做),或者,如果它是用 C 编写的,则使用 C/API 调用来调用方法(在这种情况下,被覆盖的方法不会是称为)。

于 2013-04-17T18:47:37.903 回答
2

urllib2.Request创建一个使用 acStringIO.StringIO来保存读取的内容的子类。然后你可以实施seek等等。实际上你可以只使用一个字符串,但这会更多的工作。

于 2013-04-17T18:45:24.300 回答