2010-01-26 59 views
0

我正在製作一個python URL抓取程序。對於我而言,我希望它真的快超時,所以我超時正確的,因爲它應該做urllib2超時但不關閉套接字連接

urllib2.urlopen("http://.../", timeout=2)

當然。但是,它不打擾關閉到服務器的連接,所以服務器認爲客戶端仍然連接。如何讓urllib2在超時後關閉連接?

運行gc.collect()不起作用,如果我無法幫助,我不想使用httplib。

我能得到的最接近的是:第一次嘗試會超時。服務器報告連接關閉只是作爲第二次嘗試超時。然後,服務器報告連接關閉只是作爲第三次嘗試超時。無限廣告。

非常感謝。

回答

2

我懷疑套接字仍然在棧幀中打開。當Python引發異常時,它會存儲堆棧幀,以便調試器和其他工具可以查看堆棧並反省值。由於歷史原因,現在爲了向後兼容,堆棧信息在sys(參見sys.exc_info(),sys.exc_type和其他)中存儲(以每個線程爲基礎)。這是Python 3.0中已被刪除的內容之一。

這對你意味着什麼是堆棧還活着,並引用。這個棧包含了一些具有開放套接字的函數的本地數據。這就是套接字尚未關閉的原因。只有當堆棧跟蹤被移除時,所有內容纔會被刪除。

爲了測試是否是這樣的情況下,插入類似

try: 
    1/0 
except ZeroDivisionError: 
    pass 

在except從句。這是用其他方法替換當前異常的快速方法。

+0

嗯!一個非常有趣的想法。謝謝,但它不工作;不過,我從來沒有這樣想過。 我認爲對於我的項目來說,我的整個推理只是有點太過分。對我而言,最好不要依賴於此,而只是終止服務器上的重複連接。 – Michael 2010-01-26 06:19:21

0

這是一個黑客,但下面的代碼工程。如果請求在另一個函數中,並且它不引發異常,那麼套接字始終關閉。

def _fetch(self, url): 
    try: 
     return urllib2.urlopen(urllib2.Request(url), timeout=5).read() 
    except urllib2.URLError, e: 
     if isinstance(e.reason, socket.timeout): 
      return None 
     else: 
      raise e 

def fetch(self, url): 
    x = None 
    while x is None: 
     x = self._fetch(url) 
     print "Timeout" 
    return x 

是否有人有更好的方法?