Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Getting more video ids than 30 fails #1119

Open
vuhaopro90 opened this issue Feb 24, 2024 · 10 comments
Open

Getting more video ids than 30 fails #1119

vuhaopro90 opened this issue Feb 24, 2024 · 10 comments
Labels
bug Something isn't working

Comments

@vuhaopro90
Copy link

Hi everyone,
I want to get all tiktok video id from a user, this is code:


from TikTokApi import TikTokApi
import asyncio
import os

ms_token = os.environ.get(
    "ms_token", None
)  
async def user_example():
    async with TikTokApi() as api:
        await api.create_sessions(headless=False, ms_tokens=[ms_token], num_sessions=1, sleep_after=3)
        user = api.user("truong_se")
        user_data = await user.info()

        async for video in user.videos(count=30):
            print(video)
            video = str(video) + "\n"
            with open('test1.json', 'a') as file:
                file.write(video)

if __name__ == "__main__":
    asyncio.run(user_example())

in this line, I try edit count=30 to count=1000 but it doesn't work:

async for video in user.videos(count=1000):

output:
2024-02-24 09:39:55,961 - TikTokApi.tiktok - ERROR - Got an unexpected status code: {'log_pb': {'impr_id': '202402240240321EB88FFC04941C07B40E'}, 'statusCode': 10201, 'statusMsg': '', 'status_code': 10201, 'status_msg': ''}

Is there any solution to fix this situation? Thanks.

@vuhaopro90 vuhaopro90 added the bug Something isn't working label Feb 24, 2024
@cloudengineer89
Copy link

hey, try to look through this code ms_token = os.environ.get( "ms_token", None ) . Is your token actually located within your environment?
try to pass directly at first

@ajctrl
Copy link

ajctrl commented Mar 2, 2024

same here, more than 35 videos fail

@anarchopythonista
Copy link

anarchopythonista commented Mar 8, 2024

I've had mixed luck with trying to scrape large amounts at once. I'll post a modified version of your code adding the changes I've made that seem to work best, though I see a strong positive correlation between failure rate and post count (especially for profiles with >1000 posts).

Code

from TikTokApi import TikTokApi
import asyncio
import os

ms_token = os.environ.get(
    "ms_token", None
)  
async def user_example(username):
    async with TikTokApi() as api:
        await api.create_sessions(headless=False, ms_tokens=[ms_token], num_sessions=1, sleep_after=3)
        user = api.user(username)
        user_data = await user.info()
        post_count = user_data["userInfo"]["stats"].get("videoCount")

        async for video in user.videos(count=post_count):
            print(video)
            video = str(video) + "\n"
            with open('test1.json', 'a') as file:
                file.write(video)

if __name__ == "__main__":
    asyncio.run(user_example("truong_se"))

Breakdown

First, I added a username parameter to your user_example definition. This allows you to call this function for other usernames in a more streamlined fashion. It also cleans up your code elsewhere, as in user = api.user(username). (my own version of this function includes a manual limit: int = 0 in the definition for situations like where a user has a substantial number of non-public posts.)
Next, I added the post_count variable assignment. This will extract the number of videos from user_data in the previous line. Note: this number is not always accurate, as it reflects all posts - including private, which we can't scrape.
Finally, I added the username you had to the function call asyncio.run(user_example("truong_se")), reflecting the syntax update in the definition.

Hope this is helpful!

@vuhaopro90
Copy link
Author

I've had mixed luck with trying to scrape large amounts at once. I'll post a modified version of your code adding the changes I've made that seem to work best, though I see a strong positive correlation between failure rate and post count (especially for profiles with >1000 posts).

Code

from TikTokApi import TikTokApi
import asyncio
import os

ms_token = os.environ.get(
    "ms_token", None
)  
async def user_example(username):
    async with TikTokApi() as api:
        await api.create_sessions(headless=False, ms_tokens=[ms_token], num_sessions=1, sleep_after=3)
        user = api.user(username)
        user_data = await user.info()
        post_count = user_data["userInfo"]["stats"].get("videoCount")

        async for video in user.videos(count=post_count):
            print(video)
            video = str(video) + "\n"
            with open('test1.json', 'a') as file:
                file.write(video)

if __name__ == "__main__":
    asyncio.run(user_example("truong_se"))

Breakdown

First, I added a username parameter to your user_example definition. This allows you to call this function for other usernames in a more streamlined fashion. It also cleans up your code elsewhere, as in user = api.user(username). (my own version of this function includes a manual limit: int = 0 in the definition for situations like where a user has a substantial number of non-public posts.) Next, I added the post_count variable assignment. This will extract the number of videos from user_data in the previous line. Note: this number is not always accurate, as it reflects all posts - including private, which we can't scrape. Finally, I added the username you had to the function call asyncio.run(user_example("truong_se")), reflecting the syntax update in the definition.

Hope this is helpful!

My goal is to get all the user's video ids, I used my own method, surprisingly it works perfectly, it doesn't miss a single video.

This is my code:

driver = webdriver.Chrome() 
    user_link = "https://www.tiktok.com/@hieuthuhai2222"

    driver.get(user_link)

    time.sleep(10) 

    script = """let id_video = '';
    let lastScrollHeight = 0;
    let scrollCompleted = false;

    while (!scrollCompleted) {
        const currentScrollHeight = document.body.scrollHeight;

        if (currentScrollHeight === lastScrollHeight) {
            const divs = document.querySelectorAll('.css-1as5cen-DivWrapper');
            
            divs.forEach(div => {
                const link = div.querySelector('a');
                if (link) {
                    const href = link.getAttribute('href');
                    if (href.includes("/video/")) {
                        const id = href.split('/').pop();
                        id_video += id + ","; 
                    }
                }
            });

            scrollCompleted = true;
        } else {
            lastScrollHeight = currentScrollHeight;
            window.scrollTo(0, currentScrollHeight);
            await new Promise(resolve => setTimeout(resolve, 1000));
        }
    }

    return id_video;


    """

    ids = driver.execute_script(script)
    print(ids)

