2

我目前正在使用 urllib2 在 python2.7 中编写一个简单的爬虫。这是下载器类。

class Downloader:
    def __init__(self, limit = 3):
        self.limit = limit

    def downloadGet(self, url):
        request = urllib2.Request(url)
        retry = 0
        succ = False
        page = None

        while retry < self.limit:
            print "Retry: " + str(retry) + " Limit:" + str(self.limit)
            try:
                response = urllib2.urlopen(request)
                page = response.read()
                succ = True
                break
            except:
                retry += 1

        return succ, page

每个 url 都会尝试 3 次。也使用了多线程,线程代码如下:

class DownloadThread(Thread):
    def __init__(self, requestGet, limit):
        Thread.__init__(self)
        self.requestGet = requestGet
        self.downloader = Downloader(limit)

    def run(self):
        while True:
            url = self.requestGet()
            if url == None:
                break

            ret = self.download(url)
            print ret

    def download(self, url):
        # some other staff
        succ, flv = self.downloader.downloadGet(url)
        return succ

但是,在实验中,线程数设置为 5,下载器在尝试 3 次后不会停止。对于某些线程,输出甚至显示“重试:4280 限制:3”。似乎忽略了while条件。

任何帮助和建议都受到热烈欢迎。谢谢!

4

3 回答 3

5

downloadGet:中无限循环的一个可能原因limit是字符串对象。

如果limit是字符串,则在 Python 2.x中retry < self.limit产生:True

>>> retry = 4280
>>> limit = '3'
>>> retry < limit
True

检查通过的类型limit

于 2013-11-06T10:57:05.273 回答
0

如果 URL 不为空,您的代码中没有任何内容DownloadThread可以跳出 while 循环。

于 2013-11-06T10:53:58.437 回答
0

您应该以更 Pythonic 的方式定义循环:

def downloadGet(self, url):
    ...
    # do not declare retry before this
    for retry in xrange(self.limit):
        ...
        try:

编辑:

或者,您可以利用while比尝试更清楚地处理循环状态的优势break(尽管我觉得我的第一个示例不那么脆弱):

def downloadGt(self, url):
    ...
    while retry in xrange(self.limit) or succ == False:
        ...

这具有更多的自我记录的好处。

不过,我会考虑将循环重构为下载而不是下载器。像这样的东西:

class DownloadThread(Thread):
    ...
    def download(self, url):
        for retry in xrange(self.downloader.limit):
            succ, flv = self.downloader.downloadGet(url)
            if succ:
                return succ


class Downloader(object):
    ...
    def downloadGet(self, url)
        request = urllib2.Request(url)
        try:
            response = urllib2.urlopen(request)
            page = response.read()

        # always qualify your exception handlers 
        # or you may be masking errors you don't know about
        except urllib2.HTTPError:
            return False, None

        return True, page
于 2013-11-06T10:59:36.083 回答