--no-posts; Deprecate --{profile-pic,stories}-only
This commit is contained in:
parent
0f0ac13d72
commit
e388a1c966
@ -95,8 +95,15 @@ What to Download of each Profile
|
|||||||
|
|
||||||
.. option:: --profile-pic-only, -P
|
.. option:: --profile-pic-only, -P
|
||||||
|
|
||||||
|
.. deprecated:: 4.1
|
||||||
|
Use :option:`--no-posts`.
|
||||||
|
|
||||||
Only download profile picture.
|
Only download profile picture.
|
||||||
|
|
||||||
|
.. option:: --no-posts
|
||||||
|
|
||||||
|
Do not download regular posts.
|
||||||
|
|
||||||
.. option:: --no-profile-pic
|
.. option:: --no-profile-pic
|
||||||
|
|
||||||
Do not download profile picture.
|
Do not download profile picture.
|
||||||
@ -112,6 +119,9 @@ What to Download of each Profile
|
|||||||
|
|
||||||
.. option:: --stories-only
|
.. option:: --stories-only
|
||||||
|
|
||||||
|
.. deprecated:: 4.1
|
||||||
|
Use :option:`--stories` :option:`--no-posts`.
|
||||||
|
|
||||||
Rather than downloading regular posts of each specified profile, only
|
Rather than downloading regular posts of each specified profile, only
|
||||||
download stories. Requires :option:`--login`. Does not imply
|
download stories. Requires :option:`--login`. Does not imply
|
||||||
:option:`--no-profile-pic`.
|
:option:`--no-profile-pic`.
|
||||||
@ -121,10 +131,6 @@ What to Download of each Profile
|
|||||||
If possible, use ``:stories`` target rather than :option:`--stories-only`
|
If possible, use ``:stories`` target rather than :option:`--stories-only`
|
||||||
with all your followees. ``:stories`` uses fewer API requests.
|
with all your followees. ``:stories`` uses fewer API requests.
|
||||||
|
|
||||||
.. option:: --tagged-only
|
|
||||||
|
|
||||||
Download only post where each profile is tagged, not their regular posts.
|
|
||||||
|
|
||||||
Which Posts to Download
|
Which Posts to Download
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
@ -58,12 +58,11 @@ def filterstr_to_filterfunc(filter_str: str, item_type: type):
|
|||||||
|
|
||||||
def _main(instaloader: Instaloader, targetlist: List[str],
|
def _main(instaloader: Instaloader, targetlist: List[str],
|
||||||
username: Optional[str] = None, password: Optional[str] = None,
|
username: Optional[str] = None, password: Optional[str] = None,
|
||||||
sessionfile: Optional[str] = None, max_count: Optional[int] = None,
|
sessionfile: Optional[str] = None,
|
||||||
profile_pic: bool = True, profile_pic_only: bool = False,
|
download_profile_pic: bool = True,
|
||||||
|
download_posts=True, download_stories: bool = False, download_tagged: bool = False,
|
||||||
fast_update: bool = False,
|
fast_update: bool = False,
|
||||||
stories: bool = False, stories_only: bool = False,
|
max_count: Optional[int] = None, post_filter_str: Optional[str] = None,
|
||||||
tagged: bool = False, tagged_only: bool = False,
|
|
||||||
post_filter_str: Optional[str] = None,
|
|
||||||
storyitem_filter_str: Optional[str] = None) -> None:
|
storyitem_filter_str: Optional[str] = None) -> None:
|
||||||
"""Download set of profiles, hashtags etc. and handle logging in and session files if desired."""
|
"""Download set of profiles, hashtags etc. and handle logging in and session files if desired."""
|
||||||
# Parse and generate filter function
|
# Parse and generate filter function
|
||||||
@ -89,10 +88,6 @@ def _main(instaloader: Instaloader, targetlist: List[str],
|
|||||||
else:
|
else:
|
||||||
instaloader.interactive_login(username)
|
instaloader.interactive_login(username)
|
||||||
instaloader.context.log("Logged in as %s." % username)
|
instaloader.context.log("Logged in as %s." % username)
|
||||||
# Determine what to download
|
|
||||||
download_profile_pic = profile_pic or profile_pic_only
|
|
||||||
download_profile_posts = not (stories_only or profile_pic_only)
|
|
||||||
download_profile_stories = stories or stories_only
|
|
||||||
# Try block for KeyboardInterrupt (save session on ^C)
|
# Try block for KeyboardInterrupt (save session on ^C)
|
||||||
profiles = set()
|
profiles = set()
|
||||||
anonymous_retry_profiles = set()
|
anonymous_retry_profiles = set()
|
||||||
@ -147,7 +142,7 @@ def _main(instaloader: Instaloader, targetlist: List[str],
|
|||||||
try:
|
try:
|
||||||
profile = instaloader.check_profile_id(target)
|
profile = instaloader.check_profile_id(target)
|
||||||
if instaloader.context.is_logged_in and profile.has_blocked_viewer:
|
if instaloader.context.is_logged_in and profile.has_blocked_viewer:
|
||||||
if download_profile_pic or (download_profile_posts and not profile.is_private):
|
if download_profile_pic or ((download_posts or download_tagged) and not profile.is_private):
|
||||||
raise ProfileNotExistsException("{} blocked you; But we download her anonymously."
|
raise ProfileNotExistsException("{} blocked you; But we download her anonymously."
|
||||||
.format(target))
|
.format(target))
|
||||||
else:
|
else:
|
||||||
@ -157,39 +152,30 @@ def _main(instaloader: Instaloader, targetlist: List[str],
|
|||||||
except ProfileNotExistsException as err:
|
except ProfileNotExistsException as err:
|
||||||
# Not only our profile.has_blocked_viewer condition raises ProfileNotExistsException,
|
# Not only our profile.has_blocked_viewer condition raises ProfileNotExistsException,
|
||||||
# check_profile_id() also does, since access to blocked profile may be responded with 404.
|
# check_profile_id() also does, since access to blocked profile may be responded with 404.
|
||||||
if instaloader.context.is_logged_in and (download_profile_pic or download_profile_posts):
|
if instaloader.context.is_logged_in and (download_profile_pic or download_posts or
|
||||||
|
download_tagged):
|
||||||
instaloader.context.log(err)
|
instaloader.context.log(err)
|
||||||
instaloader.context.log("Trying again anonymously, helps in case you are just blocked.")
|
instaloader.context.log("Trying again anonymously, helps in case you are just blocked.")
|
||||||
with instaloader.anonymous_copy() as anonymous_loader:
|
with instaloader.anonymous_copy() as anonymous_loader:
|
||||||
with instaloader.context.error_catcher():
|
with instaloader.context.error_catcher():
|
||||||
anonymous_retry_profiles.add(anonymous_loader.check_profile_id(target))
|
anonymous_retry_profiles.add(anonymous_loader.check_profile_id(target))
|
||||||
instaloader.context.log("Looks good.")
|
instaloader.context.error("Warning: {} will be downloaded anonymously (\"{}\")."
|
||||||
|
.format(target, err))
|
||||||
else:
|
else:
|
||||||
raise
|
raise
|
||||||
if len(profiles) > 1:
|
if len(profiles) > 1:
|
||||||
instaloader.context.log("Downloading {} profiles: {}".format(len(profiles),
|
instaloader.context.log("Downloading {} profiles: {}".format(len(profiles),
|
||||||
' '.join([p.username for p in profiles])))
|
' '.join([p.username for p in profiles])))
|
||||||
if download_profile_pic or download_profile_posts:
|
instaloader.download_profiles(profiles,
|
||||||
# Iterate through profiles list and download them
|
download_profile_pic, download_posts, download_tagged, download_stories,
|
||||||
for target in profiles:
|
fast_update, post_filter, storyitem_filter)
|
||||||
with instaloader.context.error_catcher(target):
|
if anonymous_retry_profiles:
|
||||||
instaloader.download_profile(target, download_profile_pic, not download_profile_posts,
|
instaloader.context.log("Downloading anonymously: {}"
|
||||||
fast_update, download_tagged=tagged,
|
.format(' '.join([p.username for p in anonymous_retry_profiles])))
|
||||||
download_tagged_only=tagged_only, post_filter=post_filter)
|
with instaloader.anonymous_copy() as anonymous_loader:
|
||||||
if anonymous_retry_profiles:
|
anonymous_loader.download_profiles(anonymous_retry_profiles,
|
||||||
instaloader.context.log("Downloading anonymously: {}"
|
download_profile_pic, download_posts, download_tagged,
|
||||||
.format(' '.join([p.username for p in anonymous_retry_profiles])))
|
fast_update=fast_update, post_filter=post_filter)
|
||||||
with instaloader.anonymous_copy() as anonymous_loader:
|
|
||||||
for target in anonymous_retry_profiles:
|
|
||||||
with instaloader.context.error_catcher(target):
|
|
||||||
anonymous_loader.download_profile(target, download_profile_pic, not download_profile_posts,
|
|
||||||
fast_update, download_tagged=tagged,
|
|
||||||
download_tagged_only=tagged_only, post_filter=post_filter)
|
|
||||||
if download_profile_stories and profiles:
|
|
||||||
with instaloader.context.error_catcher("Download stories"):
|
|
||||||
instaloader.context.log("Downloading stories")
|
|
||||||
instaloader.download_stories(userids=list(profiles), fast_update=fast_update,
|
|
||||||
filename_target=None, storyitem_filter=storyitem_filter)
|
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
print("\nInterrupted by user.", file=sys.stderr)
|
print("\nInterrupted by user.", file=sys.stderr)
|
||||||
# Save session if it is useful
|
# Save session if it is useful
|
||||||
@ -240,7 +226,9 @@ def main():
|
|||||||
g_prof = parser.add_argument_group("What to Download of each Profile")
|
g_prof = parser.add_argument_group("What to Download of each Profile")
|
||||||
|
|
||||||
g_prof.add_argument('-P', '--profile-pic-only', action='store_true',
|
g_prof.add_argument('-P', '--profile-pic-only', action='store_true',
|
||||||
help='Only download profile picture.')
|
help=SUPPRESS)
|
||||||
|
g_prof.add_argument('--no-posts', action='store_true',
|
||||||
|
help="Do not download regular posts.")
|
||||||
g_prof.add_argument('--no-profile-pic', action='store_true',
|
g_prof.add_argument('--no-profile-pic', action='store_true',
|
||||||
help='Do not download profile picture.')
|
help='Do not download profile picture.')
|
||||||
g_post.add_argument('--no-pictures', action='store_true',
|
g_post.add_argument('--no-pictures', action='store_true',
|
||||||
@ -274,12 +262,9 @@ def main():
|
|||||||
g_prof.add_argument('-s', '--stories', action='store_true',
|
g_prof.add_argument('-s', '--stories', action='store_true',
|
||||||
help='Also download stories of each profile that is downloaded. Requires --login.')
|
help='Also download stories of each profile that is downloaded. Requires --login.')
|
||||||
g_prof.add_argument('--stories-only', action='store_true',
|
g_prof.add_argument('--stories-only', action='store_true',
|
||||||
help='Rather than downloading regular posts of each specified profile, only download '
|
help=SUPPRESS)
|
||||||
'stories. Requires --login. Does not imply --no-profile-pic.')
|
|
||||||
g_prof.add_argument('--tagged', action='store_true',
|
g_prof.add_argument('--tagged', action='store_true',
|
||||||
help='Also download posts where each profile is tagged.')
|
help='Also download posts where each profile is tagged.')
|
||||||
g_prof.add_argument('--tagged-only', action='store_true',
|
|
||||||
help='Download only post where each profile is tagged, not their regular posts.')
|
|
||||||
|
|
||||||
g_cond = parser.add_argument_group("Which Posts to Download")
|
g_cond = parser.add_argument_group("Which Posts to Download")
|
||||||
|
|
||||||
@ -369,6 +354,11 @@ def main():
|
|||||||
if args.no_pictures and args.fast_update:
|
if args.no_pictures and args.fast_update:
|
||||||
raise SystemExit('--no-pictures and --fast-update cannot be used together.')
|
raise SystemExit('--no-pictures and --fast-update cannot be used together.')
|
||||||
|
|
||||||
|
# Determine what to download
|
||||||
|
download_profile_pic = not args.no_profile_pic or args.profile_pic_only
|
||||||
|
download_posts = not (args.no_posts or args.stories_only or args.profile_pic_only)
|
||||||
|
download_stories = args.stories or args.stories_only
|
||||||
|
|
||||||
loader = Instaloader(sleep=not args.no_sleep, quiet=args.quiet, user_agent=args.user_agent,
|
loader = Instaloader(sleep=not args.no_sleep, quiet=args.quiet, user_agent=args.user_agent,
|
||||||
dirname_pattern=args.dirname_pattern, filename_pattern=args.filename_pattern,
|
dirname_pattern=args.dirname_pattern, filename_pattern=args.filename_pattern,
|
||||||
download_pictures=not args.no_pictures,
|
download_pictures=not args.no_pictures,
|
||||||
@ -385,14 +375,12 @@ def main():
|
|||||||
username=args.login.lower() if args.login is not None else None,
|
username=args.login.lower() if args.login is not None else None,
|
||||||
password=args.password,
|
password=args.password,
|
||||||
sessionfile=args.sessionfile,
|
sessionfile=args.sessionfile,
|
||||||
max_count=int(args.count) if args.count is not None else None,
|
download_profile_pic=download_profile_pic,
|
||||||
profile_pic=not args.no_profile_pic,
|
download_posts=download_posts,
|
||||||
profile_pic_only=args.profile_pic_only,
|
download_stories=download_stories,
|
||||||
|
download_tagged=args.tagged,
|
||||||
fast_update=args.fast_update,
|
fast_update=args.fast_update,
|
||||||
stories=args.stories,
|
max_count=int(args.count) if args.count is not None else None,
|
||||||
stories_only=args.stories_only,
|
|
||||||
tagged=args.tagged,
|
|
||||||
tagged_only=args.tagged_only,
|
|
||||||
post_filter_str=args.post_filter,
|
post_filter_str=args.post_filter,
|
||||||
storyitem_filter_str=args.storyitem_filter)
|
storyitem_filter_str=args.storyitem_filter)
|
||||||
loader.close()
|
loader.close()
|
||||||
|
@ -11,7 +11,7 @@ from contextlib import contextmanager, suppress
|
|||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
from typing import Any, Callable, Iterator, List, Optional, Union
|
from typing import Any, Callable, Iterator, List, Optional, Set, Union
|
||||||
|
|
||||||
from .exceptions import *
|
from .exceptions import *
|
||||||
from .instaloadercontext import InstaloaderContext
|
from .instaloadercontext import InstaloaderContext
|
||||||
@ -707,6 +707,72 @@ class Instaloader:
|
|||||||
return profile
|
return profile
|
||||||
raise ProfileNotExistsException("Profile {0} does not exist.".format(profile_name))
|
raise ProfileNotExistsException("Profile {0} does not exist.".format(profile_name))
|
||||||
|
|
||||||
|
def download_profiles(self, profiles: Set[Profile],
|
||||||
|
profile_pic: bool = True, posts: bool = True, tagged: bool = False, stories: bool = False,
|
||||||
|
fast_update: bool = False,
|
||||||
|
post_filter: Optional[Callable[[Post], bool]] = None,
|
||||||
|
storyitem_filter: Optional[Callable[[Post], bool]] = None):
|
||||||
|
"""High-level method to download set of profiles.
|
||||||
|
|
||||||
|
:param profiles: Set of profiles to download.
|
||||||
|
:param profile_pic: not :option:`--no-profile-pic`.
|
||||||
|
:param posts: not :option:`--no-posts`.
|
||||||
|
:param tagged: :option:`--tagged`.
|
||||||
|
:param stories: :option:`--stories`.
|
||||||
|
:param fast_update: :option:`--fast-update`.
|
||||||
|
:param post_filter: :option:`--post-filter`.
|
||||||
|
:param storyitem_filter: :option:`--post-filter`."""
|
||||||
|
|
||||||
|
for profile in profiles:
|
||||||
|
with self.context.error_catcher(profile.username):
|
||||||
|
profile_name = profile.username
|
||||||
|
|
||||||
|
# Save metadata as JSON if desired.
|
||||||
|
if self.save_metadata:
|
||||||
|
json_filename = '{0}/{1}_{2}'.format(self.dirname_pattern.format(profile=profile_name,
|
||||||
|
target=profile_name),
|
||||||
|
profile_name, profile.userid)
|
||||||
|
self.save_metadata_json(json_filename, profile)
|
||||||
|
|
||||||
|
# Download profile picture
|
||||||
|
if profile_pic:
|
||||||
|
with self.context.error_catcher('Download profile picture of {}'.format(profile_name)):
|
||||||
|
self.download_profilepic(profile)
|
||||||
|
|
||||||
|
# Catch some errors
|
||||||
|
if profile.is_private:
|
||||||
|
if not self.context.is_logged_in:
|
||||||
|
raise LoginRequiredException("--login=USERNAME required.")
|
||||||
|
if not profile.followed_by_viewer and self.context.username != profile.username:
|
||||||
|
raise PrivateProfileNotFollowedException("Private but not followed.")
|
||||||
|
|
||||||
|
# Download tagged, if requested
|
||||||
|
if tagged:
|
||||||
|
with self.context.error_catcher('Download tagged of {}'.format(profile_name)):
|
||||||
|
self.download_tagged(profile, fast_update=fast_update, post_filter=post_filter)
|
||||||
|
|
||||||
|
# Iterate over pictures and download them
|
||||||
|
if posts:
|
||||||
|
self.context.log("Retrieving posts from profile {}.".format(profile_name))
|
||||||
|
totalcount = profile.mediacount
|
||||||
|
count = 1
|
||||||
|
for post in profile.get_posts():
|
||||||
|
self.context.log("[%3i/%3i] " % (count, totalcount), end="", flush=True)
|
||||||
|
count += 1
|
||||||
|
if post_filter is not None and not post_filter(post):
|
||||||
|
self.context.log('<skipped>')
|
||||||
|
continue
|
||||||
|
with self.context.error_catcher("Download {} of {}".format(post, profile_name)):
|
||||||
|
downloaded = self.download_post(post, target=profile_name)
|
||||||
|
if fast_update and not downloaded:
|
||||||
|
break
|
||||||
|
|
||||||
|
if stories and profiles:
|
||||||
|
with self.context.error_catcher("Download stories"):
|
||||||
|
self.context.log("Downloading stories")
|
||||||
|
self.download_stories(userids=list(profiles), fast_update=fast_update, filename_target=None,
|
||||||
|
storyitem_filter=storyitem_filter)
|
||||||
|
|
||||||
def download_profile(self, profile_name: Union[str, Profile],
|
def download_profile(self, profile_name: Union[str, Profile],
|
||||||
profile_pic: bool = True, profile_pic_only: bool = False,
|
profile_pic: bool = True, profile_pic_only: bool = False,
|
||||||
fast_update: bool = False,
|
fast_update: bool = False,
|
||||||
@ -714,7 +780,11 @@ class Instaloader:
|
|||||||
download_tagged: bool = False, download_tagged_only: bool = False,
|
download_tagged: bool = False, download_tagged_only: bool = False,
|
||||||
post_filter: Optional[Callable[[Post], bool]] = None,
|
post_filter: Optional[Callable[[Post], bool]] = None,
|
||||||
storyitem_filter: Optional[Callable[[StoryItem], bool]] = None) -> None:
|
storyitem_filter: Optional[Callable[[StoryItem], bool]] = None) -> None:
|
||||||
"""Download one profile"""
|
"""Download one profile
|
||||||
|
|
||||||
|
.. deprecated:: 4.1
|
||||||
|
Use :meth:`Instaloader.download_profiles`.
|
||||||
|
"""
|
||||||
|
|
||||||
# Get profile main page json
|
# Get profile main page json
|
||||||
# check if profile does exist or name has changed since last download
|
# check if profile does exist or name has changed since last download
|
||||||
|
Loading…
x
Reference in New Issue
Block a user