Fix anon username from id (find renamed profile)

maybe related to #95, #104, 67ac8f3397.
This commit is contained in:
Alexander Graf 2018-05-01 13:06:06 +02:00
parent 1469064176
commit 2722da6ae4
5 changed files with 28 additions and 14 deletions

View File

@ -74,7 +74,10 @@ metadata of a Profile. :class:`Profile` instances can be created with:
profile = Profile.from_username(L.context, USERNAME)
- :meth:`Profile_from_userid`
given its User ID (currently requires to be logged in).
given its User ID. This allows to easily lookup a Profile's username given
its ID::
Profile.from_id(L.context, USERID).username
- :meth:`Profile.get_followees`
Profiles that are followed by given user.

View File

@ -629,10 +629,6 @@ 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

@ -56,6 +56,7 @@ class InstaloaderContext:
self.quiet = quiet
self.max_connection_attempts = max_connection_attempts
self._graphql_page_length = 50
self._root_rhx_gis = None
# error log, filled with error() and printed at the end of Instaloader.main()
self.error_log = []
@ -376,3 +377,14 @@ class InstaloaderContext:
except KeyboardInterrupt:
self.error("[skipped by user]", repeat_at_end=False)
raise ConnectionException(error_string) from err
@property
def root_rhx_gis(self) -> Optional[str]:
"""rhx_gis string returned in the / query."""
if self.is_logged_in:
# At the moment, rhx_gis seems to be required for anonymous requests only. By returning None when logged
# in, we can save the root_rhx_gis lookup query.
return None
if not self._root_rhx_gis:
self._root_rhx_gis = self.get_json('', {})['rhx_gis']
return self._root_rhx_gis

View File

@ -145,8 +145,8 @@ class Post:
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.
# is contained. This is better than to get the username by user ID, since it
# 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)
@ -379,17 +379,16 @@ class Profile:
@classmethod
def from_id(cls, context: InstaloaderContext, profile_id: int):
"""If logged in, create a Profile instance from a given userid. If possible, use :meth:`Profile.from_username`
or constructor directly rather than this method, since does many requests.
"""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.
:param context: :attr:`Instaloader.context`
:param profile_id: userid
:raises: :class:`ProfileNotExistsException`, :class:`LoginRequiredException`, :class:`ProfileHasNoPicsException`
:raises: :class:`ProfileNotExistsException`, :class:`ProfileHasNoPicsException`
"""
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']
{'id': str(profile_id), 'first': 1},
rhx_gis=context.root_rhx_gis)['data']['user']
if data:
data = data["edge_owner_to_timeline_media"]
else:
@ -400,7 +399,7 @@ class Profile:
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) + ").")
username = Post.from_mediaid(context, int(data['edges'][0]["node"]["id"])).owner_username
username = Post.from_shortcode(context, data['edges'][0]["node"]["shortcode"]).owner_username
return cls(context, {'username': username.lower(), 'id': profile_id})
def _asdict(self):

View File

@ -54,6 +54,10 @@ 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):
self.assertEqual(PUBLIC_PROFILE.lower(),
instaloader.Profile.from_id(self.L.context, PUBLIC_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)