169

How can I save all cookies in Python's Selenium WebDriver to a .txt file, and then load them later?

The documentation doesn't say much of anything about the getCookies function.

Peter Mortensen
  • 30,030
  • 21
  • 100
  • 124
Aaron Hiniker
  • 3,485
  • 6
  • 19
  • 14

8 Answers8

258

You can save the current cookies as a Python object using pickle. For example:

import pickle
import selenium.webdriver

driver = selenium.webdriver.Firefox()
driver.get("http://www.google.com")
pickle.dump( driver.get_cookies() , open("cookies.pkl","wb"))

And later to add them back:

import pickle
import selenium.webdriver

driver = selenium.webdriver.Firefox()
driver.get("http://www.google.com")
cookies = pickle.load(open("cookies.pkl", "rb"))
for cookie in cookies:
    driver.add_cookie(cookie)
Peter Mortensen
  • 30,030
  • 21
  • 100
  • 124
Ali-Akber Saifee
  • 3,926
  • 1
  • 15
  • 18
  • 1
    I'm getting "pickle protocol must be <= 2" error. Using the pickle code you posted. What does this mean? Is it referring to the arguments? – Aaron Hiniker Feb 25 '13 at 00:50
  • Would this do the same thing? cookieFile = open("cookies.pkl", "w") dump = pickle.dumps(driver.get_cookies()) cookieFile.write(dump) – Aaron Hiniker Feb 25 '13 at 01:00
  • 1
    Hi Aaron, I've modified the sample a bit - basically the 'b' flag added to the file open sections. Can you try with that? – Ali-Akber Saifee Feb 25 '13 at 01:03
  • Same error, I'm not familiar with pickle so I'm not sure what it is. "raise ValueError("pickle protocol must be <= %d" % HIGHEST_PROTOCOL" – Aaron Hiniker Feb 25 '13 at 01:06
  • may i know which version of python you're running this under? – Ali-Akber Saifee Feb 25 '13 at 01:08
  • I'm really sorry - I'd made a typo in the sample - it should have been pickle.dump instead of pickle.dumps :) – Ali-Akber Saifee Feb 25 '13 at 01:29
  • will driver.add_cookie(cookie) replace the cookie in the loop and finally it can only add one cookie entry? – clevertension Jul 18 '16 at 09:14
  • How can I get secure cookies? – Wictor Chaves Nov 29 '17 at 13:37
  • I get a recursion error if I copy this, marking down – Danny Watson Dec 20 '18 at 11:08
  • Works perfectly fine on python 3.6.7. Saves authentication from previous session perfectly. No installation for 'pickle' required. – Roel Van de Paar Jun 03 '19 at 04:58
  • 7
    I have an issue with this. It works fine however when I try to `drive.add_cookie` t again I got an error message saying "expiry" key is not valid. I am using chromedriver on Mac OS – Solal Aug 12 '19 at 22:32
  • might wanna call driver.delete_all_cookies() before loading the cookies. My code wasn't working without it. – Wildhammer Dec 15 '19 at 02:00
  • I'm also getting `selenium.common.exceptions.InvalidArgumentException: Message: invalid argument: invalid 'expiry'` – Dan Apr 03 '20 at 05:44
  • For those getting the error saying `invalid 'expiry'`, see my fix here: https://stackoverflow.com/a/61845727/3862439 – jcady May 17 '20 at 01:12
  • Hi, I've used your code to write complete solution of loading cookies on starting browser and storing cookies in closing browser. It supports multi instances which is not possible via using `user-data-dir`. https://dev.to/hardiksondagar/reuse-sessions-using-cookies-in-python-selenium-12ca – Hardik Sondagar Jul 28 '20 at 13:02
  • If you save the cookies as .JSON it is nice for reading and adjustments as well as easy to parse back into python – InLaw Dec 23 '20 at 12:10
  • What is the method to save/load JSON cookies?? – The Dan Apr 09 '21 at 21:15
  • 1
    with this I did not able to login again with the previous saved cookies. – Nilanj Aug 25 '21 at 04:36
111

When you need cookies from session to session, there is another way to do it. Use the Chrome options user-data-dir in order to use folders as profiles. I run:

# You need to: from selenium.webdriver.chrome.options import Options
chrome_options = Options()
chrome_options.add_argument("user-data-dir=selenium") 
driver = webdriver.Chrome(chrome_options=chrome_options)
driver.get("www.google.com")

Here you can do the logins that check for human interaction. I do this and then the cookies I need now every time I start the Webdriver with that folder everything is in there. You can also manually install the Extensions and have them in every session.

The second time I run, all the cookies are there:

# You need to: from selenium.webdriver.chrome.options import Options    
chrome_options = Options()
chrome_options.add_argument("user-data-dir=selenium") 
driver = webdriver.Chrome(chrome_options=chrome_options)
driver.get("www.google.com") # Now you can see the cookies, the settings, extensions, etc., and the logins done in the previous session are present here. 

