36

I am trying to add a cookie to an existing cookiejar using the python requests 1.2.3 library. Every time I add the new cookie, the data in the jar is munged for the new cookie. Keys missing, Values missing or matched to incorrect Keys. I'm not sure if it's a Request library bug or I'm not sending the cookie correctly. I'm using the following code that is resulting in a bad cookie in cookiejar. Am I formatting the cookie correctly? Any ideas?

    my_cookie = {
           'domain':'www.mydomain.com',
           'expires':None,
           'name':'COOKIE_NAME',
           'path':'/',
           'value':'the cookie works',
           'version':0
}

s = requests.Session()
requests.utils.add_dict_to_cookiejar(s.cookies, my_cookie)
fat fantasma
  • 7,483
  • 15
  • 48
  • 66

5 Answers5

61

Quick Answer

Option 1

import requests
s = requests.session()
s.cookies.set("COOKIE_NAME", "the cookie works", domain="example.com")

Option 2

import requests
s = requests.session()
# Note that domain keyword parameter is the only optional parameter here
cookie_obj = requests.cookies.create_cookie(domain="example.com",name="COOKIE_NAME",value="the cookie works")
s.cookies.set_cookie(cookie_obj)

Detailed Answer

I do not know if this technique was valid when the original question was asked, but ideally you would generate your own cookie object using requests.cookies.create_cookie(name,value,**kwargs) and then add it to the cookie jar via requests.cookies.RequestsCookieJar.set_cookie(cookie,*args,**kwargs). See the source/documentation here.

Adding a custom cookie to requests session

>>> import requests
>>> s = requests.session()
>>> print(s.cookies)
<RequestsCookieJar[]>
>>> required_args = {
        'name':'COOKIE_NAME',
        'value':'the cookie works'
    }
>>> optional_args = {
    'version':0,
    'port':None,
#NOTE: If domain is a blank string or not supplied this creates a
# "super cookie" that is supplied to all domains.
    'domain':'example.com',
    'path':'/',
    'secure':False,
    'expires':None,
    'discard':True,
    'comment':None,
    'comment_url':None,
    'rest':{'HttpOnly': None},
    'rfc2109':False
}
>>> my_cookie = requests.cookies.create_cookie(**required_args,**optional_args)
# Counter-intuitively, set_cookie _adds_ the cookie to your session object,
#  keeping existing cookies in place
>>> s.cookies.set_cookie(my_cookie)
>>> s.cookies
<RequestsCookieJar[Cookie(version=0, name='COOKIE_NAME', value='the cookie works', port=None, port_specified=False, domain='www.domain.com', domain_specified=True, domain_initial_dot=False, path='/', path_specified=True, secure=False, expires=None, discard=True, comment=None, comment_url=None, rest={'HttpOnly': None}, rfc2109=False)]>

Bonus: Lets add a super cookie then delete it

>>> my_super_cookie = requests.cookies.create_cookie('super','cookie')
>>> s.cookies.set_cookie(my_super_cookie)
# Note we have both our previous cookie and our new cookie
>>> s.cookies
<RequestsCookieJar[Cookie(version=0, name='super', value='cookie', port=None, port_specified=False, domain='', domain_specified=False, domain_initial_dot=False, path='/', path_specified=True, secure=False, expires=None, discard=True, comment=None, comment_url=None, rest={'HttpOnly': None}, rfc2109=False), Cookie(version=0, name='COOKIE_NAME', value='the cookie works', port=None, port_specified=False, domain='www.domain.com', domain_specified=True, domain_initial_dot=False, path='/', path_specified=True, secure=False, expires=None, discard=True, comment=None, comment_url=None, rest={'HttpOnly': None}, rfc2109=False)]>
# Deleting is simple, note that this deletes the cookie based on the name,
# if you have multiple cookies with the same name it will raise
# requests.cookies.CookieConflictError
>>> del s.cookies['super']
>>> s.cookies
<RequestsCookieJar[Cookie(version=0, name='COOKIE_NAME', value='the cookie works', port=None, port_specified=False, domain='www.domain.com', domain_specified=True, domain_initial_dot=False, path='/', path_specified=True, secure=False, expires=None, discard=True, comment=None, comment_url=None, rest={'HttpOnly': None}, rfc2109=False)]>
Kamel
  • 740
  • 1
  • 5
  • 8
  • 3
    I don't understand, why is this not documented on the requests library docs? Such a simple case, yet I had to search here. The docs always use a more complicated example. – Cristiano Coelho Feb 12 '19 at 21:43
  • I'm not sure either... this was a thorn in my side as well hence why I went through the effort to dissect it myself. Glad you found it helpful! – Kamel Feb 14 '19 at 00:46
  • Note: it's `requests.cookies.create_cookie`, not `session.cookies.create_cookie`. I made that mistake and got an error: 'RequestsCookieJar' object has no attribute 'create_cookie' – cheshirekow Nov 08 '19 at 04:47
  • 1
    Also note that the documentation page you linked appears to show a more concise `session.cookies.set("COOKIE_NAME", "the cookie works", domain="example.com")`. – cheshirekow Nov 08 '19 at 04:49
  • Mix this with a [hidden] proxy and a header, it is perfect for a request. – Franco Gil Jul 17 '20 at 15:35
  • @cheshirekow originally i responded saying i prefer the more verbose option, but after a second look i decided to add this as another option. thanks for the feedback! – Kamel Jan 08 '21 at 19:59
22

