2010-06-02 4 views
17

J'essaye d'écrire une fonction pour poster des données de formulaire et enregistrer les informations de cookie retournées dans un fichier de sorte que la prochaine fois que la page est visitée, les informations cookie sont envoyé au serveur (comportement normal du navigateur). J'ai écrit ceci relativement facilement en C++ en utilisant curlib, mais j'ai passé presque toute une journée à essayer d'écrire ceci en Python, en utilisant urllib2 - et toujours pas de succès.Python formulaire POST en utilisant urllib2 (également question sur la sauvegarde/utilisation de cookies)

C'est ce que j'ai jusqu'à présent:

import urllib, urllib2 
import logging 

# the path and filename to save your cookies in 
COOKIEFILE = 'cookies.lwp' 

cj = None 
ClientCookie = None 
cookielib = None 


logger = logging.getLogger(__name__) 

# Let's see if cookielib is available 
try: 
    import cookielib 
except ImportError: 
    logger.debug('importing cookielib failed. Trying ClientCookie') 
    try: 
     import ClientCookie 
    except ImportError: 
     logger.debug('ClientCookie isn\'t available either') 
     urlopen = urllib2.urlopen 
     Request = urllib2.Request 
    else: 
     logger.debug('imported ClientCookie succesfully') 
     urlopen = ClientCookie.urlopen 
     Request = ClientCookie.Request 
     cj = ClientCookie.LWPCookieJar() 

else: 
    logger.debug('Successfully imported cookielib') 
    urlopen = urllib2.urlopen 
    Request = urllib2.Request 

    # This is a subclass of FileCookieJar 
    # that has useful load and save methods 
    cj = cookielib.LWPCookieJar() 


login_params = {'name': 'anon', 'password': 'pass' } 

