2012-10-05 12 views
54

Estoy utilizando el módulo requests (versión 0.10.0 con Python 2.5). He descubierto cómo enviar datos a un formulario de inicio de sesión en un sitio web y recuperar la clave de sesión, pero no veo una forma obvia de utilizar esta clave de sesión en solicitudes posteriores. ¿Puede alguien completar los puntos suspensivos en el siguiente código o sugerir otro enfoque?Python Solicitudes y sesiones persistentes

>>> import requests 
>>> login_data = {'formPosted':'1', 'login_email':'[email protected]', 'password':'pw'} 
>>> r = requests.post('https://localhost/login.py', login_data) 
>>> 
>>> r.text 
u'You are being redirected <a href="profilePage?_ck=1349394964">here</a>' 
>>> r.cookies 
{'session_id_myapp': '127-0-0-1-825ff22a-6ed1-453b-aebc-5d3cf2987065'} 
>>> 
>>> r2 = requests.get('https://localhost/profile_data.json', ...) 

Respuesta

113

Usted puede crear fácilmente una sesión persistente usando:

s = requests.session() 

Después de eso, continuar con sus peticiones como lo haría:

s.post('https://localhost/login.py', login_data) 
#logged in! cookies saved for future requests. 
r2 = s.get('https://localhost/profile_data.json', ...) 
#cookies sent automatically! 
#do whatever, s will keep your cookies intact :) 

Para más información sobre las sesiones: http://docs.python-requests.org/en/latest/user/advanced/#session-objects

+0

Gracias Anuj, esta es una solución perfecta. Es mucho más claro que el ejemplo en la documentación python-requests. – ChrisGuest

+2

¿Hay alguna forma de guardar la sesión en sí entre las secuencias de comandos? – Gtx

+4

Puede pickle.dump cookies de sesión a un archivo como pickle.dump (session.cookies._cookies, archivo) y pickle.load a session como sigue cookies = pickle.load (archivo) cj = requests.cookies.RequestsCookieJar() cj. _cookies = cookies y session.cookies = cj – Cyril

4

La documentación dice que get toma en un argumento opcional cookies que le permite especificar las cookies de usar:

de los documentos:

>>> url = 'http://httpbin.org/cookies' 
>>> cookies = dict(cookies_are='working') 

>>> r = requests.get(url, cookies=cookies) 
>>> r.text 
'{"cookies": {"cookies_are": "working"}}' 

http://docs.python-requests.org/en/latest/user/quickstart/#cookies

7

Compruebe hacia fuera mi respuesta en esta pregunta similar:

python: urllib2 how to send cookie with urlopen request

import urllib2 
import urllib 
from cookielib import CookieJar 

cj = CookieJar() 
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj)) 
# input-type values from the html form 
formdata = { "username" : username, "password": password, "form-id" : "1234" } 
data_encoded = urllib.urlencode(formdata) 
response = opener.open("https://page.com/login.php", data_encoded) 
content = response.read() 

EDITAR:

Veo que he recibido un voto negativo por mi respuesta, pero no hay ningún comentario que explique. Supongo que es porque me refiero a las bibliotecas urllib en lugar de requests. Lo hago porque OP pide ayuda con requests o alguien sugiere otro enfoque.

+2

No soy uno de tus votantes a la baja, pero como conjetura, es probable que muchos lectores ignoren la última frase del OP como "¿Alguien puede completar los puntos suspensivos en el siguiente código o sugerir otro enfoque? [con la biblioteca de solicitudes que implicaría más cirugía mayor para mi código que meramente rellenar las elipsis con algo más]. "- ​​pero eso es solo una suposición de mi parte. –

+2

Como OP, puedo decir que su respuesta proporciona una alternativa útil. Solo para demostrar que 'requests' ofrece una solución simple y de alto nivel para un problema que de otro modo tomaría 3 bibliotecas para implementar. – ChrisGuest

4

las otras respuestas ayudan a comprender cómo mantener una sesión de este tipo. Además, deseo proporcionar una clase que mantenga la sesión mantenida sobre diferentes ejecuciones de un script (con un archivo de caché). Esto significa que un "inicio de sesión" apropiado solo se realiza cuando es necesario (sin timout o sin sesión en el caché). También es compatible con la configuración de proxy en llamadas posteriores a 'obtener' o 'publicar'.

Se prueba con Python3.

Úselo como base para su propio código. Los siguientes fragmentos son lanzamiento con GPL v3

import pickle 
import datetime 
import os 
from urllib.parse import urlparse 
import requests  