I found out a way to do it by importing CookieJar, Cookie, and cookies. With help from @Lukasa, he showed me a better way. However, with his way I was not able to specify the "port_specified", "domain_specified", "domain_initial_dot" or "path_specified" attributes. The "set" method does it automatically with default values. I'm trying to scrape a website and their cookie has different values in those attributes. As I am new to all of this I'm not sure if that really matters yet.

my_cookie = {
"version":0,
"name":'COOKIE_NAME',
"value":'true',
"port":None,
# "port_specified":False,
"domain":'www.mydomain.com',
# "domain_specified":False,
# "domain_initial_dot":False,
"path":'/',
# "path_specified":True,
"secure":False,
"expires":None,
"discard":True,
"comment":None,
"comment_url":None,
"rest":{},
"rfc2109":False
}

s = requests.Session()
s.cookies.set(**my_cookie)
fat fantasma
  • 7,483
  • 15
  • 48
  • 66
18

If you're looking to handle a plain cookies str:

def make_cookiejar_dict(cookies_str):
    # alt: `return dict(cookie.strip().split("=", maxsplit=1) for cookie in cookies_str.split(";"))`
    cookiejar_dict = {}
    for cookie_string in cookies_str.split(";"):
        # maxsplit=1 because cookie value may have "="
        cookie_key, cookie_value = cookie_string.strip().split("=", maxsplit=1)
        cookiejar_dict[cookie_key] = cookie_value
    return cookiejar_dict


cookies_str = '''nopubuser_abo=1; groupenctype_abo="1="'''
cj = requests.utils.cookiejar_from_dict(make_cookiejar_dict(cookies_str))
sess = requests.Session()
sess.cookies = cj
Zachary Ryan Smith
  • 2,688
  • 1
  • 20
  • 30
Andelf
  • 603
  • 6
  • 10
  • 1
    You should probably split on `;`, then `strip` whitespace before splitting on `=`. Also, an explanation would be nice. – wizzwizz4 Jan 02 '17 at 18:57
  • 1
    This will also fail if there are '=' signs in the cookie value, which may be the case if the value has been base64 encoded. I realize it's not great, and implies importing `re` as well, but this worked for me: `cj = requests.utils.cookiejar_from_dict(dict(re.match(r'^([^=]+)=(.+)$', p.strip()).groups() for p in plain_cookie.split('; ')))` – Greg Sadetsky Sep 02 '20 at 02:08
  • 1
    @GregSadetsky i edited the answer to handle cookie values having "=". Please review – Zachary Ryan Smith Oct 14 '21 at 14:13
  • Great use of `maxsplit`, I didn't know about this argument! Thank you – Greg Sadetsky Oct 15 '21 at 16:42
  • Instead of re-coding this by hand you can use what already exists in `http.cookiejar`, like `parse_ns_headers`. I downvoted this answer because OP asked how to set a cookie, not how to parse a `Set-Cookie` header value. – bfontaine Sep 01 '22 at 09:07
11

To use the built in functions and methods...

import requests

session = requests.session()
my_cookies = {'cookie_key': 'cookie_value',
              'another_cookie_key': 'another_cookie_value'}
requests.utils.add_dict_to_cookiejar(session.cookies, my_cookies)

You can add as many cookies as you need. If you need special headers, use this method to add them.

my_headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:75.0) Gecko/20100101 Firefox/75.0'}
session.headers.update(my_headers)
user180977
  • 121
  • 1
  • 4
1

Add new cookie into requests's session.cookies

Method 1: session.cookies.set

pass in dict of new cookie

also two write type:

Type 1: All in single dict

cookieCurrencyDict = {
    "name": "user_pref_currency",
    "value": "CNY",
    # common part
    "domain": ".ti.com.cn",
    "path": "/",
    "expires": 1701488751,
    "secure": True,
    # "discard": True,
    "version": 0,
}

session.cookies.set(**cookieCurrencyDict)

Type 2: name, value and common dict

cookieCommonDict = {
    "domain": ".ti.com.cn",
    "path": "/",
    "expires": expiresOneYear,
    "secure": True,
    # "discard": True,
    "version": 0,
}

session.cookies.set(name="user_pref_currency", value="CNY", **cookieCommonDict)
# or omit parameter name:
# session.cookies.set("user_pref_currency", "CNY", **cookieCommonDict)

Method 2: requests.cookies.create_cookie + session.cookies.set_cookie

generate new cookie object, then add into cookies

cookieCommonDict = {
    "domain": ".ti.com.cn",
    "path": "/",
    "expires": expiresOneYear,
    "secure": True,
    # "discard": True,
    "version": 0,
}

cookieCurrency = requests.cookies.create_cookie(
    name="user_pref_currency",
    value="CNY",
    **cookieCommonDict
)
# or omit parameter name:
# cookieCurrency = requests.cookies.create_cookie("user_pref_currency", "CNY", **cookieCommonDict)

session.cookies.set_cookie(cookieCurrency)

Added new cookie example

session.cookies._cookies['.ti.com.cn']['/']['user_pref_currency'] = 

Cookie(version=0, name='user_pref_currency', value='CNY', port=None, port_specified=False, domain='.ti.com.cn', domain_specified=True, domain_initial_dot=True, path='/', path_specified=True, secure=True, expires=1701503561, discard=True, comment=None, comment_url=None, rest={'HttpOnly': None}, rfc2109=False)

Summary

  • session.cookies.set == requests.cookies.create_cookie + session.cookies.set_cookie

Reference

crifan
  • 12,947
  • 1
  • 71
  • 56