web-dev-qa-db-ja.com

pre Python 2.6バージョンでのurllib2.urlopen()のタイムアウト

rllib2ドキュメント は、timeoutパラメータがPython 2.6に追加されたことを示しています。残念ながら私のコードベースはPython 2.5および2.4プラットフォームで実行されています。

タイムアウトをシミュレートする別の方法はありますか?私がやりたいのは、コードが一定時間リモートサーバーと通信できるようにすることだけです。

おそらく、代替の組み込みライブラリはありますか? (pycurlのようなサードパーティをインストールしたくない)

28
rubayeet

以下を使用して、すべてのソケット操作(HTTP要求を含む)のグローバルタイムアウトを設定できます。

socket.setdefaulttimeout()

このような:

import urllib2
import socket
socket.setdefaulttimeout(30)
f = urllib2.urlopen('http://www.python.org/')

この場合、urllib2リクエストは30秒後にタイムアウトし、ソケット例外をスローします。 (これはPython 2.3)で追加されました

57
Corey Goldberg

かなりの苛立ちで、urllib2.HTTPHandlerが使用するhttplib.HTTPConnectionクラスをオーバーライドできます。

def urlopen_with_timeout(url, data=None, timeout=None):

  # Create these two helper classes fresh each time, since
  # timeout needs to be in the closure.
  class TimeoutHTTPConnection(httplib.HTTPConnection):
    def connect(self):
      """Connect to the Host and port specified in __init__."""
      msg = "getaddrinfo returns an empty list"
      for res in socket.getaddrinfo(self.Host, self.port, 0,
                      socket.SOCK_STREAM): 
        af, socktype, proto, canonname, sa = res
        try:
          self.sock = socket.socket(af, socktype, proto)
          if timeout is not None:
            self.sock.settimeout(timeout)
          if self.debuglevel > 0:
            print "connect: (%s, %s)" % (self.Host, self.port)
          self.sock.connect(sa)
        except socket.error, msg:
          if self.debuglevel > 0:
            print 'connect fail:', (self.Host, self.port)
          if self.sock:
            self.sock.close()
          self.sock = None
          continue
        break
      if not self.sock:
        raise socket.error, msg

  class TimeoutHTTPHandler(urllib2.HTTPHandler):
    http_request = urllib2.AbstractHTTPHandler.do_request_
    def http_open(self, req):
      return self.do_open(TimeoutHTTPConnection, req)

  opener = urllib2.build_opener(TimeoutHTTPHandler)
  opener.open(url, data)
4
Philip Z

Urllib2に 2.6メンテナンスブランチからの変更 でパッチを適用(またはローカルバージョンをデプロイ)するのが最善の選択だと思います。

ファイルは/usr/lib/python2.4/urllib2.pyにある必要があります(Linuxおよび2.4の場合)

2
Kimvais

標準ライブラリのhttplibを使用しています。非常に単純なAPIがありますが、ご想像のとおりhttpのみを処理します。 IIUC urllibは、httplibを使用してhttpのものを実装します。

1
Kris Walker

タイムアウトは2か所で設定する必要があります。

import urllib2
import socket

socket.setdefaulttimeout(30)
f = urllib2.urlopen('http://www.python.org/', timeout=30)
1

ええと、2.4と2.6のどちらでもタイムアウトが処理される方法は同じです。 2.6でurllib2.pyファイルを開くと、タイムアウトとして追加の引数を取り、前述のようにsocket.defaulttimeout()メソッドを使用して処理することがわかります。

したがって、その場合はurllib2.pyを更新する必要はありません。

0
Konark Modi