class MyLoginSession: 
    """ 
    a class which handles and saves login sessions. It also keeps track of proxy settings. 
    It does also maintine a cache-file for restoring session data from earlier 
    script executions. 
    """ 
    def __init__(self, 
       loginUrl, 
       loginData, 
       loginTestUrl, 
       loginTestString, 
       sessionFileAppendix = '_session.dat', 
       maxSessionTimeSeconds = 30 * 60, 
       proxies = None, 
       userAgent = 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.1', 
       debug = True, 
       forceLogin = False, 
       **kwargs): 
     """ 
     save some information needed to login the session 

     you'll have to provide 'loginTestString' which will be looked for in the 
     responses html to make sure, you've properly been logged in 

     'proxies' is of format { 'https' : 'https://user:[email protected]:port', 'http' : ... 
     'loginData' will be sent as post data (dictionary of id : value). 
     'maxSessionTimeSeconds' will be used to determine when to re-login. 
     """ 
     urlData = urlparse(loginUrl) 

     self.proxies = proxies 
     self.loginData = loginData 
     self.loginUrl = loginUrl 
     self.loginTestUrl = loginTestUrl 
     self.maxSessionTime = maxSessionTimeSeconds 
     self.sessionFile = urlData.netloc + sessionFileAppendix 
     self.userAgent = userAgent 
     self.loginTestString = loginTestString 
     self.debug = debug 

     self.login(forceLogin, **kwargs) 

    def modification_date(self, filename): 
     """ 
     return last file modification date as datetime object 
     """ 
     t = os.path.getmtime(filename) 
     return datetime.datetime.fromtimestamp(t) 

    def login(self, forceLogin = False, **kwargs): 
     """ 
     login to a session. Try to read last saved session from cache file. If this fails 
     do proper login. If the last cache access was too old, also perform a proper login. 
     Always updates session cache file. 
     """ 
     wasReadFromCache = False 
     if self.debug: 
      print('loading or generating session...') 
     if os.path.exists(self.sessionFile) and not forceLogin: 
      time = self.modification_date(self.sessionFile)   

      # only load if file less than 30 minutes old 
      lastModification = (datetime.datetime.now() - time).seconds 
      if lastModification < self.maxSessionTime: 
       with open(self.sessionFile, "rb") as f: 
        self.session = pickle.load(f) 
        wasReadFromCache = True 
        if self.debug: 
         print("loaded session from cache (last access %ds ago) " 
           % lastModification) 
     if not wasReadFromCache: 
      self.session = requests.Session() 
      self.session.headers.update({'user-agent' : self.userAgent}) 
      res = self.session.post(self.loginUrl, data = self.loginData, 
            proxies = self.proxies, **kwargs) 

      if self.debug: 
       print('created new session with login') 
      self.saveSessionToCache() 

     # test login 
     res = self.session.get(self.loginTestUrl) 
     if res.text.lower().find(self.loginTestString.lower()) < 0: 
      raise Exception("could not log into provided site '%s'" 
          " (did not find successful login string)" 
          % self.loginUrl) 

    def saveSessionToCache(self): 
     """ 
     save session to a cache file 
     """ 
     # always save (to update timeout) 
     with open(self.sessionFile, "wb") as f: 
      pickle.dump(self.session, f) 
      if self.debug: 
       print('updated session cache-file %s' % self.sessionFile) 

    def retrieveContent(self, url, method = "get", postData = None, **kwargs): 
     """ 
     return the content of the url with respect to the session. 

     If 'method' is not 'get', the url will be called with 'postData' 
     as a post request. 
     """ 
     if method == 'get': 
      res = self.session.get(url , proxies = self.proxies, **kwargs) 
     else: 
      res = self.session.post(url , data = postData, proxies = self.proxies, **kwargs) 

     # the session has been updated on the server, so also update in cache 
     self.saveSessionToCache()    

     return res 

Un fragmento de código para el uso de la clase anterior puede tener este aspecto:

if __name__ == "__main__": 
    # proxies = {'https' : 'https://user:[email protected]:port', 
    #   'http' : 'http://user:[email protected]:port'} 

    loginData = {'user' : 'usr', 
       'password' : 'pwd'} 

    loginUrl = 'https://...' 
    loginTestUrl = 'https://...' 
    successStr = 'Hello Tom' 
    s = MyLoginSession(loginUrl, loginData, loginTestUrl, successStr, 
         #proxies = proxies 
         ) 

    res = s.retrieveContent('https://....') 
    print(res.text) 

    # if, for instance, login via JSON values required try this: 
    s = MyLoginSession(loginUrl, None, loginTestUrl, successStr, 
         #proxies = proxies, 
         json = loginData) 
+1

Esta es una gran respuesta, es extrañamente difícil buscar esta solución también. – duality

0

Al tratar todas las respuestas anteriores, he encontrado que el uso de RequestsCookieJar en lugar de la el CookieJar normal para las solicitudes subsiguientes solucionó mi problema.

import requests 
import json 

authUrl = 'https://whatever.com/login' 

#The subsequent url 
testUrl = 'https://whatever.com/someEndpoint' 

#Whatever you are posting 
login_data = {'formPosted':'1', 'login_email':'[email protected]', 'password':'pw'} 

#The auth token or any other data that we will recieve from the authRequest. 
token = '' 

# Post the loginRequest 
loginRequest = requests.post(authUrl,login_data) 
print loginRequest.text 

# Save the request content to your variable. In this case I needed a field called token. 
token = str(json.loads(loginRequest.content)['token']) 
print token 

# Verify successfull login 
print loginRequest.status_code 

#Create your RequestsCookieJar for your subsequent requests and add the cookie 
jar = requests.cookies.RequestsCookieJar() 
jar.set('LWSSO_COOKIE_KEY', token) 

#Execute your next request(s) with the RequestCookieJar set 
r = requests.get(testUrl, cookies=jar) 
print(r.text) 
print(r.status_code) 
0

fragmento para recuperar datos JSON, protegido por contraseña

import requests 

username = "my_user_name" 
password = "my_super_secret" 
url = "https://www.my_base_url.com" 
the_page_i_want = "/my_json_data_page" 

session = requests.Session() 
# retrieve cookie value 
resp = session.get(url+'/login') 
csrf_token = resp.cookies['csrftoken'] 
# login, add referer 
resp = session.post(url+"/login", 
        data={ 
         'username': username, 
         'password': password, 
         'csrfmiddlewaretoken': csrf_token, 
         'next': the_page_i_want, 
        }, 
        headers=dict(Referer=url+"/login")) 
print(resp.json()) 
Cuestiones relacionadas