1
0
mirror of https://github.com/instaloader/instaloader.git synced 2024-09-11 16:22:24 +02:00

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:
Alexander Graf 2017-07-14 11:00:22 +02:00
parent 8607135740
commit c0eecd1bd2

View File

@ -407,24 +407,22 @@ class Instaloader:
self._log("Saved session to %s." % filename) self._log("Saved session to %s." % filename)
def load_session_from_file(self, username: str, filename: Optional[str] = None) -> None: def load_session_from_file(self, username: str, filename: Optional[str] = None) -> None:
"""Returns loaded requests.Session object, or None if not found.""" """Internally stores requests.Session object loaded from file.
self.username = username
using_default_session = False 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: if filename is None:
filename = get_default_session_filename(username) filename = get_default_session_filename(username)
using_default_session = True with open(filename, 'rb') as sessionfile:
try: session = requests.Session()
with open(filename, 'rb') as sessionfile: session.cookies = requests.utils.cookiejar_from_dict(pickle.load(sessionfile))
session = requests.Session() session.headers.update(default_http_header())
session.cookies = requests.utils.cookiejar_from_dict(pickle.load(sessionfile)) session.headers.update({'X-CSRFToken': session.cookies.get_dict()['csrftoken']})
session.headers.update(default_http_header()) self._log("Loaded session from %s." % filename)
session.headers.update({'X-CSRFToken': session.cookies.get_dict()['csrftoken']}) self.session = session
self._log("Loaded session from %s." % filename) self.username = username
self.session = session
self.username = username
except FileNotFoundError as err:
if not using_default_session:
print(err, file=sys.stderr)
def test_login(self, session: requests.Session) -> Optional[str]: def test_login(self, session: requests.Session) -> Optional[str]:
"""Returns the Instagram username to which given requests.Session object belongs, or None.""" """Returns the Instagram username to which given requests.Session object belongs, or None."""
@ -766,13 +764,13 @@ class Instaloader:
return return
data = self.get_json(name, max_id=get_last_id(data)) data = self.get_json(name, max_id=get_last_id(data))
def interactive_login(self, username: str, password: Optional[str] = None) -> None: def interactive_login(self, username: str) -> None:
"""Logs in and returns session, asking user for password if needed""" """Logs in and internally stores session, asking user for password interactively.
if password is not None:
self.login(username, password) :raises LoginRequiredException: when in quiet mode."""
return
if self.quiet: if self.quiet:
raise LoginRequiredException("Quiet mode requires given password or valid session file.") raise LoginRequiredException("Quiet mode requires given password or valid session file.")
password = None
while password is None: while password is None:
password = getpass.getpass(prompt="Enter Instagram password for %s: " % username) password = getpass.getpass(prompt="Enter Instagram password for %s: " % username)
try: try:
@ -786,12 +784,20 @@ class Instaloader:
profile_pic_only: bool = False, download_videos: bool = True, geotags: bool = False, profile_pic_only: bool = False, download_videos: bool = True, geotags: bool = False,
fast_update: bool = False, hashtag_lookup_username: bool = False) -> None: fast_update: bool = False, hashtag_lookup_username: bool = False) -> None:
"""Download set of profiles and handle sessions""" """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 # Login, if desired
if username is not None: 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): 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) self._log("Logged in as %s." % username)
# Try block for KeyboardInterrupt (save session on ^C) # Try block for KeyboardInterrupt (save session on ^C)
failedtargets = [] failedtargets = []
@ -804,22 +810,31 @@ class Instaloader:
self.download_hashtag(hashtag=pentry[1:], max_count=max_count, fast_update=fast_update, self.download_hashtag(hashtag=pentry[1:], max_count=max_count, fast_update=fast_update,
download_videos=download_videos, geotags=geotags, download_videos=download_videos, geotags=geotags,
lookup_username=hashtag_lookup_username) lookup_username=hashtag_lookup_username)
elif pentry[0] == '@' and username is not None: elif pentry[0] == '@':
self._log("Retrieving followees of %s..." % pentry[1:]) if username is not None:
followees = self.get_followees(pentry[1:]) self._log("Retrieving followees of %s..." % pentry[1:])
targets.update([followee['username'] for followee in followees]) followees = self.get_followees(pentry[1:])
elif pentry == ":feed-all" and username is not None: targets.update([followee['username'] for followee in followees])
self._log("Retrieving pictures from your feed...") else:
self.download_feed_pics(fast_update=fast_update, max_count=max_count, print("--login=USERNAME required to download {}.".format(pentry), file=sys.stderr)
download_videos=download_videos, geotags=geotags) elif pentry == ":feed-all":
elif pentry == ":feed-liked" and username is not None: if username is not None:
self._log("Retrieving pictures you liked from your feed...") self._log("Retrieving pictures from your feed...")
self.download_feed_pics(fast_update=fast_update, max_count=max_count, self.download_feed_pics(fast_update=fast_update, max_count=max_count,
filter_func=lambda node: download_videos=download_videos, geotags=geotags)
not node["likes"]["viewer_has_liked"] else:
if "likes" in node print("--login=USERNAME required to download {}.".format(pentry), file=sys.stderr)
else not node["viewer_has_liked"], elif pentry == ":feed-liked":
download_videos=download_videos, geotags=geotags) 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: else:
targets.add(pentry) targets.add(pentry)
if len(targets) > 1: if len(targets) > 1:
@ -869,7 +884,8 @@ def main():
'profiles, but if you want to download private profiles or all followees of ' 'profiles, but if you want to download private profiles or all followees of '
'some profile, you have to specify a username used to login.') 'some profile, you have to specify a username used to login.')
parser.add_argument('-p', '--password', metavar='YOUR-PASSWORD', 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 ' '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 ' '--password is not given. Specifying this option without --login has no '
'effect.') 'effect.')