Download Hashtag profilepic and save metadata JSON

This commit is contained in:
Alexander Graf
2020-04-19 10:31:58 +02:00
parent 83a0f52c60
commit c9e4f68597
3 changed files with 37 additions and 11 deletions

View File

@@ -144,7 +144,8 @@ def _main(instaloader: Instaloader, targetlist: List[str],
profiles.add(followee) profiles.add(followee)
elif target[0] == '#': elif target[0] == '#':
instaloader.download_hashtag(hashtag=target[1:], max_count=max_count, fast_update=fast_update, instaloader.download_hashtag(hashtag=target[1:], max_count=max_count, fast_update=fast_update,
post_filter=post_filter) post_filter=post_filter,
profile_pic=download_profile_pic, posts=download_posts)
elif target[0] == '-': elif target[0] == '-':
instaloader.download_post(Post.from_shortcode(instaloader.context, target[1:]), target) instaloader.download_post(Post.from_shortcode(instaloader.context, target[1:]), target)
elif target[0] == "%": elif target[0] == "%":

View File

@@ -358,7 +358,7 @@ class Instaloader:
self.context.log('geo', end=' ', flush=True) self.context.log('geo', end=' ', flush=True)
@_retry_on_connection_error @_retry_on_connection_error
def download_title_pic(self, url: str, target: Union[str, Path], name_suffix: str, owner_profile: Profile, def download_title_pic(self, url: str, target: Union[str, Path], name_suffix: str, owner_profile: Optional[Profile],
_attempt: int = 1) -> None: _attempt: int = 1) -> None:
"""Downloads and saves a picture that does not have an association with a Post or StoryItem, such as a """Downloads and saves a picture that does not have an association with a Post or StoryItem, such as a
Profile picture or a Highlight cover picture. Modification time is taken from the HTTP response headers. Profile picture or a Highlight cover picture. Modification time is taken from the HTTP response headers.
@@ -380,7 +380,8 @@ class Instaloader:
pic_extension = 'jpg' pic_extension = 'jpg'
if ((format_string_contains_key(self.dirname_pattern, 'profile') or if ((format_string_contains_key(self.dirname_pattern, 'profile') or
format_string_contains_key(self.dirname_pattern, 'target'))): format_string_contains_key(self.dirname_pattern, 'target'))):
filename = '{0}/{1}_{2}.{3}'.format(self.dirname_pattern.format(profile=owner_profile.username.lower(), profile_str = owner_profile.username.lower() if owner_profile is not None else target
filename = '{0}/{1}_{2}.{3}'.format(self.dirname_pattern.format(profile=profile_str,
target=target), target=target),
pic_identifier, name_suffix, pic_extension) pic_identifier, name_suffix, pic_extension)
else: else:
@@ -408,6 +409,12 @@ class Instaloader:
.. versionadded:: 4.3""" .. versionadded:: 4.3"""
self.download_title_pic(highlight.cover_url, target, 'cover', highlight.owner_profile) self.download_title_pic(highlight.cover_url, target, 'cover', highlight.owner_profile)
def download_hashtag_profilepic(self, hashtag: Hashtag) -> None:
"""Downloads and saves the profile picture of a Hashtag.
.. versionadded:: 4.4"""
self.download_title_pic(hashtag.profile_pic_url, '#' + hashtag.name, 'profile_pic', None)
@_requires_login @_requires_login
def save_session_to_file(self, filename: Optional[str] = None) -> None: def save_session_to_file(self, filename: Optional[str] = None) -> None:
"""Saves internally stored :class:`requests.Session` object. """Saves internally stored :class:`requests.Session` object.
@@ -888,7 +895,9 @@ class Instaloader:
def download_hashtag(self, hashtag: Union[Hashtag, str], def download_hashtag(self, hashtag: Union[Hashtag, str],
max_count: Optional[int] = None, max_count: Optional[int] = None,
post_filter: Optional[Callable[[Post], bool]] = None, post_filter: Optional[Callable[[Post], bool]] = None,
fast_update: bool = False) -> None: fast_update: bool = False,
profile_pic: bool = True,
posts: bool = True) -> None:
"""Download pictures of one hashtag. """Download pictures of one hashtag.
To download the last 30 pictures with hashtag #cat, do:: To download the last 30 pictures with hashtag #cat, do::
@@ -900,14 +909,30 @@ class Instaloader:
:param max_count: Maximum count of pictures to download :param max_count: Maximum count of pictures to download
:param post_filter: function(post), which returns True if given picture should be downloaded :param post_filter: function(post), which returns True if given picture should be downloaded
:param fast_update: If true, abort when first already-downloaded picture is encountered :param fast_update: If true, abort when first already-downloaded picture is encountered
:param profile_pic: not :option:`--no-profile-pic`.
:param posts: not :option:`--no-posts`.
.. versionchanged:: 4.4
Add parameters `profile_pic` and `posts`.
""" """
if isinstance(hashtag, str): if isinstance(hashtag, str):
with self.context.error_catcher("Get hashtag #{}".format(hashtag)): with self.context.error_catcher("Get hashtag #{}".format(hashtag)):
hashtag = Hashtag.from_name(self.context, hashtag) hashtag = Hashtag.from_name(self.context, hashtag)
assert isinstance(hashtag, Hashtag) if not isinstance(hashtag, Hashtag):
self.context.log("Retrieving pictures with hashtag #{}...".format(hashtag.name)) return
self.posts_download_loop(hashtag.get_posts(), "#" + hashtag.name, fast_update, post_filter, target = "#" + hashtag.name
max_count=max_count) if profile_pic:
with self.context.error_catcher("Download profile picture of {}".format(target)):
self.download_hashtag_profilepic(hashtag)
if posts:
self.context.log("Retrieving pictures with hashtag #{}...".format(hashtag.name))
self.posts_download_loop(hashtag.get_posts(), target, fast_update, post_filter,
max_count=max_count)
if self.save_metadata:
json_filename = '{0}/{1}'.format(self.dirname_pattern.format(profile=target,
target=target),
target)
self.save_metadata_json(json_filename, hashtag)
def download_tagged(self, profile: Profile, fast_update: bool = False, def download_tagged(self, profile: Profile, fast_update: bool = False,
target: Optional[str] = None, target: Optional[str] = None,

View File

@@ -1169,8 +1169,8 @@ class Hashtag:
@property @property
def name(self): def name(self):
"""Hashtag name, without preceeding '#'""" """Hashtag name lowercased, without preceeding '#'"""
return self._node["name"] return self._node["name"].lower()
def _query(self, params): def _query(self, params):
return self._context.get_json("explore/tags/{0}/".format(self.name), return self._context.get_json("explore/tags/{0}/".format(self.name),
@@ -1189,7 +1189,7 @@ class Hashtag:
def __eq__(self, other: object) -> bool: def __eq__(self, other: object) -> bool:
if isinstance(other, Hashtag): if isinstance(other, Hashtag):
return self.name.lower() == other.name.lower() return self.name == other.name
return NotImplemented return NotImplemented
def __hash__(self) -> int: def __hash__(self) -> int: