UNPKG

@xbibzlibrary/tiktokscrap

Version:

Powerful TikTok Scraper and Downloader Library

114 lines (93 loc) 3.75 kB
import BaseScraper from './base'; import { TikTokUser, TikTokVideo, TikTokPhoto, TikTokScrapOptions, TikTokScrapResult, TikTokUserFeedOptions } from '../types'; import { ValidationError, NotFoundError } from '../errors'; export class UserScraper extends BaseScraper { constructor(options: TikTokScrapOptions = {}) { super(options); } public async getUserByUsername(username: string): Promise<TikTokScrapResult<TikTokUser>> { return this.executeRequest(async () => { if (!this.validator.validateTikTokUsername(username)) { throw new ValidationError('Invalid TikTok username'); } const url = this.buildUrl('https://www.tiktok.com', `/${username}`); const response = await this.http.get(url); if (response.status !== 200) { throw new NotFoundError('User not found'); } return this.parser.parseUserData(response.data); }, `Get user by username: ${username}`); } public async getUserFeed(options: TikTokUserFeedOptions): Promise<TikTokScrapResult<TikTokVideo[] | TikTokPhoto[]>> { return this.executeRequest(async () => { this.validator.validateUserFeedOptions(options); const { username, cursor = 0, count = 20, type = 'post' } = options; // First, get user info to extract secUid const userResult = await this.getUserByUsername(username); if (!userResult.success || !userResult.data) { throw new NotFoundError('User not found'); } const secUid = userResult.data.secUid; const url = this.buildUrl('https://www.tiktok.com', '/api/item_list/', { count, id: userResult.data.id, type: type === 'post' ? 1 : 2, // 1 for posts, 2 for likes secUid, maxCursor: cursor, minCursor: 0, retryType: 0, isWeb: 1 }); const response = await this.http.get(url); if (response.status !== 200) { throw new NotFoundError('Could not fetch user feed'); } const data = response.data; if (!data.body || !data.body.itemListData) { return []; } return data.body.itemListData.map((item: any) => { // Check if it's a video or photo if (item.video) { return this.parser.parseVideoObject(item); } else if (item.images) { return this.parser.parsePhotoObject(item); } throw new ValidationError('Unknown item type in user feed'); }); }, `Get user feed for ${options.username}: ${options.count}`); } public async getUserVideos(username: string, cursor: number = 0, count: number = 20): Promise<TikTokScrapResult<TikTokVideo[]>> { return this.getUserFeed({ username, cursor, count, type: 'post' }) as Promise<TikTokScrapResult<TikTokVideo[]>>; } public async getUserPhotos(username: string, cursor: number = 0, count: number = 20): Promise<TikTokScrapResult<TikTokPhoto[]>> { return this.getUserFeed({ username, cursor, count, type: 'post' }) as Promise<TikTokScrapResult<TikTokPhoto[]>>; } public async getUserLikedVideos(username: string, cursor: number = 0, count: number = 20): Promise<TikTokScrapResult<TikTokVideo[]>> { return this.getUserFeed({ username, cursor, count, type: 'like' }) as Promise<TikTokScrapResult<TikTokVideo[]>>; } public async getUserLikedPhotos(username: string, cursor: number = 0, count: number = 20): Promise<TikTokScrapResult<TikTokPhoto[]>> { return this.getUserFeed({ username, cursor, count, type: 'like' }) as Promise<TikTokScrapResult<TikTokPhoto[]>>; } } export default UserScraper;