@koonn
Copy link

koonn commented Apr 8, 2024

When I set the count to 35 or higher, the same error occurs.

I've encountered a limitation where I cannot retrieve information for more than 35 videos at once. However, I found a workaround using the cursor argument in the users.videos endpoint.

This argument specifies the starting point for the count. By updating cursor and repeating the process, I can access information for more than 35 videos.

I hope this solution is helpful to you!

@lhphat02
Copy link

lhphat02 commented Apr 9, 2024

Hi @koonn , I tried to use cursor but it didn't work. At the 35 first videos it worked but when the cursor start at 35 or higher, it don't return data anymore. Here's how I implemented:

async def get_user_videos(user_name):
  async with TikTokApi() as api:
    await api.create_sessions(ms_tokens=[ms_token], num_sessions=1, sleep_after=1, headless=False)
    user = api.user(user_name)
    count = 35
    cursor = 0

    while cursor < 350:
      print(f"Fetching videos from cursor {cursor}...")

      try:
        async for video in user.videos(count=count, cursor=cursor):
          print(video)
        cursor += count

      except Exception as e:
        print(f"Error: {e}")
        break

Have you tried using it? Then can I see your code please?
I'd be really appreciate that.

ajctrl added a commit to ajctrl/TikTok-Api that referenced this issue Apr 9, 2024
@koonn
Copy link

koonn commented Apr 9, 2024

@lhphat02

here is my code.

async def get_hashtag_videos(hash_tag, num_data=30):
    videos_data = []
    cursor = 0

    async with TikTokApi() as api:
        await api.create_sessions(ms_tokens=[ms_token], num_sessions=1, sleep_after=3, headless=False)
        tag = api.hashtag(name=hash_tag)

        while cursor <= num_data:
            async for video in tag.videos(count=30, cursor=cursor):
                print(video)
                video_data = video.as_dict
                videos_data.append(video_data) 
            cursor += 30

I actually use this solution for tag.videos, not for users.videos, and it works well. After checking the implementation for user.videos, it seems that this solution would work there too.

@lhphat02
Copy link

@koonn
Hi, thanks for your code, it works pretty well. But when I modify the code for crawling user.videos , it still not work, I think there're some problems with the TikTok's API or their policies about rate limits. Here's my code I modified from yours for user.videos :

async def get_user_videos(user_name, num_data=300):
    result = []
    cursor = 0

    async with TikTokApi() as api:
        await api.create_sessions(ms_tokens=[ms_token], num_sessions=1, sleep_after=3, headless=False)
        user = api.user(username=user_name)

        while cursor <= num_data:
            print(f"cursor: {cursor}")
            async for video in user.videos(count=30, cursor=cursor):
                print(video)
                video_data = video.as_dict
                result.append(video_data) 
            cursor += 30
            
    return result

Btw thanks for your solution. Have a nice day!

@anarchopythonista
Copy link

@koonn Hi, thanks for your code, it works pretty well. But when I modify the code for crawling user.videos , it still not work, I think there're some problems with the TikTok's API or their policies about rate limits. Here's my code I modified from yours for user.videos :

async def get_user_videos(user_name, num_data=300):
    result = []
    cursor = 0

    async with TikTokApi() as api:
        await api.create_sessions(ms_tokens=[ms_token], num_sessions=1, sleep_after=3, headless=False)
        user = api.user(username=user_name)

        while cursor <= num_data:
            print(f"cursor: {cursor}")
            async for video in user.videos(count=30, cursor=cursor):
                print(video)
                video_data = video.as_dict
                result.append(video_data) 
            cursor += 30
            
    return result

Btw thanks for your solution. Have a nice day!

Which version of TikTokApi are you using?

Installing v6.2.2 broke user.videos() for me. Downgrading to 6.2.0 with pip install TikTokApi==6.2.0 --force-reinstall fixed the issue.

@Gereks123
Copy link

Gereks123 commented Apr 12, 2024

@koonn Hi, thanks for your code, it works pretty well. But when I modify the code for crawling user.videos , it still not work, I think there're some problems with the TikTok's API or their policies about rate limits. Here's my code I modified from yours for user.videos :

async def get_user_videos(user_name, num_data=300):
    result = []
    cursor = 0

    async with TikTokApi() as api:
        await api.create_sessions(ms_tokens=[ms_token], num_sessions=1, sleep_after=3, headless=False)
        user = api.user(username=user_name)

        while cursor <= num_data:
            print(f"cursor: {cursor}")
            async for video in user.videos(count=30, cursor=cursor):
                print(video)
                video_data = video.as_dict
                result.append(video_data) 
            cursor += 30
            
    return result

Btw thanks for your solution. Have a nice day!

Which version of TikTokApi are you using?

Installing v6.2.2 broke user.videos() for me. Downgrading to 6.2.0 with pip install TikTokApi==6.2.0 --force-reinstall fixed the issue.

I personally downgraded and I could fetch more than 30+ videos per account without issues!

EDIT: wording

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

8 participants
@anarchopythonista @cloudengineer89 @koonn @ajctrl @Gereks123 @lhphat02 @vuhaopro90 and others