pythondata-structurestwittertweepypaginator

Tweepy: about accessing the "id" of a user after a Pagination response


I'm really stuck on this one.

I'm using Tweepy to get the IDs of all users that liked a specific tweet. I seem to get a list of "User" structures that contain "id", "name" and "username", but I'm not able to get only the "id".

The code is simple:

client = tweepy.Client(
    bearer_token=bearer_token,
    consumer_key=api_key, consumer_secret=api_secret,
    access_token=user_token, access_token_secret=user_token_secret,
    wait_on_rate_limit=True
)

for response in tweepy.Paginator(client.get_liking_users, id=tweetid, max_results=100, limit=10):
    for item in response:
        print("ITEM:\n", item)
        if item is not None:
            for user in item:
                if user is not None:
                    print(user)

The print of "item" gets me this (simplified, of course; the number of structures is high, that's why I have to use Paginator):

[<User id=0000001 name=user1 username=UserName1>, <User id=0002 name=user2 username=UserName2>, <User id=000003 name=user3 username=UserName3>]

and the print of "user" just gets me the individual usernames: "UserName1", etc.

But no way to get user.id, user.User.id, nor anything similar. And I'm frustrated, because the information is right there, just I can't access it easily.

Thank you!


Solution

  • Tweepy documentation provides an example of something very similar to what you want to do: https://docs.tweepy.org/en/stable/examples.html -> API v2 -> Get Tweet’s Liking Users

    import tweepy
    
    
    bearer_token = ""
    
    client = tweepy.Client(bearer_token)
    
    # Get Tweet's Liking Users
    
    # This endpoint/method allows you to get information about a Tweet’s liking
    # users
    
    tweet_id = 1460323737035677698
    
    # By default, only the ID, name, and username fields of each user will be
    # returned
    # Additional fields can be retrieved using the user_fields parameter
    response = client.get_liking_users(tweet_id, user_fields=["profile_image_url"])
    
    for user in response.data:
        print(user.username, user.profile_image_url)
    

    This example prints the user's username and profile image URL, but note the comment says the id is also returned, so something like user.id should work. Otherwise, you can also add id to user_fields to make sure it's returned, although that shouldn't be necessary.

    Unfortunately, I am not able to test it myself because I don't have a Twitter developer account with the required elevated access.

    Edit: I got access to an API account with elevated access and I was able to test your code, see the update below

    Iterating paginated results

    The reason why you need a double for loop to iterate the paginated results and it eventually crashes after showing some results with an error saying you are trying to access a non-existent id attribute on an str object is because you are not iterating the Paginator results correctly.

    For the sake of simplicity, I'm going to label your three nested for loops:

    loop 0: for response in tweepy.Paginator(...
    loop 1: for item in response
    loop 2: for user in item

    Paginator returns a Response object with all the results in the data attribute. The object has other attributes like meta, count, etc.

    When you do loop 1, you are iterating all these data, count, etc., attributes of Response.

    If the attribute you are iterating happens to be the data attribute, it will start loop 2 and it will iterate the results getting the output you expect.

    But loop 1 will also iterate other Reponse items outside of the data attribute.

    Let's see, for example, what happens when loop 1 enters the meta attribute.

    meta is a dictionary that looks like this:

    meta={'result_count': 80, 'next_token': '676f9b7bumw8i3jbm4nnifamw2ejjaktp8kjym6akdak9'}
    

    When you enter loop 2 with the meta attribute, it will start iterating the keys (not the values, because that's how dicts work in Python) so the value of user in loop 2 will be either result_count or next_token. And it's then when you are getting your error saying you are trying to access id on a str.

    What you should be doing is iterating the response.data in loop 1 instead and that will also allow removing the need of a second loop:

    for response in tweepy.Paginator(client.get_liking_users, id=tweetid, max_results=100, limit=10):
        for user in response.data:
            print(user.id)
    

    Edit: grammar and style