Python 요청 및 영구 세션


119

내가 사용하고 요청 모듈 (파이썬 2.5 버전 0.10.0을). 웹 사이트의 로그인 양식에 데이터를 제출하고 세션 키를 검색하는 방법을 알아 냈지만 후속 요청에서이 세션 키를 사용하는 확실한 방법을 볼 수 없습니다. 누군가 아래 코드의 줄임표를 채우거나 다른 접근 방식을 제안 할 수 있습니까?

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

답변:


209

다음을 사용하여 영구 세션을 쉽게 만들 수 있습니다.

s = requests.Session()

그 후 다음과 같이 요청을 계속하십시오.

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

세션에 대한 자세한 내용 : https://requests.kennethreitz.org/en/master/user/advanced/#session-objects


4
스크립트 실행 사이에 세션 자체를 저장하는 방법은 무엇입니까?
Gtx

10
다음과 같이 pickle.dump (session.cookies._cookies, file) 및 pickle.load와 같은 파일에 세션 쿠키를 pickle.dump 수 있습니다. cookies = pickle.load (file) cj = requests.cookies.RequestsCookieJar () cj._cookies = 쿠키 및 session.cookies = cj
Cyril

프록시를 사용하면 어떻게됩니까?
brainLoop

1
로 보낸 요청의 localhost경우 잘못된 도메인 속성 값이 포함 된 경우 웹 서버에서 반환 한 로그인 및 기타 쿠키에 문제가있을 수 있습니다. 의 경우 localhost웹 서버는 도메인 속성이로 설정된 쿠키를 반환해야합니다 localhost.local. 그렇지 않으면 쿠키가 세션에 적용되지 않습니다. 이 경우 127.0.0.1대신 사용localhost
Sergey Nudnov

@SergeyNudnov 귀하의 의견에 감사드립니다. 세션이 쿠키를 올바르게 처리하지 않는 이유를 알아 내려고 많은 시간을 낭비했습니다. 도메인을 localhost에서 localhost.local로 변경하면 문제가 해결되었습니다. 다시 한 번 감사드립니다.
Pulkownik

25

다른 답변은 그러한 세션을 유지하는 방법을 이해하는 데 도움이됩니다. 또한 다른 스크립트 실행 (캐시 파일 사용)에서 세션을 유지하는 클래스를 제공하고 싶습니다. 즉, 필요한 경우에만 적절한 "로그인"이 수행됩니다 (시간 초과 또는 캐시에 세션이 없음). 또한 'get'또는 'post'에 대한 후속 호출에 대한 프록시 설정을 지원합니다.

Python3으로 테스트되었습니다.

자신의 코드를위한 기초로 사용하십시오. 다음 스 니펫은 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: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

위 클래스를 사용하기위한 코드 스 니펫은 다음과 같습니다.

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)

6
이것은 훌륭한 대답입니다.이 솔루션을 검색하는 것도 이상하게도 어렵습니다.
duality

요청 모듈의 일부로 구현하면 안 되나요?
user1602

requests모듈을 사용합니다 . 모듈의 일부로 구현하는 방법은 무엇입니까? 또는 @ user1602를 어떻게 의미합니까?
DomTomCat

17

이 비슷한 질문에서 내 대답을 확인하십시오.

python : urllib2 urlopen 요청으로 쿠키를 보내는 방법

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

편집하다:

내 답변에 대해 몇 개의 반대표를 받았지만 설명에 대한 설명은 없습니다. . urllib대신 라이브러리를 참조하고 있기 때문이라고 생각합니다 requests. OP가 도움을 요청 requests하거나 누군가가 다른 접근 방식을 제안 하기 때문에 그렇게합니다 .


2
나는 당신의 반대 투표자 중 한 명은 아니지만 추측으로 많은 독자들은 아마도 OP의 마지막 문장을“누군가가 아래 코드의 줄임표를 채우거나 다른 접근 방식을 제안 할 수 있습니까? 단순히 타원을 다른 것으로 채우는 것보다 내 코드에 대한 수술].” -하지만 그건 제 추측 일뿐입니다.
Brandon Rhodes

7
OP로서 귀하의 답변이 유용한 대안을 제공한다고 말할 수 있습니다. requests구현하는 데 3 개의 라이브러리가 필요한 문제에 대한 간단하고 높은 수준의 솔루션을 제공하는 것을 입증하는 경우에만 가능합니다 .
ChrisGuest

7

문서 get에는 선택 사항이 포함되어 있습니다.cookies 사용할 쿠키를 지정할 수 인수가 포함되어 있습니다.

문서에서 :

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

위의 모든 답변을 시도한 결과 후속 요청에 대해 일반 CookieJar 대신 "RequestsCookieJar"를 사용하여 문제가 해결되었음을 알았습니다.

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
@ jim-chertkov에게 감사드립니다! 몇 년이 지난 후에도 큰 대답! 나는 이것을 사용하고 이해할 수 있었다.
JayRizzo

2

json 데이터를 검색하는 스 니펫, 암호로 보호됨

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

필요한 쿠키 만 저장하고 재사용하십시오.

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

이것은 Python에서 작동합니다.

# 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=(",", ": ")))
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.