Usability fixes in improvements
On module level: Cleaner exception handling for load_session_from file interactive_login logs in interactively now, always asking the user for password. Before, it had an optional password parameter determining whether it was interactive or not. On application level: Warn if profile specifiers are used which require login, but not --login flag was given (@profile, :feed-all, :feed-liked). Clearly warn that --password is insecure.
This commit is contained in:
parent
8607135740
commit
c0eecd1bd2
@ -407,24 +407,22 @@ class Instaloader:
|
||||
self._log("Saved session to %s." % filename)
|
||||
|
||||
def load_session_from_file(self, username: str, filename: Optional[str] = None) -> None:
|
||||
"""Returns loaded requests.Session object, or None if not found."""
|
||||
self.username = username
|
||||
using_default_session = False
|
||||
"""Internally stores requests.Session object loaded from file.
|
||||
|
||||
If filename is None, the file with the default session path is loaded.
|
||||
|
||||
:raises FileNotFoundError; If the file does not exist.
|
||||
"""
|
||||
if filename is None:
|
||||
filename = get_default_session_filename(username)
|
||||
using_default_session = True
|
||||
try:
|
||||
with open(filename, 'rb') as sessionfile:
|
||||
session = requests.Session()
|
||||
session.cookies = requests.utils.cookiejar_from_dict(pickle.load(sessionfile))
|
||||
session.headers.update(default_http_header())
|
||||
session.headers.update({'X-CSRFToken': session.cookies.get_dict()['csrftoken']})
|
||||
self._log("Loaded session from %s." % filename)
|
||||
self.session = session
|
||||
self.username = username
|
||||
except FileNotFoundError as err:
|
||||
if not using_default_session:
|
||||
print(err, file=sys.stderr)
|
||||
with open(filename, 'rb') as sessionfile:
|
||||
session = requests.Session()
|
||||
session.cookies = requests.utils.cookiejar_from_dict(pickle.load(sessionfile))
|
||||
session.headers.update(default_http_header())
|
||||
session.headers.update({'X-CSRFToken': session.cookies.get_dict()['csrftoken']})
|
||||
self._log("Loaded session from %s." % filename)
|
||||
self.session = session
|
||||
self.username = username
|
||||
|
||||
def test_login(self, session: requests.Session) -> Optional[str]:
|
||||
"""Returns the Instagram username to which given requests.Session object belongs, or None."""
|
||||
@ -766,13 +764,13 @@ class Instaloader:
|
||||
return
|
||||
data = self.get_json(name, max_id=get_last_id(data))
|
||||
|
||||
def interactive_login(self, username: str, password: Optional[str] = None) -> None:
|
||||
"""Logs in and returns session, asking user for password if needed"""
|
||||
if password is not None:
|
||||
self.login(username, password)
|
||||
return
|
||||
def interactive_login(self, username: str) -> None:
|
||||
"""Logs in and internally stores session, asking user for password interactively.
|
||||
|
||||
:raises LoginRequiredException: when in quiet mode."""
|
||||
if self.quiet:
|
||||
raise LoginRequiredException("Quiet mode requires given password or valid session file.")
|
||||
password = None
|
||||
while password is None:
|
||||
password = getpass.getpass(prompt="Enter Instagram password for %s: " % username)
|
||||
try:
|
||||
@ -786,12 +784,20 @@ class Instaloader:
|
||||
profile_pic_only: bool = False, download_videos: bool = True, geotags: bool = False,
|
||||
fast_update: bool = False, hashtag_lookup_username: bool = False) -> None:
|
||||
"""Download set of profiles and handle sessions"""
|
||||
# pylint:disable=too-many-branches,too-many-locals
|
||||
# pylint:disable=too-many-branches,too-many-locals,too-many-statements
|
||||
# Login, if desired
|
||||
if username is not None:
|
||||
self.load_session_from_file(username, sessionfile)
|
||||
try:
|
||||
self.load_session_from_file(username, sessionfile)
|
||||
except FileNotFoundError as err:
|
||||
if sessionfile is not None:
|
||||
print(err, file=sys.stderr)
|
||||
self._log("Session file does not exist yet - Logging in.")
|
||||
if username != self.test_login(self.session):
|
||||
self.interactive_login(username, password)
|
||||
if password is not None:
|
||||
self.login(username, password)
|
||||
else:
|
||||
self.interactive_login(username)
|
||||
self._log("Logged in as %s." % username)
|
||||
# Try block for KeyboardInterrupt (save session on ^C)
|
||||
failedtargets = []
|
||||
@ -804,22 +810,31 @@ class Instaloader:
|
||||
self.download_hashtag(hashtag=pentry[1:], max_count=max_count, fast_update=fast_update,
|
||||
download_videos=download_videos, geotags=geotags,
|
||||
lookup_username=hashtag_lookup_username)
|
||||
elif pentry[0] == '@' and username is not None:
|
||||
self._log("Retrieving followees of %s..." % pentry[1:])
|
||||
followees = self.get_followees(pentry[1:])
|
||||
targets.update([followee['username'] for followee in followees])
|
||||
elif pentry == ":feed-all" and username is not None:
|
||||
self._log("Retrieving pictures from your feed...")
|
||||
self.download_feed_pics(fast_update=fast_update, max_count=max_count,
|
||||
download_videos=download_videos, geotags=geotags)
|
||||
elif pentry == ":feed-liked" and username is not None:
|
||||
self._log("Retrieving pictures you liked from your feed...")
|
||||
self.download_feed_pics(fast_update=fast_update, max_count=max_count,
|
||||
filter_func=lambda node:
|
||||
not node["likes"]["viewer_has_liked"]
|
||||
if "likes" in node
|
||||
else not node["viewer_has_liked"],
|
||||
download_videos=download_videos, geotags=geotags)
|
||||
elif pentry[0] == '@':
|
||||
if username is not None:
|
||||
self._log("Retrieving followees of %s..." % pentry[1:])
|
||||
followees = self.get_followees(pentry[1:])
|
||||
targets.update([followee['username'] for followee in followees])
|
||||
else:
|
||||
print("--login=USERNAME required to download {}.".format(pentry), file=sys.stderr)
|
||||
elif pentry == ":feed-all":
|
||||
if username is not None:
|
||||
self._log("Retrieving pictures from your feed...")
|
||||
self.download_feed_pics(fast_update=fast_update, max_count=max_count,
|
||||
download_videos=download_videos, geotags=geotags)
|
||||
else:
|
||||
print("--login=USERNAME required to download {}.".format(pentry), file=sys.stderr)
|
||||
elif pentry == ":feed-liked":
|
||||
if username is not None:
|
||||
self._log("Retrieving pictures you liked from your feed...")
|
||||
self.download_feed_pics(fast_update=fast_update, max_count=max_count,
|
||||
filter_func=lambda node:
|
||||
not node["likes"]["viewer_has_liked"]
|
||||
if "likes" in node
|
||||
else not node["viewer_has_liked"],
|
||||
download_videos=download_videos, geotags=geotags)
|
||||
else:
|
||||
print("--login=USERNAME required to download {}.".format(pentry), file=sys.stderr)
|
||||
else:
|
||||
targets.add(pentry)
|
||||
if len(targets) > 1:
|
||||
@ -869,7 +884,8 @@ def main():
|
||||
'profiles, but if you want to download private profiles or all followees of '
|
||||
'some profile, you have to specify a username used to login.')
|
||||
parser.add_argument('-p', '--password', metavar='YOUR-PASSWORD',
|
||||
help='Password for your Instagram account. If --login is given and there is '
|
||||
help='Note that specifying passwords on command line is considered insecure! '
|
||||
'Password for your Instagram account. If --login is given and there is '
|
||||
'not yet a valid session file, you\'ll be prompted for your password if '
|
||||
'--password is not given. Specifying this option without --login has no '
|
||||
'effect.')
|
||||
|
Loading…
Reference in New Issue
Block a user