The advantage is you can use multiple folders with different settings and cookies, Extensions without the need to load, unload cookies, install and uninstall Extensions, change settings, change logins via code, and thus no way to have the logic of the program break, etc.

Also, this is faster than having to do it all by code.

Peter Mortensen
  • 30,030
  • 21
  • 100
  • 124
Eduard Florinescu
  • 15,293
  • 28
  • 107
  • 170
39

Remember, you can only add a cookie for the current domain.

If you want to add a cookie for your Google account, do

browser.get('http://google.com')
for cookie in cookies:
    browser.add_cookie(cookie)
Peter Mortensen
  • 30,030
  • 21
  • 100
  • 124
Exsonic
  • 439
  • 6
  • 3
  • 2
    This should be in their documentation :( – Tjorriemorrie Mar 10 '18 at 22:45
  • 1
    @Tjorriemorrie http://selenium-python.readthedocs.io/api.html#selenium.webdriver.remote.webdriver.WebDriver.add_cookie – Mauricio Cortazar Mar 12 '18 at 21:49
  • 3
    @MauricioCortazar it says nothing about the domain requirement, which is what I was referring to – Tjorriemorrie Mar 13 '18 at 03:04
  • 2
    @Tjorriemorrie that's basic man, the cookies only are stored in the domain, even subdomain aren't allowed – Mauricio Cortazar Mar 13 '18 at 03:24
  • 2
    This comment seems relevant where it comes to multiple domains using a cookie from a root domain. For example, google.com could be the root domain, and another domain or subdomain owned by Google could use the same cookie. I like the solution by @Eduard Florinescu better because of this (and other reasons) as it doesn't require using the browser.get before loading cookies, they are just there already from the data dir. It seems the additional browser.get is required here before loading the cookies file (as per this comment), though did not test it. – Roel Van de Paar Jun 03 '19 at 05:07
24

Just a slight modification for the code written by Roel Van de Paar, as all credit goes to him. I am using this in Windows and it is working perfectly, both for setting and adding cookies:

from selenium import webdriver
from selenium.webdriver.chrome.options import Options

chrome_options = Options()
chrome_options.add_argument("--user-data-dir=chrome-data")
driver = webdriver.Chrome('chromedriver.exe',options=chrome_options)
driver.get('https://web.whatsapp.com')  # Already authenticated
time.sleep(30)
Peter Mortensen
  • 30,030
  • 21
  • 100
  • 124
19

Based on the answer by Eduard Florinescu, but with newer code and the missing imports added:

$ cat work-auth.py
#!/usr/bin/python3

# Setup:
# sudo apt-get install chromium-chromedriver
# sudo -H python3 -m pip install selenium

import time
from selenium import webdriver
from selenium.webdriver.chrome.options import Options

chrome_options = Options()
chrome_options.add_argument("--user-data-dir=chrome-data")
driver = webdriver.Chrome('/usr/bin/chromedriver',options=chrome_options)
chrome_options.add_argument("user-data-dir=chrome-data")
driver.get('https://www.somedomainthatrequireslogin.com')
time.sleep(30)  # Time to enter credentials
driver.quit()

$ cat work.py
#!/usr/bin/python3

import time
from selenium import webdriver
from selenium.webdriver.chrome.options import Options

chrome_options = Options()
chrome_options.add_argument("--user-data-dir=chrome-data")
driver = webdriver.Chrome('/usr/bin/chromedriver',options=chrome_options)
driver.get('https://www.somedomainthatrequireslogin.com')  # Already authenticated
time.sleep(10)
driver.quit()
Peter Mortensen
  • 30,030
  • 21
  • 100
  • 124
Roel Van de Paar
  • 1,768
  • 20
  • 32
  • 3
    The pickle stuff didn't work for me. (This is the second time I've tried using it.) So I used your method which also didn't work for me at first. Changes I had to make: I had to type chrome_options.add_argument('no-sandbox') due to the problem documented at https://github.com/theintern/intern/issues/878 and I had to make user-data-dir a full path in my Windows 10 environment. – Eric Klien Jun 10 '19 at 09:21
  • Not working for my website that stores authentication data in cookies – Wildhammer Dec 14 '19 at 23:26
  • You could have just improved their answer, it basically is working fine – clel Feb 06 '21 at 15:07
2

This is code I used in Windows. It works.

for item in COOKIES.split(';'):
    name,value = item.split('=', 1)
    name=name.replace(' ', '').replace('\r', '').replace('\n', '')
    value = value.replace(' ', '').replace('\r', '').replace('\n', '')
    cookie_dict={
            'name':name,
            'value':value,
            "domain": "",  # Google Chrome
            "expires": "",
            'path': '/',
            'httpOnly': False,
            'HostOnly': False,
            'Secure': False
        }
    self.driver_.add_cookie(cookie_dict)
