본문으로 바로가기

파일의 IT 블로그

  1. Home
  2. 프로그래밍/Python
  3. [Python] 크롬 브라우저의 모든 쿠키 가져오기

[Python] 크롬 브라우저의 모든 쿠키 가져오기

· 댓글개 · KRFile

직접 작성한 코드 사용

#chrome_cookie_parser.py

import os
import json
import base64
import sqlite3
import shutil
from datetime import datetime, timedelta
import win32crypt  # pip install pypiwin32
from Crypto.Cipher import AES  # pip install pycryptodome


# 코드 참고 : https://www.thepythoncode.com/article/extract-chrome-cookies-python


def get_chrome_datetime(chromedate):
    """크롬 형식의 날짜 및 시간에서 `datetime.datetime` 객체를 반환합니다.
    `chromedate`는 1601년 1월 1일부터 마이크로초 단위로 지정되어 있습니다."""
    if chromedate != 86400000000 and chromedate:
        try:
            return datetime(1601, 1, 1) + timedelta(microseconds=chromedate)
        except Exception as e:
            print(f"오류: {e}, chromedate: {chromedate}")
            return chromedate
    else:
        return ""


def get_encryption_key():
    local_state_path = os.path.join(os.environ["USERPROFILE"],
                                    "AppData", "Local", "Google", "Chrome",
                                    "User Data", "Local State")
    with open(local_state_path, "r", encoding="utf-8") as f:
        local_state = f.read()
        local_state = json.loads(local_state)

    # Base64로부터 암호화 키를 디코딩합니다.
    key = base64.b64decode(local_state["os_crypt"]["encrypted_key"])
    # 'DPAPI' 문자열을 제거합니다.
    key = key[5:]
    # 현재 사용자 로그온 자격 증명에서 유도된 세션 키를 사용하여 원래로 암호화된 키를 반환합니다.
    # 참조: http://timgolden.me.uk/pywin32-docs/win32crypt.html
    return win32crypt.CryptUnprotectData(key, None, None, None, 0)[1]


def decrypt_data(data, key) -> str:
    try:
        # 초기화 벡터를 가져옵니다.
        iv = data[3:15]
        data = data[15:]
        # 암호화 객체 생성
        cipher = AES.new(key, AES.MODE_GCM, iv)
        # 암호화된 비밀번호를 복호화합니다.
        return cipher.decrypt(data)[:-16].decode()
    except:
        try:
            return str(win32crypt.CryptUnprotectData(data, None, None, None, 0)[1])
        except:
            # 지원되지 않음
            return ""


