1
0
mirror of https://github.com/instaloader/instaloader.git synced 2024-07-07 11:42:38 +02:00

Various minor fixes

* Fix Post.owner_profile in cases where initial owner struct contains id
  only

* Assert node structure is complete enough at Post creation

* Fix get_followees() call in _main()

* Prefer importing from '.' rather than '.<submodule>' in __main__

* Fix name of instaloader_unittests ('-' is illegal in module names)

* Foreport 5fe2a70374
  "Fix downloading of hashtags"

* Foreport 67ac8f3397
  "Enforce being logged in for getting username by id"
This commit is contained in:
Alexander Graf 2018-04-11 10:45:38 +02:00
parent 5b9590a768
commit 25b8165547
4 changed files with 42 additions and 13 deletions

View File

@ -6,11 +6,10 @@ import sys
from argparse import ArgumentParser, SUPPRESS
from typing import Callable, List, Optional
from . import __version__
from .exceptions import *
from .instaloader import Instaloader, Tristate, get_default_session_filename
from . import (Instaloader, InstaloaderException, InvalidArgumentException, Post, Profile, ProfileNotExistsException,
Tristate, __version__)
from .instaloader import get_default_session_filename
from .instaloadercontext import default_user_agent
from .structures import Post
def usage_string():
@ -92,7 +91,8 @@ def _main(instaloader: Instaloader, targetlist: List[str],
with instaloader.context.error_catcher(target):
if target[0] == '@':
instaloader.context.log("Retrieving followees of %s..." % target[1:])
profiles.update([followee['username'] for followee in instaloader.get_followees(target[1:])])
followees = instaloader.get_followees(Profile.from_username(instaloader.context, target[1:]))
profiles.update([followee['username'] for followee in followees])
elif target[0] == '#':
instaloader.download_hashtag(hashtag=target[1:], max_count=max_count, fast_update=fast_update,
filter_func=filter_func)

View File

@ -607,12 +607,18 @@ class Instaloader:
def get_hashtag_posts(self, hashtag: str) -> Iterator[Post]:
"""Get Posts associated with a #hashtag."""
yield from (Post(self.context, node)
for node in self.context.graphql_node_list("298b92c8d7cad703f7565aa892ede943",
{'tag_name': hashtag},
'https://www.instagram.com/explore/tags/{0}/'
.format(hashtag),
lambda d: d['data']['hashtag']['edge_hashtag_to_media']))
has_next_page = True
end_cursor = None
while has_next_page:
if end_cursor:
params = {'__a': 1, 'max_id': end_cursor}
else:
params = {'__a': 1}
hashtag_data = self.context.get_json('explore/tags/{0}/'.format(hashtag),
params)['graphql']['hashtag']['edge_hashtag_to_media']
yield from (Post(self.context, edge['node']) for edge in hashtag_data['edges'])
has_next_page = hashtag_data['page_info']['has_next_page']
end_cursor = hashtag_data['page_info']['end_cursor']
def download_hashtag(self, hashtag: str,
max_count: Optional[int] = None,
@ -675,6 +681,10 @@ class Instaloader:
else:
self.context.log("Trying to find profile {0} using its unique ID {1}.".format(profile_name,
profile_id))
if not self.context.is_logged_in:
self.context.error("Profile {} changed its name. "
"If you use --login=USERNAME, I can find out the new name.")
raise LoginRequiredException("--login=USERNAME required to obtain profile name from its ID number")
profile_from_id = Profile.from_id(self.context, profile_id)
newname = profile_from_id.username
self.context.log("Profile {0} has changed its name to {1}.".format(profile_name, newname))

View File

@ -43,7 +43,15 @@ class Post:
:param node: Node structure, as returned by Instagram.
:param owner_profile: The Profile of the owner, if already known at creation.
"""
assert 'shortcode' in node
# Ensure node contains all the data that is accessed via self._node
assert 'shortcode' in node or 'code' in node
assert 'id' in node
assert 'owner' in node
assert 'date' in node or 'taken_at_timestamp' in node
assert 'display_url' in node or 'display_src' in node
assert 'is_video' in node
self._context = context
self._node = node
self._owner_profile = owner_profile
@ -109,10 +117,18 @@ class Post:
@property
def owner_profile(self) -> 'Profile':
if not self._owner_profile:
owner_struct = self._field('owner')
if 'username' in self._node['owner']:
owner_struct = self._node['owner']
else:
# Sometimes, the 'owner' structure does not contain the username, only the user's ID. In that case,
# this call triggers downloading of the complete Post metadata struct, where the owner username
# is contained. This is better than to get the username by user ID, since it is possible anonymously
# and gives us other information that is more likely to be usable.
owner_struct = self._full_metadata['owner']
if 'username' in owner_struct:
self._owner_profile = Profile(self._context, owner_struct)
else:
# Fallback, if we still did not get the owner username
self._owner_profile = Profile.from_id(self._context, owner_struct['id'])
return self._owner_profile
@ -303,6 +319,8 @@ class Profile:
@classmethod
def from_id(cls, context: InstaloaderContext, profile_id: int):
if not context.is_logged_in:
raise LoginRequiredException("--login=USERNAME required to obtain profile metadata from its ID number.")
data = context.graphql_query("472f257a40c653c64c666ce877d59d2b",
{'id': str(profile_id), 'first': 1})['data']['user']
if data:

View File

@ -91,6 +91,7 @@ class TestInstaloader(unittest.TestCase):
print(f['username'])
def test_get_username_by_id(self):
self.L.load_session_from_file(OWN_USERNAME)
self.assertEqual(PUBLIC_PROFILE.lower(),
instaloader.Profile.from_id(self.L.context, PUBLIC_PROFILE_ID).username)