33import os
44from datetime import datetime
55from urllib .parse import urljoin
6+ import json
67
78import requests
89
@@ -24,6 +25,7 @@ def __init__(
2425 self ,
2526 email = None ,
2627 password = None ,
28+ cookies_path = None ,
2729 base_url = None ,
2830 publication_url = None ,
2931 debug = False ,
@@ -37,6 +39,9 @@ def __init__(
3739 Args:
3840 email:
3941 password:
42+ cookies_path
43+ To re-use your session without logging in each time, you can save your cookies to a json file and then load them in the next session.
44+ Make sure to re-save your cookies, as they do update over time.
4045 base_url:
4146 The base URL to use to contact the Substack API.
4247 Defaults to https://substack.com/api/v1.
@@ -49,30 +54,39 @@ def __init__(
4954
5055 self ._session = requests .Session ()
5156
52- if email is not None and password is not None :
57+ # Load cookies from file if provided
58+ # Helps with Captcha errors by reusing cookies from "local" auth, then switching to running code in the cloud
59+ if cookies_path is not None :
60+ with open (cookies_path , "r" ) as f :
61+ cookies = json .load (f )
62+ self ._session .cookies .update (cookies )
63+
64+ elif email is not None and password is not None :
5365 self .login (email , password )
66+ else :
67+ raise ValueError ("Must provide email and password or cookies_path to authenticate." )
68+
69+ # if the user provided a publication url, then use that
70+ if publication_url :
71+ import re
72+
73+ # Regular expression to extract subdomain name
74+ match = re .search (r"https://(.*).substack.com" , publication_url .lower ())
75+ subdomain = match .group (1 ) if match else None
76+
77+ user_publications = self .get_user_publications ()
78+ # search through publications to find the publication with the matching subdomain
79+ for publication in user_publications :
80+ if publication ['subdomain' ] == subdomain :
81+ # set the current publication to the users publication
82+ user_publication = publication
83+ break
84+ else :
85+ # get the users primary publication
86+ user_publication = self .get_user_primary_publication ()
5487
55- # if the user provided a publication url, then use that
56- if publication_url :
57- import re
58-
59- # Regular expression to extract subdomain name
60- match = re .search (r"https://(.*).substack.com" , publication_url .lower ())
61- subdomain = match .group (1 ) if match else None
62-
63- user_publications = self .get_user_publications ()
64- # search through publications to find the publication with the matching subdomain
65- for publication in user_publications :
66- if publication ['subdomain' ] == subdomain :
67- # set the current publication to the users publication
68- user_publication = publication
69- break
70- else :
71- # get the users primary publication
72- user_publication = self .get_user_primary_publication ()
73-
74- # set the current publication to the users primary publication
75- self .change_publication (user_publication )
88+ # set the current publication to the users primary publication
89+ self .change_publication (user_publication )
7690
7791 def login (self , email , password ) -> dict :
7892 """
@@ -114,6 +128,16 @@ def change_publication(self, publication):
114128 # sign-in to the publication
115129 self .signin_for_pub (publication )
116130
131+ def export_cookies (self , path : str = "cookies.json" ):
132+ """
133+ Export cookies to a json file.
134+ Args:
135+ path: path to the json file
136+ """
137+ cookies = self ._session .cookies .get_dict ()
138+ with open (path , "w" ) as f :
139+ json .dump (cookies , f )
140+
117141 @staticmethod
118142 def _handle_response (response : requests .Response ):
119143 """
0 commit comments