How to use cookies exported from chrome in python aiohttp?
Asked Answered
S

2

6

I'm trying to visit some website using aiohttp/python. Currently I can export the site's cookies with extensions in Google Chrome, formatted like

.domain.name TRUE / FALSE 1547016401 cookies values

I can load it with

import http.cookiejar
cj = http.cookiejar.MozillaCookieJar('cookies.txt')
cj.load()
cookies = {}
for each in cj:
    cookies[each.name] = each.value

and use cookies in aiohttp like:

async with ClientSession(cookies=cookies) as session:

Is there any more elegant way to do this? Looked through docs of aiohttp, but no luck finding them.

Stimulative answered 9/1, 2018 at 12:36 Comment(2)
aiohttp doesn't support cookie files. PR is welcome :)Stylus
upstream issue: add aiohttp.MozillaCookieJar to load/save cookies.txt filesDiscoloration
T
3

The cookiejar_to_cookies function below can convert http.cookiejar.CookieJar to list[tuple[str, http.cookies.Morsel]] which can then be passed to aiohttp as cookies.

Warning: Not tested thoroughly, may have bugs and/or security risks. Use at your own risk!

from datetime import datetime
from http.cookiejar import Cookie, CookieJar
from http.cookies import Morsel, BaseCookie, CookieError


def morsel(cookie: Cookie) -> Morsel | None:
    base_cookie = BaseCookie()
    try:
        base_cookie[cookie.name] = cookie.value
    except CookieError:  # Illegal key
        return

    morsel = base_cookie[cookie.name]
    for key in (
        'path',
        'comment',
        'domain',
        # 'max-age', Cookie converts 'max-age' to 'expires' internally
        'secure',
        'version',
    ):
        if (value := getattr(cookie, key)) is not None:
            morsel[key] = value

    try:
        morsel['expires'] = datetime.fromtimestamp(cookie.expires).strftime(
            "%a, %d %b %Y %H:%M:%S GMT"
        )
    except (
        OSError,  # Invalid argument (value of cookie.expires is invalid)
        TypeError,  # cookie.expires is None
    ):
        pass

    for key in ('HttpOnly', 'SameSite'):
        if (value := cookie.get_nonstandard_attr(key, None)) is not None:
            morsel[key] = value

    return morsel


def cookiejar_to_cookies(cj: CookieJar) -> list[tuple[str, Morsel]]:
    return [(c.name, m) for c in cj if (m := morsel(c)) is not None]

Termite answered 7/10, 2023 at 20:50 Comment(0)
D
1

based on the answer by AXO

AiohttpMozillaCookieJar.py

from http.cookiejar import MozillaCookieJar
from http.cookies import BaseCookie, Morsel, SimpleCookie
from collections import defaultdict
from pathlib import Path
from datetime import datetime
from http.cookiejar import Cookie
from typing import Union


from aiohttp import CookieJar


PathLike = Union[str, "os.PathLike[str]"]


class AiohttpMozillaCookieJar(CookieJar):
    """
    load/save cookies from/to a cookies.txt file with aiohttp

    convert between http.cookiejar.MozillaCookieJar and aiohttp.CookieJar

    import aiohttp
    from AiohttpMozillaCookieJar import AiohttpMozillaCookieJar
    jar = AiohttpMozillaCookieJar()
    cookies_txt_path = "cookies.txt"
    jar.load(cookies_txt_path)
    async with aiohttp.ClientSession(cookie_jar=jar) as session:
        url = "..."
        response = await aiohttp_session.get(url)
    jar.save(cookies_txt_path)

    author: Milan Hauth <[email protected]>
    license: MIT License
    """

    def load(self, file_path):

        file_path = Path(file_path)

        jar_1 = MozillaCookieJar()
        jar_1.load(file_path)

        # Cookie in jar_1 -> Morsel in jar_2

        # jar_1._cookies # dict
        # jar_1._cookies[domain] # dict
        # jar_1._cookies[domain][path] # dict
        # jar_1._cookies[domain][path][name] # Cookie

        # jar_2._cookies # collections.defaultdict(SimpleCookie)
        # jar_2._cookies[(domain, path)] # SimpleCookie
        # jar_2._cookies[(domain, path)][name] # Morsel

        for cookie_1 in jar_1:

            morsel_2 = Morsel()

            domain = cookie_1.domain
            path = cookie_1.path
            name = cookie_1.name

            if name.lower() in Morsel._reserved:
                #print(f"illegal morsel name: {name}")
                continue

            for key in (
                'path',
                'comment',
                'domain',
                'secure',
                'version',
            ):
                if (value := getattr(cookie_1, key)) is not None:
                    morsel_2[key] = value

            morsel_2._key = cookie_1.name
            morsel_2._value = cookie_1.value
            morsel_2._coded_value = cookie_1.value

            try:
                morsel_2['expires'] = datetime.fromtimestamp(cookie_1.expires).strftime(
                    "%a, %d %b %Y %H:%M:%S GMT"
                )
            except (
                OSError,  # Invalid argument (value of cookie.expires is invalid)
                TypeError,  # cookie.expires is None
            ):
                pass

            for key in ('HttpOnly', 'SameSite'):
                if (value := cookie_1.get_nonstandard_attr(key, None)) is not None:
                    morsel_2[key] = value

            self._cookies[(domain, path)][name] = morsel_2


    def save(self, file_path: PathLike) -> None:

        file_path = Path(file_path)

        jar_1 = MozillaCookieJar()

        # Morsel in jar_2 -> Cookie in jar_1

        # jar_2._cookies # collections.defaultdict(SimpleCookie)
        # jar_2._cookies[(domain, path)] # SimpleCookie
        # jar_2._cookies[(domain, path)][name] # Morsel

        # jar_1._cookies # dict
        # jar_1._cookies[domain] # dict
        # jar_1._cookies[domain][path] # dict
        # jar_1._cookies[domain][path][name] # Cookie

        for (domain, path), cookie_2 in self._cookies.items():

            for name, morsel_2 in cookie_2.items():

                try:
                    expires = self._expirations[(domain, path, name)].timestamp()
                except KeyError:
                    expires = datetime.strptime(morsel_2["expires"], "%a, %d %b %Y %H:%M:%S %Z").timestamp()

                cookie_1 = Cookie(
                    0, # version
                    name, # name
                    morsel_2.value, # value
                    None, # port
                    False, # port_specified
                    domain, # domain
                    False, # domain_specified
                    False, # domain_initial_dot
                    path, # path
                    False, # path_specified
                    morsel_2["secure"], # secure
                    expires, # expires
                    False, # discard
                    None, # comment
                    None, # comment_url
                    {}, # rest
                )
                if not domain in jar_1._cookies:
                    jar_1._cookies[domain] = dict()
                if not path in jar_1._cookies[domain]:
                    jar_1._cookies[domain][path] = dict()
                jar_1._cookies[domain][path][name] = cookie_1

        jar_1.save(file_path)
Discoloration answered 27/12, 2023 at 19:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.