From 9e04ef343673ee1f45186b5c2546ab674df3e6c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Koch-Kramer?= Date: Mon, 4 Feb 2019 22:57:05 +0100 Subject: [PATCH] New Profile.from_id() that works without posts The old method needed the target profile to have at least one post. The new method works anonymously even for private profiles. Closes #249. --- instaloader/exceptions.py | 4 ++++ instaloader/structures.py | 21 ++++++++++----------- test/instaloader_unittests.py | 17 ++++++++++++----- 3 files changed, 26 insertions(+), 16 deletions(-) diff --git a/instaloader/exceptions.py b/instaloader/exceptions.py index 29b55a9..5041f3a 100644 --- a/instaloader/exceptions.py +++ b/instaloader/exceptions.py @@ -22,6 +22,10 @@ class ProfileNotExistsException(InstaloaderException): class ProfileHasNoPicsException(InstaloaderException): + """ + .. deprecated:: 4.2.2 + Not raised anymore. + """ pass diff --git a/instaloader/structures.py b/instaloader/structures.py index 678d350..22f0465 100644 --- a/instaloader/structures.py +++ b/instaloader/structures.py @@ -396,28 +396,27 @@ class Profile: @classmethod def from_id(cls, context: InstaloaderContext, profile_id: int): """Create a Profile instance from a given userid. If possible, use :meth:`Profile.from_username` - or constructor directly rather than this method, since it does many requests. + or constructor directly rather than this method, since it requires more requests. :param context: :attr:`Instaloader.context` :param profile_id: userid - :raises: :class:`ProfileNotExistsException`, :class:`ProfileHasNoPicsException` + :raises: :class:`ProfileNotExistsException` """ if profile_id in context.profile_id_cache: return context.profile_id_cache[profile_id] - data = context.graphql_query("472f257a40c653c64c666ce877d59d2b", - {'id': str(profile_id), 'first': 1}, + data = context.graphql_query('7c16654f22c819fb63d1183034a5162f', + {'user_id': str(profile_id), + 'include_chaining': False, + 'include_reel': True, + 'include_suggested_users': False, + 'include_logged_out_extras': False, + 'include_highlight_reels': False}, rhx_gis=context.root_rhx_gis)['data']['user'] if data: - data = data["edge_owner_to_timeline_media"] + profile = cls(context, data['reel']['owner']) else: raise ProfileNotExistsException("No profile found, the user may have blocked you (ID: " + str(profile_id) + ").") - if not data['edges']: - if data['count'] == 0: - raise ProfileHasNoPicsException("Profile with ID {0}: no pics found.".format(str(profile_id))) - else: - raise LoginRequiredException("Login required to determine username (ID: " + str(profile_id) + ").") - profile = Post(context, data['edges'][0]['node']).owner_profile context.profile_id_cache[profile_id] = profile return profile diff --git a/test/instaloader_unittests.py b/test/instaloader_unittests.py index 209db06..1a6b3ad 100644 --- a/test/instaloader_unittests.py +++ b/test/instaloader_unittests.py @@ -17,6 +17,9 @@ OWN_USERNAME = "aandergr" NORMAL_MAX_COUNT = 2 PAGING_MAX_COUNT = 15 PRIVATE_PROFILE = "aandergr" +PRIVATE_PROFILE_ID = 1706625676 +EMPTY_PROFILE = "not_public" +EMPTY_PROFILE_ID = 1928659031 # Preserve query timestamps (rate control) between tests to not get rate limited instaloadercontext_query_timestamps = list() @@ -83,10 +86,18 @@ class TestInstaloaderAnonymously(unittest.TestCase): self.assertEqual(PUBLIC_PROFILE_ID, instaloader.Profile.from_username(self.L.context, PUBLIC_PROFILE).userid) - def test_get_username_by_id(self): + def test_get_username_by_id_private(self): + self.assertEqual(PRIVATE_PROFILE.lower(), + instaloader.Profile.from_id(self.L.context, PRIVATE_PROFILE_ID).username) + + def test_get_username_by_id_public(self): self.assertEqual(PUBLIC_PROFILE.lower(), instaloader.Profile.from_id(self.L.context, PUBLIC_PROFILE_ID).username) + def test_get_username_by_id_empty(self): + self.assertEqual(EMPTY_PROFILE.lower(), + instaloader.Profile.from_id(self.L.context, EMPTY_PROFILE_ID).username) + def test_post_from_mediaid(self): for post in instaloader.Profile.from_username(self.L.context, PUBLIC_PROFILE).get_posts(): post2 = instaloader.Post.from_mediaid(self.L.context, post.mediaid) @@ -169,10 +180,6 @@ class TestInstaloaderLoggedIn(TestInstaloaderAnonymously): for f in profile.get_followers(): print(f.username) - def test_get_username_by_id(self): - self.assertEqual(PUBLIC_PROFILE.lower(), - instaloader.Profile.from_id(self.L.context, PUBLIC_PROFILE_ID).username) - def test_get_likes(self): for post in instaloader.Profile.from_username(self.L.context, OWN_USERNAME).get_posts(): for like in post.get_likes():