def login(theurl, login_params): 
    init_cookies(); 

    data = urllib.urlencode(login_params) 
    txheaders = {'User-agent' : 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'} 

    try: 
    # create a request object 
    req = Request(theurl, data, txheaders) 

    # and open it to return a handle on the url 
    handle = urlopen(req) 

    except IOError, e: 
    log.debug('Failed to open "%s".' % theurl) 
    if hasattr(e, 'code'): 
     log.debug('Failed with error code - %s.' % e.code) 
    elif hasattr(e, 'reason'): 
     log.debug("The error object has the following 'reason' attribute :"+e.reason) 
     sys.exit() 

    else: 

    if cj is None: 
     log.debug('We don\'t have a cookie library available - sorry.') 
    else: 
     print 'These are the cookies we have received so far :' 
     for index, cookie in enumerate(cj): 
     print index, ' : ', cookie 

     # save the cookies again 
     cj.save(COOKIEFILE) 

     #return the data 
     return handle.read() 



# FIXME: I need to fix this so that it takes into account any cookie data we may have stored 
    def get_page(*args, **query): 
    if len(args) != 1: 
     raise ValueError(
      "post_page() takes exactly 1 argument (%d given)" % len(args) 
     ) 
    url = args[0] 
    query = urllib.urlencode(list(query.iteritems())) 
    if not url.endswith('/') and query: 
     url += '/' 
    if query: 
     url += "?" + query 
    resource = urllib.urlopen(url) 
    logger.debug('GET url "%s" => "%s", code %d' % (url, 
                resource.url, 
                resource.code)) 
    return resource.read() 

Lorsque je tente de vous connecter, je passe le nom d'utilisateur et ,. PWD cependant, la connexion échoue et aucune donnée de cookie n'est enregistrée.

Mes deux questions sont:

  • quelqu'un peut-il voir ce qui ne va pas avec la fonction de connexion(), et comment puis-je résoudre ce problème?
  • comment puis-je modifier la fonction get_page() pour utiliser les informations de cookie que j'ai enregistrées?

Répondre

29

Il y a pas mal de problèmes avec le code que vous avez posté. En règle générale, vous devez créer un programme d'ouverture personnalisé qui peut gérer les redirections, https, etc., sinon vous rencontrerez des problèmes. En ce qui concerne les cookies eux-mêmes, vous devez appeler le chargement et enregistrer les méthodes sur votre cookiejar, et utiliser l'une des sous-classes, telles que MozillaCookieJar ou LWPCookieJar.

Voici une classe que j'ai écrite pour me connecter à Facebook, alors que je jouais à des jeux web idiots. Je l'ai juste modifié pour utiliser un cookiejar basé sur un fichier, plutôt qu'un cookie en mémoire.

import cookielib 
import os 
import urllib 
import urllib2 

# set these to whatever your fb account is 
fb_username = "[email protected]" 
fb_password = "secretpassword" 

cookie_filename = "facebook.cookies" 

class WebGamePlayer(object): 

    def __init__(self, login, password): 
     """ Start up... """ 
     self.login = login 
     self.password = password 

     self.cj = cookielib.MozillaCookieJar(cookie_filename) 
     if os.access(cookie_filename, os.F_OK): 
      self.cj.load() 
     self.opener = urllib2.build_opener(
      urllib2.HTTPRedirectHandler(), 
      urllib2.HTTPHandler(debuglevel=0), 
      urllib2.HTTPSHandler(debuglevel=0), 
      urllib2.HTTPCookieProcessor(self.cj) 
     ) 
     self.opener.addheaders = [ 
      ('User-agent', ('Mozilla/4.0 (compatible; MSIE 6.0; ' 
          'Windows NT 5.2; .NET CLR 1.1.4322)')) 
     ] 

     # need this twice - once to set cookies, once to log in... 
     self.loginToFacebook() 
     self.loginToFacebook() 

     self.cj.save() 

    def loginToFacebook(self): 
     """ 
     Handle login. This should populate our cookie jar. 
     """ 
     login_data = urllib.urlencode({ 
      'email' : self.login, 
      'pass' : self.password, 
     }) 
     response = self.opener.open("https://login.facebook.com/login.php", login_data) 
     return ''.join(response.readlines()) 

test = WebGamePlayer(fb_username, fb_password) 

Une fois que vous avez défini votre nom d'utilisateur et mot de passe, vous devriez voir un fichier, facebook.cookies, avec vos cookies en elle. En pratique, vous voudrez probablement le modifier pour vérifier si vous avez un cookie actif et l'utiliser, puis vous reconnecter si l'accès est refusé.

+0

+1 pour l'extrait de code. Votre code est tellement plus propre et net que le mien (eh bien je commence juste à apprendre à être un Pythonista!;) J'ai lu et relu votre message - il y a deux choses qui ne me sont pas claires. 1). Je ne comprends pas pourquoi vous devez appeler loginToFacebook() deux fois. Il semble que le cookie sera défini chaque fois que l'identifiant de la méthode loginToFacebook() est invoqué. Pourriez-vous clarifier s'il vous plaît? 2). pouvez-vous donner des directives sur la façon de vérifier si un cookie ACTIVE existe? – morpheous

+1

Avec les connexions basées sur les cookies, le serveur vous attribue d'abord un cookie, * puis * vous connectez. Si vous essayez de supprimer l'une des connexions, vous constaterez que vous n'êtes pas connecté - FB a vérifié votre réponse, vu que vous n'avez pas de cookie et que vous êtes redirigé vers la page de connexion.Un moyen plus clair serait de remplacer le premier appel par un pour obtenir la page d'accueil du FB comme 'def getFBCookie (self): self.opener.open ('https://www.facebook.com/')' qui serait faire la même chose. Et oui, c'est un code assez soigné. Cela prend un peu plus de temps à l'avance, mais paye quand vous avez besoin de le lire plus tard, ou de le réutiliser :) –

2

Si vous avez du mal à faire fonctionner vos requêtes POST (comme je l'ai fait avec un formulaire de connexion), il vaut vraiment la peine d'installer rapidement l'extension des en-têtes HTTP Live sur Firefox (http://livehttpheaders.mozdev.org /index.html). Cette petite extension peut, entre autres choses, vous montrer les données POST exactes qui sont envoyées lorsque vous vous connectez manuellement.

Dans mon cas, je me suis cogné la tête contre le mur pendant des heures parce que le site insistait sur un champ supplémentaire avec 'action = login' (doh!).

1

Veuillez utiliser ignore_discard et ignore_expires lors de la sauvegarde du cookie, dans le cas de la mienne, il a enregistré OK.

self.cj.save(cookie_file, ignore_discard=True, ignore_expires=True) 
Questions connexes