2012-10-05 9 views
54

Używam modułu requests (wersja 0.10.0 z Pythonem 2.5). Ustaliłem, jak przesłać dane do formularza logowania na stronie internetowej i pobrać klucz sesji, ale nie widzę oczywisty sposób użycia tego klucza sesji w kolejnych żądaniach. Czy ktoś może wypełnić wielokropek w poniższym kodzie lub zaproponować inne podejście?Żądania w pythonie i sesje trwałe

>>> 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', ...) 

Odpowiedz

113

Można łatwo tworzyć trwała sesja z użyciem:

s = requests.session() 

Następnie kontynuować prośby tak jak:

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

Więcej o sesjach: http://docs.python-requests.org/en/latest/user/advanced/#session-objects

+0

Thanks Anuj, jest to idealne rozwiązanie. Jest o wiele jaśniejszy niż przykład w dokumentacji python-requests. – ChrisGuest

+2

Jakieś sposoby na zapisanie samej sesji pomiędzy uruchomieniami skryptów? – Gtx

+4

Może pliki cookie sesji pickle.dump do pliku jak pickle.dump (session.cookies._cookies, plik) i pickle.load do sesji w następujący sposób cookie = pickle.load (plik) cj = requests.cookies.RequestsCookieJar() cj. _cookies = ciasteczka i session.cookies = cj – Cyril

7

Sprawdź moje odpowiedzi w tym podobnym pytaniem:

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

EDIT:

Widzę, że dostałem awans do mojej odpowiedzi, ale bez komentarza wyjaśniającego. Zgaduję, że to dlatego, że mam na myśli biblioteki urllib zamiast requests. Robię to, ponieważ OP prosi o pomoc z requests lub ktoś sugeruje inne podejście.

+2

Nie jestem jednym z twoich użytkowników, ale jak się domyślasz, wielu czytelników prawdopodobnie glosuje ostatnie zdanie OP jako "Czy ktoś może wypełnić elipsę w kodzie poniżej lub zasugerować inne podejście [z biblioteką zleceń, która wymagałaby większej operacji na moim kodzie niż tylko wypełniania elipsy czymś innym] "- ale to tylko przypuszczenie z mojej strony. –

+2

Jako OP mogę powiedzieć, że twoja odpowiedź stanowi przydatną alternatywę. Jeśli tylko po to, aby zademonstrować, że 'request' oferuje proste i wysokopoziomowe rozwiązanie problemu, który w przeciwnym razie zaimplementowałby 3 biblioteki. – ChrisGuest

4

inne odpowiedzi pomagają zrozumieć, jak utrzymać taką sesję. Dodatkowo chcę zapewnić klasę, która utrzymuje sesję utrzymywaną przez różne uruchomienia skryptu (z plikiem pamięci podręcznej). Oznacza to, że prawidłowe "logowanie" jest wykonywane tylko wtedy, gdy jest to wymagane (w pamięci podręcznej istnieje sesja tymczasowa lub brak sesji). Obsługuje także ustawienia proxy przy kolejnych wywołaniach "get" lub "post".

Jest testowany za pomocą Python3.

Użyj go jako podstawy dla własnego kodu. Poniższe fragmenty są uwalnianie z 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 

Kod urywek za pomocą powyższej klasy może wyglądać następująco:

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

To jest świetna odpowiedź, równie dziwnie trudno jest znaleźć to rozwiązanie. – duality

0

Po wypróbowaniu wszystkich powyższych odpowiedzi, znalazłem, że przy użyciu RequestsCookieJar zamiast regularny plik CookieJar dla kolejnych próśb naprawił mój problem.

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

urywek do pobierania danych json, chronione hasłem

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