2010-06-02 13 views
17

Sto provando a scrivere una funzione per postare i dati del modulo e salvare le informazioni sui cookie restituiti in un file in modo che la prossima volta che la pagina venga visitata, le informazioni sui cookie siano inviato al server (cioè normale comportamento del browser).Python forma il POST usando urllib2 (anche la domanda sul salvataggio/utilizzo dei cookie)

Ho scritto questo relativamente facilmente in C++ usando curlib, ma ho passato quasi un giorno intero a scrivere questo in Python, usando urllib2 - e ancora senza successo.

Questo è quello che ho finora:

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() 

Quando si tenta di accedere, passo il nome utente corretto e pwd ,. tuttavia l'accesso non riesce e nessun dato sui cookie viene salvato.

Le mie due domande sono:

  • qualcuno può vedere cosa è sbagliato con la funzione di login(), e come posso risolvere il problema?
  • come posso modificare la funzione get_page() per utilizzare qualsiasi informazione sui cookie che ho salvato?

risposta

29

Ci sono alcuni problemi con il codice che hai postato. In genere ti consigliamo di creare un dispositivo di apertura personalizzato in grado di gestire reindirizzamenti, https e così via, altrimenti ti troverai nei guai. Per quanto riguarda i cookie stessi, è necessario chiamare il carico e salvare i metodi su cookiejar e utilizzare una delle sottoclassi, ad esempio MozillaCookieJar o LWPCookieJar.

Ecco una lezione che ho scritto per accedere a Facebook, quando stavo giocando a giochi web stupidi. L'ho appena modificato per usare un cookiejar basato su file, piuttosto che uno in-memory.

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) 

Dopo aver impostato il tuo nome utente e password, si dovrebbe vedere un file, facebook.cookies, con i cookie in esso. In pratica probabilmente vorrai modificarlo per verificare se hai un cookie attivo e usarlo, quindi accedi di nuovo se l'accesso è negato.

+0

+1 per lo snippet di codice. Il tuo codice è molto più ordinato e pulito del mio (beh, sto solo iniziando a imparare a essere un Pitonista!). Ho letto una rilettura del tuo post - ci sono due cose che non mi sono chiare. 1). Non capisco perché devi chiamare loginToFacebook() due volte. Sembra che il cookie verrà impostato ogni volta che viene richiamato l'id del metodo loginToFacebook(). Potresti per favore chiarire ?. 2). puoi dare delle linee guida su come verificare se esiste un cookie ACTIVE? – morpheous

+1

Con i login basati su cookie, il server ti assegna prima un cookie, * quindi * accedi. Se tenti di rimuovere uno degli accessi, scoprirai di non aver effettuato l'accesso - FB ha controllato la tua risposta, vista che non hai un cookie e reindirizzato alla pagina di accesso.Un modo più chiaro sarebbe quello di sostituire la prima chiamata con una per ottenere la prima pagina dell'FB come 'def getFBCookie (self): self.opener.open ('https://www.facebook.com/')' che sarebbe fare la stessa cosa E sì, è un bel codice. Questo richiede un po 'più tempo in anticipo, ma ripaga quando è necessario leggerlo in seguito, o riutilizzarlo :) –

2

Se hai difficoltà a far funzionare le tue richieste POST (come se avessi con un modulo di accesso), è sicuramente necessario installare rapidamente l'estensione delle intestazioni HTTP in tempo reale su Firefox (http://livehttpheaders.mozdev.org /index.html). Questa piccola estensione può, tra le altre cose, mostrare i dati esatti POST che vengono inviati quando si esegue l'accesso manualmente.

Nel mio caso, avevo sbattuto la testa contro il muro per ore perché il sito ha insistito su un campo in più con 'action = login' (doh!).

1

Si prega di utilizzare ignore_discard e ignore_expires mentre salva cookie, nel mio caso ha salvato OK.

self.cj.save(cookie_file, ignore_discard=True, ignore_expires=True) 
Problemi correlati