Python İstekleri ve kalıcı oturumlar


120

İstek modülünü kullanıyorum (sürüm 0.10.0, Python 2.5 ile). Bir web sitesindeki oturum açma formuna nasıl veri göndereceğimi ve oturum anahtarını nasıl alacağımı buldum, ancak sonraki isteklerde bu oturum anahtarını kullanmanın açık bir yolunu göremiyorum. Birisi aşağıdaki koddaki üç noktayı doldurabilir veya başka bir yaklaşım önerebilir mi?

>>> import requests
>>> login_data =  {'formPosted':'1', 'login_email':'me@example.com', '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', ...)

Yanıtlar:


210

Şunları kullanarak kolayca kalıcı bir oturum oluşturabilirsiniz:

s = requests.Session()

Bundan sonra, isteklerinize yaptığınız gibi devam edin:

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

Oturumlar hakkında daha fazla bilgi için: https://requests.kennethreitz.org/en/master/user/advanced/#session-objects


4
Komut çalıştırmaları arasında Oturumun kendisini kaydetmenin herhangi bir yolu var mı?
Gtx

10
Pickle.dump oturum çerezlerini pickle.dump (session.cookies._cookies, dosya) gibi bir dosyaya ve pickle.load gibi oturuma aşağıdaki çerezler = pickle.load (dosya) cj = request.cookies.RequestsCookieJar () cj._cookies = tanımlama bilgileri ve oturum.cookies = cj
Cyril

Ya vekaletname dahil edersem?
brainLoop

1
Gönderilen istekler için localhost, yanlış etki alanı özellik değeri içeriyorlarsa, oturum açma ve web sunucusu tarafından döndürülen diğer çerezlerde sorunlar olabilir. Çünkü localhostweb sunucusu, etki alanı özelliği olarak ayarlanmış çerezleri döndürmelidir localhost.local, aksi takdirde çerez oturuma uygulanmaz. Bu durumda 127.0.0.1yerine kullanınlocalhost
Sergey Nudnov

@SergeyNudnov Yorumunuz için çok teşekkürler, oturumun neden çerezleri doğru şekilde işlemediğini anlamaya çalışırken çok zaman harcadım. Etki alanını localhost'tan localhost.local'a değiştirmek sorunu çözdü. Tekrar teşekkürler.
Pulkownik

26

diğer cevaplar böyle bir oturumun nasıl sürdürüleceğini anlamaya yardımcı olur. Ek olarak, oturumu bir komut dosyasının farklı çalıştırmaları üzerinde (bir önbellek dosyasıyla) sürdüren bir sınıf sağlamak istiyorum. Bu, uygun bir "oturum açma" nın yalnızca gerektiğinde gerçekleştirileceği anlamına gelir (zaman aşımı veya önbellekte oturum yok). Ayrıca 'alma' veya 'gönderme' için sonraki çağrılarda proxy ayarlarını destekler.

Python3 ile test edilmiştir.

Kendi kodunuz için bir temel olarak kullanın. Aşağıdaki parçacıklar GPL v3 ile yayınlanmıştır

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:pass@server: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

Yukarıdaki sınıfı kullanmak için bir kod parçacığı şöyle görünebilir:

if __name__ == "__main__":
    # proxies = {'https' : 'https://user:pass@server:port',
    #           'http' : 'http://user:pass@server: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)

7
Bu harika bir cevap, bu çözümü aramak da garip bir şekilde zor.
dualite

İstek modülünün bir parçası olarak uygulanmamalı mı?
user1602

Kullanımı yapar requestsmodülü. Bunu modülün bir parçası olarak uygulamaya nasıl devam edersiniz? veya @ user1602 nasıl?
DomTomCat

17

Bu benzer sorudaki cevabıma göz atın:

python: urllib2 urlopen isteği ile tanımlama bilgisi nasıl gönderilir

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

DÜZENLE:

Yanıtım için birkaç olumsuz oy aldığımı görüyorum, ancak açıklayıcı yorum yok. Sanırım bunun nedeni, urllibkütüphanelere atıfta bulunmak yerinerequests . Bunu yapıyorum çünkü OP, requestsbaşka bir yaklaşım önermek için veya birinden yardım istiyor .