def get_chrome_cookies(target_domain="", for_requests_module=False):
    # 로컬 sqlite 크롬 쿠키 데이터베이스 경로
    db_path = os.path.join(os.environ["USERPROFILE"], "AppData", "Local",
                           "Google", "Chrome", "User Data", "Default", "Network", "Cookies")

    # 데이터베이스가 현재 열려 있으면 잠금이 걸리므로 파일을 현재 디렉터리로 "복사"합니다.
    filename = "Cookies.db"
    if not os.path.isfile(filename):
        # 현재 디렉터리에 파일이 없으면 복사합니다.
        shutil.copyfile(db_path, filename)
    # 데이터베이스에 연결합니다.
    db = sqlite3.connect(filename)
    # 디코딩 오류를 무시합니다.
    db.text_factory = lambda b: b.decode(errors="ignore")
    cursor = db.cursor()

    # `cookies` 테이블에서 쿠키를 가져옵니다.
    if target_domain:
        # 도메인으로도 검색할 수 있습니다. 예: thepythoncode.com
        cursor.execute(f"""
        SELECT host_key, name, value, creation_utc, last_access_utc, expires_utc, encrypted_value
        FROM cookies
        WHERE host_key like '%{target_domain}%'""")
    else:
        # 도메인이 없는 경우 모두 가져옵니다.
        cursor.execute("""
        SELECT host_key, name, value, creation_utc, last_access_utc, expires_utc, encrypted_value
        FROM cookies""")

    # 반환할 리스트
    cookies = []

    # AES key 가져오기
    key = get_encryption_key()
    for host_key, name, value, creation_utc, last_access_utc, expires_utc, encrypted_value in cursor.fetchall():
        if not value:
            decrypted_value = decrypt_data(encrypted_value, key)
        else:
            # 이미 복호화된 경우
            decrypted_value = value

        cookies.append({
            "host": host_key,
            "name": name,
            "value": decrypted_value,
            "creation_utc": get_chrome_datetime(creation_utc),
            "last_access_utc": get_chrome_datetime(last_access_utc),
            "expires_utc": get_chrome_datetime(expires_utc)
        })

        # 복호화된 값을 사용하여 쿠키 테이블을 업데이트하고 세션 쿠키를 영구 쿠키로 만듭니다.
        # cursor.execute("""
        # UPDATE cookies SET value = ?, has_expires = 1, expires_utc = 99999999999999999, is_persistent = 1, is_secure = 0
        # WHERE host_key = ?
        # AND name = ?""", (decrypted_value, host_key, name))

    # 파이썬 requests 모듈 안에서 사용할 쿠키 값인경우
    if for_requests_module:
        cookies = {cookie["name"]: cookie["value"] for cookie in cookies}

    # 변경 사항을 저장합니다.
    db.commit()
    # 연결을 닫습니다.
    db.close()

    # 작업이 완료되었으면 복사한 Cookies.db를 삭제합니다.
    os.remove(filename)

    return cookies


# 모듈 테스트용 (직접 실행시만 실행됨)
if __name__ == '__main__':
    from pprint import pprint  # 깔끔한 출력용 pprint 모듈
    import requests

    # 크롬 쿠키 가져오기
    cookies = get_chrome_cookies()
    print(cookies)

    # 크롬 쿠키를 requests 모듈에서 사용할 수 있는 형식으로 가져오기
    cookies = get_chrome_cookies(for_requests_module=True)
    pprint(cookies)

    # 특정 도메인의 쿠키만 가져오기 (주의 : https:// 는 제외하고 입력)
    cookies = get_chrome_cookies(target_domain=".naver.com")
    pprint(cookies)

    # 특정 도메인의 쿠키를 requests 모듈에서 사용할 수 있는 형식으로 가져오기
    cookies = get_chrome_cookies(
        target_domain=".naver.com", for_requests_module=True)
    pprint(cookies)

    # 가져온 쿠키를 requests 모듈에서 사용하기
    res = requests.get("https://www.naver.com", cookies=cookies)
    pprint(res.text)

위 코드를 사용하면 파이썬을 이용하여 크롬 브라우저의 모든 쿠키를 가져올 수 있습니다. 인터넷 글을 참고해서 코드를 조금 다듬었습니다. 위는 조금 구버전 코드고 타입 힌트를 추가한 최신 코드는 여기서 받아볼 수 있습니다. (작동엔 지장 X)

 

모듈로 사용할 수 있게 제작하였고, [블럭*get_chrome_cookies()*] 와 같은 형태로 호출 시 크롬 브라우저에서 저장중인 모든 사이트의 쿠키를 딕셔너리 형태로 return 합니다.

 

또한 인자의 기본값 대신에(Default Paramter), [**target_domain**] 값을 변경해 함수를 호출하면 특정 도메인에 쿠키값만 추출 가능합니다. 다만 주의할 점은 https:// 는 제외하고 호출해주셔야 한다는 점입니다. 또 [**for_requests_module**]을 True로 두고 호출하면 파이썬 requests 모듈에서 사용가능한 cookie 값 형태로 변환해서 딕셔너리로 반환합니다.

 

if __name__ == "__main__"  아래부터 예제 코드를 작성해놨으니깐 글로 이해가 잘 안가시면 직접 실행해서 출력값을 확인해보시면 되겠습니다.

 

