web-dev-qa-db-ja.com

urllib2.urlopen:インターネットに接続せずにスクリプトを開始すると、「名前またはサービスが不明です」が持続する

以下に、2秒ごとにGoogleへの接続を開くこの単純な最小限の「動作」の例を示します。インターネット接続が機能しているときにこのスクリプトを実行すると、成功メッセージが表示され、切断すると失敗メッセージが表示され、再接続すると再び成功メッセージが表示されます。ここまでは順調ですね。

ただし、インターネットが切断されているときにスクリプトを開始すると、失敗メッセージが表示され、後で接続すると、成功メッセージが表示されません。エラーが発生し続けます:

urlopenエラー[Errno-2]名前またはサービスが不明

何が起こっている?

import urllib2, time

while True:
    try:
        print('Trying')
        response = urllib2.urlopen('http://www.google.com')
        print('Success')
        time.sleep(2)
    except Exception, e:
        print('Fail ' + str(e))
        time.sleep(2)
15
Ben Ruijl

これは、DNS名「www.google.com」を解決できないために発生します。インターネット接続がない場合、DNSサーバーに到達してこのエントリを解決できない可能性があります。

初めてあなたの質問を読み間違えたようです。 Linuxでの動作は、glibcの特殊性です。ロード時に「/etc/resolv.conf」を1回だけ読み取ります。 glibcは、res_init()関数を介して「/etc/resolv.conf」を強制的に再読み取りすることができます。

1つの解決策は、res_init()関数をラップし、getaddrinfo()urllib2.urlopen()によって間接的に使用される)を呼び出す前に呼び出すことです。

次のことを試してみてください(Linuxを使用していると仮定します)。

_import ctypes
libc = ctypes.cdll.LoadLibrary('libc.so.6')
res_init = libc.__res_init
# ...
res_init()
response = urllib2.urlopen('http://www.google.com')
_

もちろん、これは、「/ etc /resolv.conf」が変更されるまで待ってからres_init()を呼び出すことで最適化できます。

別の解決策は、例えばをインストールすることです。 nscd(ネームサービスキャッシュデーモン)。

16
insecure

私にとって、それはプロキシの問題でした。 urllib.requestをインポートする前に以下を実行すると役に立ちました

import os
os.environ['http_proxy']=''
response = urllib.request.urlopen('http://www.google.com')
0