2
Ben sizin aşağı seçmenlerinizden biri değilim, ancak bir tahmin olarak, birçok okuyucu muhtemelen OP'nin son cümlesini "Birisi aşağıdaki koddaki üç noktayı doldurabilir mi veya başka bir yaklaşım önerebilir mi [daha fazla önemli koduma sadece elipsleri başka bir şeyle doldurmaktan ziyade ameliyat]. " - ama bu sadece benim açımdan bir tahmin.
Brandon Rodos

7
OP olarak cevabınızın faydalı bir alternatif olduğunu söyleyebilirim. Sadece göstermek için requests, aksi takdirde uygulanması 3 kitaplık gerektiren bir soruna basit ve üst düzey bir çözüm sunar.
ChrisGuest

7

Belgeler, getisteğe bağlı bircookies kullanmak için çerezleri belirtmenize izin veren bağımsız değişken aldığını :

dokümanlardan:

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


6

Yukarıdaki tüm yanıtları denedikten sonra, sonraki istekler için normal CookieJar yerine "RequestsCookieJar" kullanmanın sorunumu çözdüğünü gördüm.

import requests
import json

# The Login URL
authUrl = 'https://whatever.com/login'

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

# Logout URL
testlogoutUrl = 'https://whatever.com/logout'

# Whatever you are posting
login_data =  {'formPosted':'1', 
               'login_email':'me@example.com', 
               'password':'pw'
               }

# The Authentication token or any other data that we will receive from the Authentication Request. 
token = ''

# Post the login Request
loginRequest = requests.post(authUrl, login_data)
print("{}".format(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'])  # or ['access_token']
print("{}".format(token))

# Verify Successful login
print("{}".format(loginRequest.status_code))

# Create your Requests Cookie Jar 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 Request Cookie Jar set
r = requests.get(testUrl, cookies=jar)
print("R.TEXT: {}".format(r.text))
print("R.STCD: {}".format(r.status_code))

# Execute your logout request(s) with the Request Cookie Jar set
r = requests.delete(testlogoutUrl, cookies=jar)
print("R.TEXT: {}".format(r.text))  # should show "Request Not Authorized"
print("R.STCD: {}".format(r.status_code))  # should show 401

1
Bunun için teşekkürler @ jim-chertkov! Yıllar sonra bile harika cevap! Bunu kullanıp anlayabildim.
JayRizzo

2

json verilerini almak için snippet, şifre korumalı

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

1

Yalnızca gerekli tanımlama bilgilerini kaydedin ve yeniden kullanın.

import os
import pickle
from urllib.parse import urljoin, urlparse

login = 'my@email.com'
password = 'secret'
# Assuming two cookies are used for persistent login.
# (Find it by tracing the login process)
persistentCookieNames = ['sessionId', 'profileId']
URL = 'http://example.com'
urlData = urlparse(URL)
cookieFile = urlData.netloc + '.cookie'
signinUrl = urljoin(URL, "/signin")
with requests.Session() as session:
    try:
        with open(cookieFile, 'rb') as f:
            print("Loading cookies...")
            session.cookies.update(pickle.load(f))
    except Exception:
        # If could not load cookies from file, get the new ones by login in
        print("Login in...")
        post = session.post(
            signinUrl,
            data={
                'email': login,
                'password': password,
            }
        )
        try:
            with open(cookieFile, 'wb') as f:
                jar = requests.cookies.RequestsCookieJar()
                for cookie in session.cookies:
                    if cookie.name in persistentCookieNames:
                        jar.set_cookie(cookie)
                pickle.dump(jar, f)
        except Exception as e:
            os.remove(cookieFile)
            raise(e)
    MyPage = urljoin(URL, "/mypage")
    page = session.get(MyPage)

0

Bu sizin için Python'da çalışacaktır;

# Call JIRA API with HTTPBasicAuth
import json
import requests
from requests.auth import HTTPBasicAuth

JIRA_EMAIL = "****"
JIRA_TOKEN = "****"
BASE_URL = "https://****.atlassian.net"
API_URL = "/rest/api/3/serverInfo"

API_URL = BASE_URL+API_URL

BASIC_AUTH = HTTPBasicAuth(JIRA_EMAIL, JIRA_TOKEN)
HEADERS = {'Content-Type' : 'application/json;charset=iso-8859-1'}

response = requests.get(
    API_URL,
    headers=HEADERS,
    auth=BASIC_AUTH
)

print(json.dumps(json.loads(response.text), sort_keys=True, indent=4, separators=(",", ": ")))
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.