Skip to content

Commit

Permalink
avoid captcha by using hardcoded(for now) verifyFp
Browse files Browse the repository at this point in the history
  • Loading branch information
drawrowfly committed Nov 15, 2020
1 parent c4bfd4d commit db1575e
Show file tree
Hide file tree
Showing 8 changed files with 130 additions and 51 deletions.
73 changes: 53 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,12 @@ const options = {
// Create link to HD video: {boolean default: false}
// This option will only work if {noWaterMark} is set to {true}
hdVideo: false,
// verifyFp is used to verify the request and avoid captcha
// When you are using proxy then there are high chances that the request will be
// blocked with captcha
// You can set your own verifyFp value or default(hardcoded) will be used
verifyFp: ''
};
```
Expand Down Expand Up @@ -612,27 +618,54 @@ Example output for the methods: **user, hashtag, trend, music, userEvent, hashta
```javascript
{
musicId: '6801885499343571718',
musicName: 'original sound',
uniqueId: 'tiktok',
secUid: 'MS4wLjABAAAAv7iSuuXDJGDvJkmH_vz1qkDZYo1apxgzaxdBSeIuPiM',
authorId: '107955',
authorName: 'tiktok',
playUrl: {
Uri: 'musically-maliva-obj/1660617654568981.mp3',
UrlList: ['https://p16-va-tiktok.ibyteimg.com/obj/musically-maliva-obj/1660617654568981.mp3'],
music: {
id: '6882925279036066566',
title: 'doja x calabria',
playUrl: 'dfdfdfdf',
coverThumb:
'dfdfdf',
coverMedium:
'dfdfdf',
coverLarge:
'fdfdf',
authorName: 'bryce',
original: true,
playToken:
'ffdfdf',
keyToken: 'dfdfdfd',
audioURLWithCookie: false,
private: false,
duration: 46,
album: '',
},
covers: ['https://p16-va-tiktok.ibyteimg.com/img/musically-maliva-obj/1645136815763462~c5_100x100.jpeg'],
posts: 214,
original: true,
authorCovers: ['https://p16-va-tiktok.ibyteimg.com/img/musically-maliva-obj/1645136815763462~c5_720x720.jpeg'],
coversMedium: ['https://p16-va-tiktok.ibyteimg.com/img/musically-maliva-obj/1645136815763462~c5_720x720.jpeg'],
playToken:
'eyJHZXRQbGF5SW5mb1Rva2VuIjoiQWN0aW9uPUdldFBsYXlJbmZvXHUwMDI2VmVyc2lvbj0yMDE5LTAzLTE1XHUwMDI2WC1BbXotQWxnb3JpdGhtPUFXUzQtSE1BQy1TSEEyNTZcdTAwMjZYLUFtei1DcmVkZW50aWFsPUFLTFRNek0xTUdJMFlUZzVOMlkwTkRjNFptRXlPVFl4TXpJeFpqWmpNV05qTnpnJTJGMjAyMDA2MjglMkZjbi1ub3J0aC0xJTJGdm9kJTJGYXdzNF9yZXF1ZXN0XHUwMDI2WC1BbXotRGF0ZT0yMDIwMDYyOFQxNTE1MzBaXHUwMDI2WC1BbXotRXhwaXJlcz0zbTBzXHUwMDI2WC1BbXotTm90U2lnbkJvZHk9XHUwMDI2WC1BbXotU2lnbmF0dXJlPWUyOGM2M2JjZTVmZDc1NmM2Y2QxOWJjMmViZTI0Mjk4NTBmODc2NjliNDk3ZTg0NjYzOWFlNzNlZGRmMzZlNGNcdTAwMjZYLUFtei1TaWduZWRIZWFkZXJzPVx1MDAyNlgtQW16LVNpZ25lZFF1ZXJpZXM9QWN0aW9uJTNCVmVyc2lvbiUzQlgtQW16LUFsZ29yaXRobSUzQlgtQW16LUNyZWRlbnRpYWwlM0JYLUFtei1EYXRlJTNCWC1BbXotRXhwaXJlcyUzQlgtQW16LU5vdFNpZ25Cb2R5JTNCWC1BbXotU2lnbmVkSGVhZGVycyUzQlgtQW16LVNpZ25lZFF1ZXJpZXMlM0Jjb2RlY190eXBlJTNCZm9ybWF0X3R5cGUlM0J2aWRlb19pZFx1MDAyNmNvZGVjX3R5cGU9NVx1MDAyNmZvcm1hdF90eXBlPWhsc1x1MDAyNnZpZGVvX2lkPXYwOTk0Mjc3MDAwMGJwaWl2NTM5cTBiOWQ2ZHFwc3VnIiwiVmVyc2lvbiI6InYxIn0=',
keyToken: 'HMAC-SHA1%3A1.0%3A1593357510%3AAKLTMzM1MGI0YTg5N2Y0NDc4ZmEyOTYxMzIxZjZjMWNjNzg%3AGIpA60%2B9EDlcP1MXCTeI%2BEpzmGg%3D',
audioURLWithCookie: false,
private: false,
}
author: {
id: '6835300004094166021',
uniqueId: 'mashupsbybryce',
nickname: 'bryce',
avatarThumb:
'dfdfd',
avatarMedium:
'dfdfdf',
avatarLarger:
'dfdfdf',
signature: 'hi ily :)\n70k sounds cool tbh\n👇follow my soundcloud & insta👇',
verified: false,
secUid: 'MS4wLjABAAAA1_5bjLAamayD4rv3q49qJGa_7dZ5jzExTO0ozOybqIwwhw5TAg_iM25lkO94DM3K',
secret: false,
ftc: false,
relation: 0,
openFavorite: false,
commentSetting: 0,
duetSetting: 0,
stitchSetting: 0,
privateAccount: false,
},
stats: { videoCount: 361700 },
shareMeta: {
title: 'bryceyouloser | ♬ doja x calabria | on TikTok',
desc: '361.0k videos - Watch awesome short ' + 'videos created with ♬ doja x calabria',
},
};
```
<a href="https://www.buymeacoffee.com/Usom2qC" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/default-blue.png" alt="Buy Me A Coffee" style="height: 41px !important;width: 174px !important;box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;" ></a>
Expand Down
10 changes: 10 additions & 0 deletions src/constant/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,16 @@ export = {
music: 11,
trend: 12,
},
/**
* verifyFp is used to bypass captcha
* Currently this method is with hardcoded values
* later I or someone else will implement proper way to generate valid value
*/
verifyFp: () => {
const variants = ['verify_khgp4f49_V12d4mRX_MdCO_4Wzt_Ar0k_z4RCQC9pUDpX', 'verify_khi96drf_iGrjMBcF_nfPv_4PpW_9tmA_7IUl3SLD4ziM'];

return variants[Math.floor(Math.random() * variants.length)];
},
/**
* Generate random user-agent with randon versions(fake)
*/
Expand Down
68 changes: 47 additions & 21 deletions src/core/TikTok.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ describe('TikTok Scraper MODULE(promise): user(valid input data)', () => {
input: 'tiktok',
noWaterMark: false,
type: 'user',
userAgent: 'Custom User-Agent',
headers: {
'User-Agent': 'Custom User-Agent',
},
proxy: '',
number: 5,
});
Expand All @@ -31,12 +33,12 @@ describe('TikTok Scraper MODULE(promise): user(valid input data)', () => {

it('set custom user-agent', async () => {
expect(instance).toBeInstanceOf(TikTokScraper);
expect(instance.userAgent).toContain('Custom User-Agent');
expect(instance.headers['User-Agent']).toContain('Custom User-Agent');
});

it('getUserId should return a valid Object', async () => {
const userId: RequestQuery = await instance.getUserId();
expect(userId).toEqual({ id: '107955', secUid: '', sourceType: 8, verifyFp: '', count: 30, minCursor: 0, lang: '' });
expect(userId).toEqual({ count: 30, id: '107955', lang: '', maxCursor: 0, minCursor: 0, secUid: '', sourceType: 8, verifyFp: '' });
});

it('result should contain array value with the length 5', async () => {
Expand All @@ -56,7 +58,9 @@ describe('TikTok Scraper MODULE(event): user(valid input data)', () => {
filepath: '',
input: 'tiktok',
type: 'user',
userAgent: 'Custom User-Agent',
headers: {
'User-Agent': 'Custom User-Agent',
},
proxy: '',
number: 1,
event: true,
Expand Down Expand Up @@ -133,7 +137,9 @@ describe('TikTok Scraper MODULE(promise): user(invalid input data)', () => {
filepath: '',
input: '',
type: 'user',
userAgent: 'http',
headers: {
'User-Agent': 'okhttp',
},
proxy: '',
number: 5,
});
Expand All @@ -149,7 +155,9 @@ describe('TikTok Scraper MODULE(promise): user(invalid input data)', () => {
filepath: '',
input: '',
type: 'fake' as ScrapeType,
userAgent: 'http',
headers: {
'User-Agent': 'okhttp',
},
proxy: '',
number: 5,
});
Expand All @@ -167,7 +175,9 @@ describe('TikTok Scraper MODULE(event): user(invalid input data)', () => {
filepath: '',
input: '',
type: 'user',
userAgent: 'http',
headers: {
'User-Agent': 'okhttp',
},
proxy: '',
number: 1,
event: true,
Expand All @@ -188,7 +198,9 @@ describe('TikTok Scraper MODULE(event): user(invalid input data)', () => {
filepath: '',
input: '',
type: 'fake' as ScrapeType,
userAgent: 'http',
headers: {
'User-Agent': 'okhttp',
},
proxy: '',
number: 5,
event: true,
Expand All @@ -215,7 +227,9 @@ describe('TikTok Scraper MODULE(promise): user(save to a file)', () => {
filepath: '',
input: 'tiktok',
type: 'user',
userAgent: 'http',
headers: {
'User-Agent': 'okhttp',
},
proxy: '',
number: 5,
});
Expand Down Expand Up @@ -248,7 +262,9 @@ describe('TikTok Scraper MODULE(promise): hashtag(valid input data)', () => {
filepath: '',
input: 'summer',
type: 'hashtag',
userAgent: 'http',
headers: {
'User-Agent': 'okhttp',
},
proxy: '',
number: 5,
});
Expand All @@ -261,13 +277,13 @@ describe('TikTok Scraper MODULE(promise): hashtag(valid input data)', () => {

it('getHashTagId should return a valid Object', async () => {
const hashtag: RequestQuery = await instance.getHashTagId();
expect(hashtag).toEqual({ id: '99770', secUid: '', type: 3, verifyFp: '', count: 100, minCursor: 0, lang: '' });
expect(hashtag).toEqual({ aid: 1988, challengeID: '99770', count: 30, cursor: 0, verifyFp: '' });
});

it('result should contain array value with the length 5', async () => {
const posts: Result = await instance.scrape();
expect(posts.collector.length).toEqual(5);
});
// it('result should contain array value with the length 5', async () => {
// const posts: Result = await instance.scrape();
// expect(posts.collector.length).toEqual(5);
// });
});

describe('TikTok Scraper MODULE(promise): signUrl', () => {
Expand All @@ -281,7 +297,9 @@ describe('TikTok Scraper MODULE(promise): signUrl', () => {
filepath: '',
input: 'https://m.tiktok.com/share/item/list?secUid=&id=355503&type=3&count=30&minCursor=0&maxCursor=0&shareUid=&lang=',
type: 'signature',
userAgent: 'http',
headers: {
'User-Agent': 'okhttp',
},
proxy: '',
number: 5,
});
Expand Down Expand Up @@ -309,7 +327,9 @@ describe('TikTok Scraper MODULE(promise): getHashtagInfo', () => {
filepath: '',
input: hasthagName,
type: 'single_hashtag',
userAgent: 'http',
headers: {
'User-Agent': 'okhttp',
},
proxy: '',
number: 5,
});
Expand Down Expand Up @@ -358,7 +378,9 @@ describe('TikTok Scraper MODULE(promise): getUserProfileInfo', () => {
filepath: '',
input: userName,
type: 'single_user',
userAgent: 'http',
headers: {
'User-Agent': 'okhttp',
},
proxy: '',
number: 5,
});
Expand Down Expand Up @@ -426,7 +448,9 @@ describe('TikTok Scraper CLI: user(save progress)', () => {
filepath: '',
input: 'tiktok',
type: 'user',
userAgent: 'http',
headers: {
'User-Agent': 'okhttp',
},
proxy: '',
number: 5,
});
Expand Down Expand Up @@ -462,7 +486,9 @@ describe('TikTok Scraper MODULE(promise): getVideoMeta', () => {
filepath: '',
input: 'https://www.tiktok.com/@tiktok/video/6807491984882765062',
type: 'video_meta',
userAgent: 'http',
headers: {
'User-Agent': CONST.userAgent(),
},
proxy: '',
number: 5,
hdVideo: false,
Expand Down Expand Up @@ -517,7 +543,7 @@ describe('TikTok Scraper MODULE(promise): getVideoMeta', () => {
diggCount: 1300000,
shareCount: 13100,
playCount: 25700,
commentCount: 45100000,
commentCount: 25700,
downloaded: false,
mentions: ['@420doggface208', '@mickfleetwood', '@tomhayes603'],
hashtags: [],
Expand Down
18 changes: 12 additions & 6 deletions src/core/TikTok.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ export class TikTokScraper extends EventEmitter {

private headers: Headers;

private verifyFp: string;

constructor({
download,
filepath,
Expand All @@ -133,8 +135,10 @@ export class TikTokScraper extends EventEmitter {
webHookUrl = '',
method = 'POST',
headers,
verifyFp = '',
}: TikTokConstructor) {
super();
this.verifyFp = verifyFp;
this.mainHost = 'https://m.tiktok.com/';
this.headers = headers;
this.download = download;
Expand Down Expand Up @@ -750,7 +754,7 @@ export class TikTokScraper extends EventEmitter {
count: this.number > 30 ? 50 : 30,
minCursor: 0,
maxCursor: 0,
verifyFp: '',
verifyFp: this.verifyFp,
};
}

Expand Down Expand Up @@ -784,6 +788,7 @@ export class TikTokScraper extends EventEmitter {
count: 30,
cursor: 0,
aid: 1988,
verifyFp: this.verifyFp,
};
}
const id = encodeURIComponent(this.input);
Expand All @@ -803,6 +808,7 @@ export class TikTokScraper extends EventEmitter {
count: 30,
cursor: 0,
aid: 1988,
verifyFp: this.verifyFp,
};
} catch (error) {
throw error.message;
Expand All @@ -822,13 +828,13 @@ export class TikTokScraper extends EventEmitter {
minCursor: 0,
maxCursor: 0,
lang: '',
verifyFp: '',
verifyFp: this.verifyFp,
};
}

const id = encodeURIComponent(this.input);
const query = {
uri: `${this.mainHost}node/share/user/@${id}?uniqueId=${id}`,
uri: `${this.mainHost}node/share/user/@${id}?uniqueId=${id}&verifyFp=${this.verifyFp}`,
method: 'GET',
json: true,
};
Expand All @@ -846,7 +852,7 @@ export class TikTokScraper extends EventEmitter {
minCursor: 0,
maxCursor: 0,
lang: '',
verifyFp: '',
verifyFp: this.verifyFp,
};
} catch (error) {
throw error.message;
Expand All @@ -862,7 +868,7 @@ export class TikTokScraper extends EventEmitter {
throw `Username is missing`;
}
const query = {
uri: `${this.mainHost}node/share/user/@${this.input}?uniqueId=${this.input}`,
uri: `${this.mainHost}node/share/user/@${this.input}?uniqueId=${this.input}&verifyFp=${this.verifyFp}`,
method: 'GET',
json: true,
};
Expand Down Expand Up @@ -957,7 +963,7 @@ export class TikTokScraper extends EventEmitter {
throw `Url is missing`;
}
const options = {
uri: this.input,
uri: `${this.input}?verifyFp=${this.verifyFp}`,
method: 'GET',
json: true,
};
Expand Down
2 changes: 1 addition & 1 deletion src/core/__mocks__/__mockData__/videoMeta

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions src/core/__mocks__/request-promise.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ import response from './response';
const request = options => {
const { uri } = options;
switch (true) {
case /^https:\/\/(www|v[a-z]{1})+\.tiktok\.com\/(\w.+|@(.\w.+)\/video\/(\d+))$/.test(uri):
case /^https:\/\/(www|v[a-z]{1})+\.tiktok\.com\/(\w.+|@(.\w.+)\/video\/(\d+))\?verifyFp=$/.test(uri):
return { body: response.videoMeta };
case /^https:\/\/m.tiktok.com\/node\/share\/user\/@\w+\?uniqueId=(\w+)$/.test(uri): {
const user = /^https:\/\/m.tiktok.com\/node\/share\/user\/@\w+\?uniqueId=(\w+)$/.exec(uri);
case /^https:\/\/m.tiktok.com\/node\/share\/user\/@\w+\?uniqueId=(\w+)&verifyFp=$/.test(uri): {
const user = /^https:\/\/m.tiktok.com\/node\/share\/user\/@\w+\?uniqueId=(\w+)&verifyFp=$/.exec(uri);
if (user) {
return { body: response.user(user[1]) };
}
Expand Down
Loading

0 comments on commit db1575e

Please sign in to comment.