开发者

Putting a `Cookie` in a `CookieJar`

I'开发者_StackOverflow中文版m using the Python Requests library to make HTTP requests. I obtain a cookie from the server as text. How do I turn that into a CookieJar with the cookie in it?


Old versions of the Requests library (0.14.2 and older) put new cookies in the jar for you when you pass a CookieJar object:

import requests
import cookielib

URL = '...whatever...'
jar = cookielib.CookieJar()
r = requests.get(URL, cookies=jar)
r = requests.get(URL, cookies=jar)

The first request to the URL fills the jar and the second request sends the cookies back to the server.

This doesn't work starting with Requests 1.0.0, released in 2012.


A Requests Session will receive and send cookies.

s = requests.Session()

s.get('http://httpbin.org/cookies/set/sessioncookie/123456789')
r = s.get("http://httpbin.org/cookies")

print(r.text)
# '{"cookies": {"sessioncookie": "123456789"}}'

(The code above is stolen from Session Objects.)

If you want cookies to persist on disk between runs of your code, you can directly use a CookieJar and save/load them:

from http.cookiejar import LWPCookieJar
import requests

cookie_file = '/tmp/cookies'
jar = LWPCookieJar(cookie_file)

# Load existing cookies (file might not yet exist)
try:
    jar.load()
except:
    pass

s = requests.Session()
s.cookies = jar

s.get('http://httpbin.org/cookies/set/sessioncookie/123456789')
r = s.get("http://httpbin.org/cookies")

# Save cookies to disk, even session cookies
jar.save(ignore_discard=True)

Then look in the file /tmp/cookies:

#LWP-Cookies-2.0
Set-Cookie3: sessioncookie=123456789; path="/"; domain="httpbin.org"; path_spec; discard; version=0


I think many of these answers are missing the point. Sometimes that other library isn't using Requests under the hood. Or it doesn't expose the cookiejar it's using. Sometimes all we have is the cookie string. In my case I'm trying to borrow the auth cookie from pyVmomi.

import requests
import http.cookies

raw_cookie_line = 'foo="a secret value"; Path=/; HttpOnly; Secure; '
simple_cookie = http.cookies.SimpleCookie(raw_cookie_line)
cookie_jar = requests.cookies.RequestsCookieJar()
cookie_jar.update(simple_cookie)

Which gives us the following cookie_jar:

In [5]: cookie_jar
Out[5]: <RequestsCookieJar[Cookie(version=0, name='foo', value='a secret value', port=None, port_specified=False, domain='', domain_specified=False, domain_initial_dot=False, path='/', path_specified=True, secure=True, expires=None, discard=False, comment='', comment_url=False, rest={'HttpOnly': True}, rfc2109=False)]>

Which we can use as normal:

requests.get(..., cookies=cookie_jar)


To help you out, I wrote an entire module. I tried it with my personal webpage and Google's cookies, so I'd assume it works.

I got help from How can I add a cookie to an existing cookielib CookieJar instance in Python?.

I have a lot of unpythonic code in here, including a semi-kludge, so your mileage may vary. Tweak it as you wish, especially with the assumed items (such as port 80). The "request" as an argument below is of type requests.request and I realized that the "method" argument must be all capitals.

Note: I haven't had time to add comments for clarification, so you'll have to use the source.

import Cookie,cookielib,requests,datetime,time  # I had this out, but I realized later I needed it when I continued testing

def time_to_tuple(time_string):
    wday = {'Mon':0,'Tue':1,'Wed':2,'Thu':3,'Fri':4,'Sat':5,'Sun':6}
    mon = {'Jan':1,'Feb':2,'Mar':3,'Apr':4,'May':5,'Jun':6,'Jul':7,'Aug':8,'Sep':9,'Oct':10,'Nov':11,'Dec':12}
    info = time_string.split(' ')
    info = [i.strip() for i in info if type(i)==str]
    month = None
    for i in info:
        if '-' in i:
            tmp = i.split('-')
            for m in tmp:
                try:
                    tmp2 = int(m)
                    if tmp2<31:
                        mday = tmp2
                    elif tmp2 > 2000:
                        year = tmp2
                except:
                    for key in mon:
                        if m.lower() in key.lower():
                            month = mon[key]
        elif ':' in i:
            tmp = i.split(':')
            if len(tmp)==2:
                hour = int(tmp[0])
                minute = int(tmp[1])
            if len(tmp)==3:
                hour = int(tmp[0])
                minute = int(tmp[1])
                second = int(tmp[2])
        else:
            for item in wday:
                if ((i.lower() in item.lower()) or (item.lower() in i.lower())):
                    day = wday[item]
            if month is None:
                for item in mon:
                    if ((i.lower() in item.lower()) or (item.lower() in i.lower())):
                        month = mon[item]
    return year,month,mday,hour,minute,second

def timefrom(year,month,mday,hour,minute,second):
    time_now = time.gmtime()
    datetime_now = datetime.datetime(time_now.tm_year,time_now.tm_mon,
                                     time_now.tm_mday,time_now.tm_hour,
                                     time_now.tm_min,time_now.tm_sec)
    then = datetime.datetime(year,month,mday,hour,minute,second)
    return (datetime_now-then).total_seconds()

