2010-03-04 13 views
2

Je suis nouveau sur Python, alors pardonnez-moi si quelque chose me manque. J'utilise urllib.FancyURLopener pour récupérer un document Web. J'utilise urllib.FancyURLopener. Cela fonctionne correctement lorsque l'authentification est désactivée sur le serveur Web, mais échoue lorsque l'authentification est activée. Je suppose que j'ai besoin de sous-classe urllib.FancyURLopener pour remplacer les méthodes get_user_passwd() et/ou prompt_user_passwd(). Alors je l'ai fait:Problèmes Python avec FancyURLopener, 401, et "Connection: close"

class my_opener (urllib.FancyURLopener): 

    # Redefine 
    def get_user_passwd(self, host, realm, clear_cache=0): 
     print "get_user_passwd() called; host %s, realm %s" % (host, realm) 
     return ('name', 'password') 

Alors je tente d'ouvrir la page:

try: 
    opener = my_opener() 
    f = opener.open ('http://1.2.3.4/whatever.html') 
    content = f.read() 
    print "Got it: ", content 

except IOError: 
    print "Failed!" 

Je me attends FancyURLopener gérer le 401, appelez mon get_user_passwd() et relancez la demande.

Ce n'est pas le cas; Je reçois l'exception IOError lorsque j'appelle "f = opener.open()".

Wireshark me dit que la demande est envoyée, et que le serveur envoie une réponse « 401 Unauthorized » avec deux têtes d'intérêt:

WWW-Authenticate: BASIC 
Connection: close 

La connexion est alors fermée, je prends mon exception, et tout est fini.

Il échoue de la même manière même si je réessaye le "f = opener.open()" après IOError.

J'ai vérifié que ma classe my_opener() fonctionne en surchargeant la méthode http_error_401() avec un simple "print 'Got 401 error'". J'ai également essayé de surcharger la méthode prompt_user_passwd(), mais cela ne se produit pas non plus.

Je ne vois aucun moyen de spécifier de manière proactive le nom d'utilisateur et le mot de passe.

Comment puis-je demander à urllib de réessayer la demande?

Merci.

+0

juste essayé d'utiliser urllib2.HTTPBasicAuthHandler() avec la méthode add_password().Dans ce cas, le serveur ne renvoie pas 401 non autorisé; à la place, il renvoie 200 OK avec un message d'erreur. La différence: avec urllib2, la requête inclut l'en-tête "Connection: close". L'urllib.FancyURLopener n'inclut pas cet en-tête. –

Répondre

0

Je viens d'essayer votre code sur mon serveur web (nginx) et il fonctionne comme prévu:

  • Get de urllib client
  • HTTP/1.1 401 non autorisé du serveur avec en-têtes

    Connection: close 
    WWW-Authenticate: Basic realm="Restricted" 
    
  • Le client réessaie avec l'en-tête Autorisation

    Authorization: Basic <Base64encoded credentials> 
    
  • Server répond avec 200 OK + contenu

Donc je suppose que votre code est bon (je l'ai essayé avec python 2.7.1) et peut-être le serveur Web que vous essayez d'accéder ne fonctionne pas comme prévu. Voici le code testé à l'aide testsite auth de base gratuite http browserspy.dk (semble qu'ils utilisent apache - le code fonctionne comme prévu):

import urllib 

class my_opener (urllib.FancyURLopener): 

    # Redefine 
    def get_user_passwd(self, host, realm, clear_cache=0): 
     print "get_user_passwd() called; host %s, realm %s" % (host, realm) 
     return ('test', 'test') 

try: 
    opener = my_opener() 
    f = opener.open ('http://browserspy.dk/password-ok.php') 
    content = f.read() 
    print "Got it: ", content 

except IOError: 
    print "Failed!"