Peter Mortensen
  • 30,030
  • 21
  • 100
  • 124
yong you
  • 21
  • 4
2

Ideally it would be better to not copy the directory in the first place, but this is very hard, see

Also


This is a solution that saves the profile directory for Firefox (similar to the user-data-dir (user data directory) in Chrome) (it involves manually copying the directory around. I haven't been able to find another way):

It was tested on Linux.


Short version:

  • To save the profile
driver.execute_script("window.close()")
time.sleep(0.5)
currentProfilePath = driver.capabilities["moz:profile"]
profileStoragePath = "/tmp/abc"
shutil.copytree(currentProfilePath, profileStoragePath,
                ignore_dangling_symlinks=True
                )
  • To load the profile
driver = Firefox(executable_path="geckodriver-v0.28.0-linux64",
                 firefox_profile=FirefoxProfile(profileStoragePath)
                )

Long version (with demonstration that it works and a lot of explanation -- see comments in the code)

The code uses localStorage for demonstration, but it works with cookies as well.

#initial imports

from selenium.webdriver import Firefox, FirefoxProfile

import shutil
import os.path
import time

# Create a new profile

driver = Firefox(executable_path="geckodriver-v0.28.0-linux64",
                  # * I'm using this particular version. If yours is
                  # named "geckodriver" and placed in system PATH
                  # then this is not necessary
                )

# Navigate to an arbitrary page and set some local storage
driver.get("https://DuckDuckGo.com")
assert driver.execute_script(r"""{
        const tmp = localStorage.a; localStorage.a="1";
        return [tmp, localStorage.a]
    }""") == [None, "1"]

# Make sure that the browser writes the data to profile directory.
# Choose one of the below methods
if 0:
    # Wait for some time for Firefox to flush the local storage to disk.
    # It's a long time. I tried 3 seconds and it doesn't work.
    time.sleep(10)

elif 1:
    # Alternatively:
    driver.execute_script("window.close()")
    # NOTE: It might not work if there are multiple windows!

    # Wait for a bit for the browser to clean up
    # (shutil.copytree might throw some weird error if the source directory changes while copying)
    time.sleep(0.5)

else:
    pass
    # I haven't been able to find any other, more elegant way.
    #`close()` and `quit()` both delete the profile directory


# Copy the profile directory (must be done BEFORE driver.quit()!)
currentProfilePath = driver.capabilities["moz:profile"]
assert os.path.isdir(currentProfilePath)
profileStoragePath = "/tmp/abc"
try:
    shutil.rmtree(profileStoragePath)
except FileNotFoundError:
    pass

shutil.copytree(currentProfilePath, profileStoragePath,
                ignore_dangling_symlinks=True # There's a lock file in the
                                              # profile directory that symlinks
                                              # to some IP address + port
               )

driver.quit()
assert not os.path.isdir(currentProfilePath)
# Selenium cleans up properly if driver.quit() is called,
# but not necessarily if the object is destructed


# Now reopen it with the old profile

driver=Firefox(executable_path="geckodriver-v0.28.0-linux64",
               firefox_profile=FirefoxProfile(profileStoragePath)
              )

# Note that the profile directory is **copied** -- see FirefoxProfile documentation
assert driver.profile.path!=profileStoragePath
assert driver.capabilities["moz:profile"]!=profileStoragePath

# Confusingly...
assert driver.profile.path!=driver.capabilities["moz:profile"]
# And only the latter is updated.
# To save it again, use the same method as previously mentioned

# Check the data is still there

driver.get("https://DuckDuckGo.com")

data = driver.execute_script(r"""return localStorage.a""")
assert data=="1", data

driver.quit()

assert not os.path.isdir(driver.capabilities["moz:profile"])
assert not os.path.isdir(driver.profile.path)

What doesn't work:

  • Initialize Firefox(capabilities={"moz:profile": "/path/to/directory"}) -- the driver will not be able to connect.
  • options=Options(); options.add_argument("profile"); options.add_argument("/path/to/directory"); Firefox(options=options) -- same as above.
user202729
  • 2,782
  • 3
  • 19
  • 30
0

Try this method:

import pickle
from selenium import webdriver
driver = webdriver.Chrome(executable_path="chromedriver.exe")
URL = "SITE URL"
driver.get(URL)
sleep(10)
if os.path.exists('cookies.pkl'):
    cookies = pickle.load(open("cookies.pkl", "rb"))
    for cookie in cookies:
        driver.add_cookie(cookie)
    driver.refresh()
    sleep(5)
# check if still need login
# if yes:
# write login code
# when login success save cookies using
pickle.dump(driver.get_cookies(), open("cookies.pkl", "wb"))