2010-06-02 11 views
17

Estoy tratando de escribir una función para publicar datos de formularios y guardar información de cookies en un archivo para que la próxima vez que se visite la página, la información de cookies enviado al servidor (es decir, comportamiento normal del navegador).Python forma POST utilizando urllib2 (también pregunta sobre guardar/usar cookies)

Escribí esto de manera relativamente fácil en C++ usando curlib, pero he pasado casi un día entero tratando de escribir esto en Python, usando urllib2, y todavía no tuve éxito.

Esto es lo que tengo hasta ahora:

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

Cuando intento iniciar sesión, que paso por el nombre de usuario correcto y pwd ,. sin embargo, el inicio de sesión falla y no se guardan datos de cookies.

Mis dos preguntas son:

  • puede alguien ver cuál es incorrecto con la función de inicio de sesión(), y cómo puedo solucionarlo?
  • ¿cómo puedo modificar la función get_page() para hacer uso de cualquier información de cookie que haya guardado?

Respuesta

29

Existen bastantes problemas con el código que ha publicado. Por lo general, querrá construir un abridor personalizado que pueda manejar redirecciones, https, etc. De lo contrario, se encontrará con problemas. En lo que a las propias galletas es así, es necesario llamar a la carga y guardar métodos en su cookiejar, y utilizar una de las subclases, como MozillaCookieJar o LWPCookieJar.

Aquí es una clase que escribí para iniciar sesión en Facebook, cuando yo estaba jugando juegos en red tontas. Acabo de modificarlo para utilizar un archivo basado en cookiejar, en lugar de uno en la memoria.

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) 

Después de configurar su nombre de usuario y contraseña, debería ver un archivo, facebook.cookies, con sus cookies en el mismo. En la práctica, es probable que desee modificarlo para verificar si tiene una cookie activa y usarla, y luego iniciar sesión de nuevo si se deniega el acceso.

+0

+1 para el fragmento de código. Tu código es mucho más limpio y más limpio que el mío (¡bueno, estoy empezando a aprender a ser un Pythonista!;) He leído y releído tu publicación, hay dos cosas que no me quedan claras. 1). No entiendo por qué tienes que llamar a loginToFacebook() dos veces. Parece que la cookie se establecerá cada vez que se invoque el método loginToFacebook(). ¿Podrías aclararlo por favor?. 2). ¿Puede dar pautas sobre cómo verificar si existe una cookie ACTIVE? – morpheous

+1

Con inicios de sesión basados ​​en cookies, el servidor primero le asigna una cookie, * luego * inicia sesión. Si intenta eliminar uno de los inicios de sesión, encontrará que no ha iniciado sesión - FB ha verificado su respuesta, visto que no tienes una cookie y te redirigió a la página de inicio de sesión.Una forma más clara sería reemplazar la primera llamada por una para obtener la página principal de FB como 'def getFBCookie (self): self.opener.open ('https://www.facebook.com/')' que sería hacer la misma cosa. Y sí, es un código bastante bueno. Eso requiere un poco más de tiempo por adelantado, pero vale la pena cuando necesitas leerlo más tarde o reutilizarlo :) –

2

Si está teniendo dificultades para hacer que sus solicitudes POST funcionen (como si tuviera un formulario de inicio de sesión), definitivamente vale la pena instalar rápidamente la extensión de encabezados de Live HTTP en Firefox (http://livehttpheaders.mozdev.org /index.html). Esta pequeña extensión puede, entre otras cosas, mostrarle los datos POST exactos que se envían cuando inicia sesión manualmente.

En mi caso, me había golpeado la cabeza contra la pared durante horas porque el sitio insistía en un campo adicional con 'action = login' (doh!).

1

Por favor, usando ignore_discard y ignore_expires mientras guarda la cookie, en mi caso se guardó OK.

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