@xbibzlibrary/tiktokscrap
Version:
Powerful TikTok Scraper and Downloader Library
114 lines (93 loc) • 3.75 kB
text/typescript
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;