def timeto(year,month,mday,hour,minute,second):
    return -1*timefrom(year,month,mday,hour,minute,second)



##['comment', 'domain', 'secure', 'expires', 'max-age', 'version', 'path', 'httponly']
def parse_request(request):
    headers = request.headers
    cookieinfo = headers['set-cookie'].split(';')
    name = 'Undefined'
    port=80
    port_specified=True
    c = Cookie.SmartCookie(headers['set-cookie'])
    cj = cookielib.CookieJar()
    for m in c.values():
        value = m.coded_value
        domain = m['domain']
        expires = m['expires']
        if type(expires) == str:
            tmp = time_to_tuple(expires)
            expires = timeto(tmp[0],tmp[1],tmp[2],tmp[3],tmp[4],tmp[5])
        max_age=m['max-age']
        version = m['version']
        if version == '':
            version = 0
        path = m['path']
        httponly = m['httponly']
        if httponly == '':
            if 'httponly' in headers['set-cookie'].lower():
                httponly = True
        else:
            httponly = False
        secure = m['secure']
        comment=m['comment']
        port = 80
        port_specified=False
        domain_specified=True
        domain_initial_dot = domain.startswith('.')
        path_specified=True
        discard = True
        comment_url=None
        rest={'HttpOnly':httponly}
        rfc2109=False
        ck = cookielib.Cookie(version,name,value,port,port_specified,domain,
                              domain_specified,domain_initial_dot,path,path_specified,
                              secure,expires,discard,comment,comment_url,rest,rfc2109)
        cj.set_cookie(ck)
    return cj


Well, cookielib.LWPCookieJar has load and save methods on it. Look at the format and see if it matches the native cookie format. You may well be able to load your cookie straight into a cookie jar using StringIO.

Alternatively, if Requests is using urllib2 under the hood, you could add a cookie handler to the default opener.


I'm trying to do the same thing. This is what I have so far, and for some reason it isn't sending the cookies along in the header. It might get you far enough along to solve your problem though.

import requests
import cookielib
import logging

log = logging.getLogger(__name__)

def auth(auth_url, cookies):
    cj = cookielib.CookieJar()
    for x in cookies:
         if len(cookies[x]) > 0:
             ck = cookielib.Cookie(version=1, name=x, value=cookies[x], 
                    port=None, port_specified=False, domain='.example.com', 
                    domain_specified=True, 
                    domain_initial_dot=True, path='/', 
                    path_specified=True, secure=False, 
                    expires=None, discard=True, 
                    comment=None, comment_url=None, 
                    rest=None, rfc2109=True)
             log.info(ck)
             cj.set_cookie(ck)

    log.info("cookies = %s " % cj)
    response = requests.get(auth_url, cookies=cj)
    log.info("response %s \n" % response)
    log.info("response.headers %s \n" % response.headers)
    log.info("response.content %s \n" % response.content)


I am assuming that you have requested url and you got headers as the response. The type of url is string. The type of headers is list.

import urllib2
import cookielib

class dummyResponse:
    def __init__(self, headers):
        self.headers = headers
    def info(self):
        return dummyInfo(self.headers)

class dummyInfo:
    def __init__(self, headers):
        self.headers = headers
    def getheaders(self, key):
        # Headers are in the form: 'Set-Cookie: key=val\r\n'. We want 'key=val'
        newMatches = []
        for header in self.headers:
            if header.lower().startswith(key.lower()):
                clearHeader = header[len(key) + 1:].strip()
                newMatches.append(clearHeader)
        return newMatches

req = urllib2.Request(url)
resp = dummyResponse(headers)

jar = cookielib.CookieJar()
jar.extract_cookies(resp, req)


A simplified version of overthink's answer, on how to get a cookiejar and persist the cookies in Python 3:

import requests

s = requests.Session()

r1 = s.get('https://stackoverflow.com')
print("r1", r1.cookies) # Have cookie
print("s", s.cookies)  # Have cookie(jar)

r2 = s.get('https://stackoverflow.com') #The cookie from r1 is resend
print("r2", r2.cookies) #No cookie (could be a new one)
print("s", s.cookies)  #Keep the cookie(jar) from r1

To persist the cookies between sessions you have to save and reuse the cookiejar in Session (the s variable).

If you get different answers between r1/r2/s on other sites, check if there is a redirect. As an example, r1/r2 will not get any cookie for https://www.stackoverflow.com, because it is redirected to the site without www.


As dstanek answered, Requests will automatically put response cookies in a cookie jar for you.

However, if you manually specify a Cookie header entry, Requests will not put those cookies in a jar for you. This means any subsequent requests will be lacking your initial set of cookies, but it will have any new cookies going forward.

If you do need to manually create a cookie jar for requests, use requests.cookies.RequestsCookieJar. In case their example code changes:

jar = requests.cookies.RequestsCookieJar()
jar.set('tasty_cookie', 'yum',   domain='httpbin.org', path='/cookies')
jar.set('gross_cookie', 'blech', domain='httpbin.org', path='/elsewhere')
url = 'http://httpbin.org/cookies'
r = requests.get(url, cookies=jar)

Note that if you provide a cookie jar and a Cookie header, the header takes precedence, but the cookie jar will still be maintained for future requests.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