크롬 쿠키를 가져올 수 있다는건 실제로 브라우저에서 접근하는 것과 똑같이 웹 요청을 걸 수 있다는 의미가 됩니다. 쿠키 값에 로그인 정보가 기록되어 있으므로, 파이썬으로 크롬 브라우저의 쿠키를 가져와서 requests로 웹 사이트 요청을 걸어주면 따로 특정 웹사이트에서 로그인 기능을 복잡하게 구현할 필요가 없어집니다.

 

그냥 크롬 브라우저에서 로그인 한번만 해주고, 파이썬으로 쿠키값만 가져와서 이걸 이용해 그대로 다시 요청해주면 파이썬 쪽에서도 로그인 문제 없이 웹 사이트 데이터에 접근할 수 있습니다. 

 

https 웹 통신에서 쿠키가 하는 일을 생각해보시면 이해가 쉬우실 겁니다! 모르시는 분들은 유투브와 인터넷 등지에 좋은 설명들이 많으니 쿠키 설명을 한번 들어보세요.

 

만약에 특정 도메인에 어떤 쿠키값이 저장되어 있는지 잘 모르겠다 싶으면 크롬의 개발자 도구를 이용해도 되고, 크롬 확장 프로그램인 EditThisCookie 같은걸 이용하셔도 됩니다.

 

EditThisCookie를 이용하면 내가 열고 있는 사이트에서 어떤 쿠키 값이 저장되어 있는지 한눈에 볼 수 있습니다. 저 빨간색 부분이 함수 호출 시 target_domain 에 넣어주면 되는 값 입니다. 예를 들어서 www.google.co.uk  에는 OTZ 라는 쿠키값이 저장되어 있고, .google.co.uk 에는 __Secure.. 등등 많은 쿠키 값들이 저장되어 있네요.

 

다른 방법 (라이브러리)

from pprint import pprint
import browser_cookie3
import requests

target_domain = ".naver.com"
chrome_cookies = browser_cookie3.chrome(domain_name=target_domain)

for cookies in chrome_cookies:
    if cookies.domain == target_domain:
        pprint({"name": cookies.name, "value": cookies.value, "domain": cookies.domain,
               "path": cookies.path, "expires": cookies.expires, "secure": cookies.secure})

위처럼 직접 작성한 코드 대신에 여러 라이브러리를 사용해도 됩니다. [**browser_cookie3**] 라이브러리를 이용하면 여러 브라우저의 쿠키를 쉽게 가져올 수 있습니다. 다만 버그가 있어서 작동을 안해서 폐기하고 위에 제가 직접 작성한 코드를 사용중이였는데 최근 문제가 해결된 거 같더라구요. 

 

일단 브라우저가 버전업될때마다 불안정해서 좀 쓰는게 꺼려지긴 하는데 일단은 라이브러리를 사용하고 싶으신 분들은 이걸 써도 괜찮을 듯 싶습니다.

 

from pycookiecheat import chrome_cookies
import requests

url = 'http://example.com/fake.html'

# Uses Chrome's default cookies filepath by default
cookies = chrome_cookies(url)
r = requests.get(url, cookies=cookies)

또 다른 라이브러리로는 [**pycookiecheat**] 란 것도 있습니다. 다만 이건 맥OS나 리눅스 계열 운영체제 전용입니다. 윈도우에서 실행하면 지원하지 않는다고 나옵니다. 자신의 환경이 우분투 같은 리눅스 계열 운영체제라면 사용해볼만 합니다.

 

여담

이 데이터도 Bing AI 같은게 수집해서 원하는 정보만 쏙쏙 골라먹고 튀겠지.. 

이 정보가 여러분께 도움이 되길 바랍니다.

SNS 공유하기
💬 댓글 개
이모티콘창 닫기
울음
안녕
감사해요
당황
피폐

이모티콘을 클릭하면 댓글창에 입력됩니다.