【问题标题】:How to save requests (python) cookies to a file?如何将请求(python)cookie保存到文件中?
【发布时间】:2012-10-13 08:44:52
【问题描述】:

请求后如何使用库requests(在python中)

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import requests
bot = requests.session()
bot.get('http://google.com')

将所有 cookie 保存在一个文件中,然后从一个文件中恢复 cookie。

【问题讨论】:

    标签: python cookies python-requests


    【解决方案1】:

    没有直接的方法可以做到这一点,但这并不难。

    您可以从与session.cookies 的会话中获取CookieJar 对象,并使用pickle 将其存储到文件中。

    一个完整的例子:

    import requests, pickle
    session = requests.session()
    # Make some calls
    with open('somefile', 'wb') as f:
        pickle.dump(session.cookies, f)
    

    然后加载:

    session = requests.session()  # or an existing session
    
    with open('somefile', 'rb') as f:
        session.cookies.update(pickle.load(f))
    

    requests 库使用 requests.cookies.RequestsCookieJar() subclass,它明确支持酸洗和类似 dict 的 API。 RequestsCookieJar.update() method 可用于使用从 pickle 文件加载的 cookie 更新现有会话 cookie jar。

    【讨论】:

    • requests.utils.dict_from_cookiejarrequests.utils.cookiejar_from_dict 不是必需的。他们不会为不同的域保存具有相同名称的 cookie,也不会保存所有必需的 cookie 数据。就因为这些,我花了很多时间调试。
    • 腌制 cookiejar 似乎并不能保存与其关联的主机。当您再次加载时,所有 cookie 都只是在主机''中。
    • @MattClimbs,dict_from_cookiejar 不保存主机信息。实际上,在当前版本中,session.cookies 可以直接腌制和取消腌制,而无需转换为dict。另外,requests.utils.dict_from_cookiejar可以替换为session.cookies.get_dict()cookiejar_from_dict可以替换为session.cookies.update(my_dict)
    • 编者注:我已经更新了这个最佳答案,而不是添加新帖子。它已经足够接近,但需要更新在其间的 6 年中所做的 API 更改,这使得这项任务变得更加容易。不要使用字典实用程序,它们根本不需要,也不保留重要的 cookie 数据。如果作者希望恢复我的更改,我可以发布我自己的答案;在这种情况下,我将不胜感激。
    • @Weekend,使用with 语句时不需要显式调用f.close()上下文管理器 为您隐式调用f.close()。请参阅docs.python.org/3/tutorial/… 答案中的 2 个单独的 with 语句不是嵌套的。
    【解决方案2】:

    r = requests.get()等调用后,r.cookies会返回一个RequestsCookieJar,你可以直接pickle,即

    import pickle
    def save_cookies(requests_cookiejar, filename):
        with open(filename, 'wb') as f:
            pickle.dump(requests_cookiejar, f)
    
    def load_cookies(filename):
        with open(filename, 'rb') as f:
            return pickle.load(f)
    
    #save cookies
    r = requests.get(url)
    save_cookies(r.cookies, filename)
    
    #load cookies and do a request
    requests.get(url, cookies=load_cookies(filename))
    

    如果你想以人类可读的格式保存你的 cookie,你必须做一些工作来将 RequestsCookieJar 提取到 LWPCookieJar

    import cookielib
    def save_cookies_lwp(cookiejar, filename):
        lwp_cookiejar = cookielib.LWPCookieJar()
        for c in cookiejar:
            args = dict(vars(c).items())
            args['rest'] = args['_rest']
            del args['_rest']
            c = cookielib.Cookie(**args)
            lwp_cookiejar.set_cookie(c)
        lwp_cookiejar.save(filename, ignore_discard=True)
    
    def load_cookies_from_lwp(filename):
        lwp_cookiejar = cookielib.LWPCookieJar()
        lwp_cookiejar.load(filename, ignore_discard=True)
        return lwp_cookiejar
    
    #save human-readable
    r = requests.get(url)
    save_cookies_lwp(r.cookies, filename)
    
    #you can pass a LWPCookieJar directly to requests
    requests.get(url, cookies=load_cookies_from_lwp(filename))
    

    【讨论】:

    • all(isinstance(c, cookielib.Cookie) for c in r.cookies)True,那么为什么要在save_cookies_lwp 中再次创建每个cookie 项?
    • 请在您的回答中使用会话
    【解决方案3】:

    扩展@miracle2k 的答案,请求Sessions 是documented 与任何cookielib CookieJar 一起工作。 LWPCookieJar(和MozillaCookieJar)可以在文件中保存和加载他们的cookies。这是一个完整的代码 sn-p 它将保存和加载请求会话的 cookie。 ignore_discard 参数用于与 httpbin 一起进行测试,但您可能不想将其包含在实际代码中。

    import os
    from cookielib import LWPCookieJar
    
    import requests
    
    
    s = requests.Session()
    s.cookies = LWPCookieJar('cookiejar')
    if not os.path.exists('cookiejar'):
        # Create a new cookies file and set our Session's cookies
        print('setting cookies')
        s.cookies.save()
        r = s.get('http://httpbin.org/cookies/set?k1=v1&k2=v2')
    else:
        # Load saved cookies from the file and use them in a request
        print('loading saved cookies')
        s.cookies.load(ignore_discard=True)
        r = s.get('http://httpbin.org/cookies')
    print(r.text)
    # Save the session's cookies back to the file
    s.cookies.save(ignore_discard=True)
    

    【讨论】:

      【解决方案4】:

      我通过json提供一种方式:

      保存 cookie -

      import json
      with open('cookie.txt', 'w') as f:
          json.dump(requests.utils.dict_from_cookiejar(bot.cookies), f)
      

      并加载 cookie -

      import json
      session = requests.session()  # or an existing session
      
      with open('cookie.txt', 'r') as f:
          cookies = requests.utils.cookiejar_from_dict(json.load(f))
          session.cookies.update(cookies)
      

      【讨论】:

      • requests.utils.dict_from_cookiejar
      • 请注意,dict_from_cookiejar 会丢失主机信息,因此如果有多个用于不同主机的同名 cookie 将不起作用。
      • 这应该是最好的答案 - 没有默认情况下不包含的外部库。
      • 这是不正确的,dict_from_cookiejar 丢失了很多关于 cookie 的信息。
      【解决方案5】:

      这样就可以了:

      session.cookies = LWPCookieJar('cookies.txt')
      

      CookieJar API 要求您手动调用 load() 和 save()。如果您不关心 cookies.txt 格式,我有一个 ShelvedCookieJar 实现,它将在更改时持续存在。

      【讨论】:

      • 这个答案缺少几个步骤。以下是完整代码:cj = cookielib.LWPCookieJar(cookie_file)cj.load()session.cookies = cj
      【解决方案6】:

      我发现其他答案有问题:

      • 它们不适用于会话。
      • 他们没有正确保存和加载。只保存了cookie名称和值,过期日期、域名等全部丢失。

      这个答案解决了这两个问题:

      import requests.cookies
      
      def save_cookies(session, filename):
          if not os.path.isdir(os.path.dirname(filename)):
              return False
          with open(filename, 'w') as f:
              f.truncate()
              pickle.dump(session.cookies._cookies, f)
      
      
      def load_cookies(session, filename):
          if not os.path.isfile(filename):
              return False
      
          with open(filename) as f:
              cookies = pickle.load(f)
              if cookies:
                  jar = requests.cookies.RequestsCookieJar()
                  jar._cookies = cookies
                  session.cookies = jar
              else:
                  return False
      

      然后只需调用save_cookies(session, filename) 保存或调用load_cookies(session, filename) 加载。就这么简单。

      【讨论】:

      • 这对我有用,没有每个函数中的 os.path.isdir 行。如果文件不存在,调用 open() 会创建文件,并为我的用例正确写入。
      【解决方案7】:

      你可以直接腌制cookies对象:

      cookies = pickle.dumps(session.cookies)
      

      dict 表示遗漏了很多信息:过期、域、路径...

      这取决于您打算对 cookie 进行的使用,但如果您没有关于过期的信息,例如,您应该实现手动跟踪过期的逻辑。

      pickling 库返回的对象可以让您轻松地重建状态,然后您可以中继库实现。

      显然,这样一来,腌制对象的消费者需要使用同一个库

      【讨论】:

        【解决方案8】:

        将 cookie 转换为 dicts 列表并保存到 json 或 db 的简单方法。 这是具有session 属性的类的方法。

        def dump_cookies(self):
            cookies = []
            for c in self.session.cookies:
                cookies.append({
                    "name": c.name,
                    "value": c.value,
                    "domain": c.domain,
                    "path": c.path,
                    "expires": c.expires
                })
            return cookies
        
        def load_cookies(self, cookies):
            for c in cookies:
                self.session.cookies.set(**c)
        

        我们只需要五个参数,例如:namevaluedomainpathexpires

        【讨论】:

          【解决方案9】:

          python 3 代码

          请注意,互联网上的绝大多数 cookie 都是 Netscape cookie。因此,如果您想以 Mozilla cookies.txt 文件格式(Lynx 和 Netscape 浏览器也使用该格式)将 cookie 保存到磁盘,请使用 MozillaCookieJar

          from http.cookiejar import MozillaCookieJar
          import requests
          
          s = requests.Session()
          s.cookies = MozillaCookieJar('cookies.txt')
          # or s.cookies = MozillaCookieJar() and later use s.cookies.filename = 'cookies.txt' or pass the file name to save method.
          
          response = s.get('https://www.msn.com')
          
          s.cookies.save()
          

          如果文件已经存在,则文件将被覆盖,从而擦除其中包含的所有 cookie。保存的 cookie 可以稍后使用 load() 或 revert() 方法恢复。

          请注意,save() 方法无论如何都不会保存会话 cookie,除非 你可以通过传递一个真正的 ignore_discard 参数来提出其他问题。

          s.cookies.save(ignore_discard=True)
          

          使用加载方式:

          从文件中加载 cookie。

          保留旧的 cookie,除非被新加载的覆盖。

          s.cookies.load()
          

          使用还原方法:

          清除所有 cookie 并从保存的文件中重新加载 cookie。

          s.cookies.revert()
          

          您可能还需要在 load 或 revert 方法中传递一个真正的 ignore_discard 参数。

          关于使用 MozillaCookieJar 的注意事项:

          注意这会丢失有关 RFC 2965 cookie 以及有关 更新的或非标准的 cookie 属性,例如端口。

          more reading

          【讨论】:

          • 这基本上可以正常工作,但是您不能像使用 requests.update() 那样添加/更新 cookie。
          【解决方案10】:

          dtheodor 的回答得到了 95%,除了这个:

          session = requests.session(cookies=cookies)
          

          对我来说,这会引发一个异常,说 session() 不接受参数。

          我通过获取 cookie.get_dict 上的键/值并将它们手动添加到会话中来解决它:

          session.cookies.set(cookies.keys()[n],cookies.values()[n])
          

          【讨论】:

          • 使用session.cookies.set(cookies.keys()[n],cookies.values()[n]) 也为我工作,谢谢!
          【解决方案11】:

          对于所有使用 Cookielib 的解决方案,在 Python 3.0 中已将其更改为 http.cookiejar 请查收Python 3.2 won't import cookielib

          【讨论】:

            猜你喜欢
            • 2021-08-23
            • 1970-01-01
            • 2017-04-03
            • 1970-01-01
            • 1970-01-01
            • 2015-09-16
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多