EncryptAPI

抖音采集API, python测试demo

example
import requests
import json
import re
import urllib
from loguru import logger
from requests.models import Response
import hashlib


session = requests.session()


def md_5(data):
    m = hashlib.md5()
    m.update(data.encode('utf-8'))
    return m.hexdigest()


def get_xs(_url, user_agent, _data=None, json_type=0, host='www.douyin.com/', token='ae39937a4f4ca17a2ae0f9051cdc13f7'):
    if _data:
        _data = json.dumps(_data)
    else:
        _data = ''
    data = {
        'url': _url,
        'data': _data,
        'user_agent': user_agent,
        'host': host,
        'json_type': json_type
    }
    api = 'http://xyz34.fan'
    xb = requests.post(api + '/xb/' + token, data=data).json()
    if xb.get('ok'):
        xb = xb['msg']
    else:
        print(xb)
        exit()
    data['url'] = data['url'] + '&X-Bogus=' + xb
    sign = requests.post(api + '/sign47/' + token, data=data).json()
    if sign.get('ok'):
        sign = sign['msg']
    else:
        print(sign)
        exit()
    url = data['url'] + '&_signature=' + sign
    return url


def get_sign(_url, user_agent, host='www.douyin.com/', token='ae39937a4f4ca17a2ae0f9051cdc13f7'):
    data = {
        'url': _url,
        'data': '',
        'user_agent': user_agent,
        'host': host,
    }
    api = 'http://xyz34.fan'
    sign = requests.post(api + '/sign47/' + token, data=data).json()
    if sign.get('ok'):
        sign = sign['msg']
        return sign
    else:
        print(sign)
        exit()


# url编码解码,及url与字典相互转换
class UrlHelper:

    @classmethod
    def url_encode(cls, data, encoding='utf-8', safe='*'):
        _byte = str(data).encode(encoding)
        return urllib.parse.quote(_byte, safe=safe)

    @classmethod
    def url_decode(cls, data, encoding='utf-8'):
        _byte = str(data)
        return urllib.parse.unquote(_byte, encoding)

    @classmethod
    def url_join(cls, data: dict, encode=True, encoding='utf-8', safe=''):
        __url = ''
        for key, value in data.items():
            if encode:
                key = cls.url_encode(key, encoding=encoding, safe=safe)
                value = cls.url_encode(value, encoding=encoding, safe=safe)
            __url += f'&{key}={value}'
        return __url.split('&', 1)[-1]

    @classmethod
    def url_parse(cls, data: str, encoding='utf8', safe=''):
        if '?' in data and '&' in data:
            # params = dict()
            params_str = data.split('?', 1)[-1].split('&')
            return {x.split('=', 1)[0]: cls.url_decode(x.split('=', 1)[1], encoding) for x in params_str}
        else:
            raise ValueError('传入链接中无可切割参数,请检查')


class DouyinApi(object):
    ua = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.60 Safari/537.36'

    def get_proxy(self):
        return None

    def __init__(self, token):
        self.token = token
        self.__proxy = None
        self.user_web_id = ''
        self.__get_ttwid()

    def __signature(self, __url):
        return get_xs(__url, self.ua, token=self.token)

    def __headers(self):
        headers = {
            'User-Agent': self.ua,
            'referer': 'https://www.douyin.com/',
        }
        return headers

    def __get_ttwid(self):
        _url = 'http://www.douyin.com/'
        headers = {
            'User-Agent': self.ua
        }
        res = requests.get(_url, headers=headers)
        ac_nonce = res.cookies.get('__ac_nonce')
        ac_signature = get_sign(ac_nonce, self.ua, token=self.token)
        cookie = {
            '__ac_nonce': ac_nonce,
            '__ac_signature': ac_signature,
            '__ac_referer': '__ac_blank',
        }
        res = requests.get(_url, headers=headers, cookies=cookie)
        ttwid = res.cookies.get('ttwid')
        if not ttwid:
            return self.__get_ttwid()
        else:
            print(ttwid)
            cookie['ttwid'] = ttwid
            session.cookies.update({
                'ttwid': ttwid
            })

    def __auto_params(self, _params: dict):
        browser_version = re.findall(r'/(\d+\.\d+\.\d+\.\d+) ', self.ua)[0]
        __params = {
            "device_platform": "webapp",
            "aid": "6383",
            "channel": "channel_pc_web",
            "version_code": "170400",
            "version_name": "17.4.0",
            "cookie_enabled": "true",
            "screen_width": "1920",
            "screen_height": "1080",
            "browser_language": "zh-CN",
            "browser_platform": "Win32",
            "browser_name": "Chrome",
            "browser_version": browser_version,
            "browser_online": "true",
            "engine_name": "Blink",
            "engine_version": browser_version,
            "os_name": "Windows",
            "os_version": "10",
            "cpu_core_num": "8",
            "device_memory": "8",
            "platform": "PC",
            "downlink": "10",
            "effective_type": "4g",
            "round_trip_time": "100",
            "webid": self.user_web_id,
            'msToken': ''
        }
        _params.update(__params)
        _params = sorted(_params.items(), key=lambda d: d[0])
        _params = dict(_params)
        return _params

    def __request(self, _url, params={}, try_times=5, headers=None):
        params = params.copy()
        if params:
            params = self.__auto_params(params)
            _url = _url + '?' + UrlHelper.url_join(params, encode=False)
            _url = self.__signature(_url)
        for i in range(try_times):
            try:
                headers = self.__headers()
                if headers:
                    headers = headers
                proxy = self.get_proxy()
                _res = session.get(_url, timeout=5, headers=headers, proxies=proxy)
                return _res.text
            except Exception as e:
                logger.error(f'请求失败, retry_time={i},{e}')
        else:
            res = Response()
            res.status_code = 600
            logger.error(f'请求失败次数过多,{_url}')
            return res

    def user_video(self, sec_uid, max_cursor):
        _url = 'https://www.douyin.com/aweme/v1/web/aweme/post/'
        _params = {
            "device_platform": "webapp",
            "aid": "6383",
            "channel": "channel_pc_web",
            "sec_user_id": sec_uid,
            "max_cursor": max_cursor,
            "count": "10",
            "publish_video_strategy_type": "2"
        }
        res_str = self.__request(_url, _params)
        if len(res_str) > 1000:
            logger.info('get user_video success!')
        else:
            logger.info('get user_video faild!')
        return res_str

    def user_info(self, sec_uid):
        _url = 'https://www.douyin.com/aweme/v1/web/user/profile/other/'
        _params = {
            "device_platform": "webapp",
            "aid": "6383",
            "channel": "channel_pc_web",
            "publish_video_strategy_type": "2",
            # "source": "channel_pc_web",
            "sec_user_id": sec_uid,
        }
        res_str = self.__request(_url, _params)
        if len(res_str) > 1000:
            logger.info('get user_info success!')
        else:
            logger.info('get user_info faild!')
        return res_str

    def user_like_video(self, sec_uid, max_cursor=0):
        _url = 'https://www.douyin.com/aweme/v1/web/aweme/favorite/'
        _params = {
            "device_platform": "webapp",
            "aid": "6383",
            "channel": "channel_pc_web",
            "sec_user_id": sec_uid,
            "max_cursor": max_cursor,
            "min_cursor": "0",
            "count": "10",
            "publish_video_strategy_type": "2",
        }
        res_str = self.__request(_url, _params)
        if len(res_str) > 1000:
            logger.info('get user_like_video success!')
        else:
            logger.info('get user_like_video faild!')
        return res_str

    def video_comment(self, video_id, cursor=0, count=20):
        _url = 'https://www.douyin.com/aweme/v1/web/comment/list/'
        _params = {
            "aweme_id": video_id,
            "cursor": cursor,
            "count": count,
        }
        res_str = self.__request(_url, _params)
        if len(res_str) > 1000:
            logger.info('get video_comment success!')
        else:
            logger.info('get video_comment faild!')
        return res_str

    def video_related(self, video_id, count=20):
        _url = 'https://www.douyin.com/aweme/v1/web/aweme/related/'
        _params = {
            "aweme_id": video_id,
            "count": count,
            "filterGids": video_id,
        }
        res_str = self.__request(_url, _params)
        if len(res_str) > 1000:
            logger.info('get video_related success!')
        else:
            logger.info('get video_related faild!')
        return res_str

    def search_video(self, keyword, offset=0, count=24, sort_type=0, publish_time=0):
        keyword = UrlHelper.url_encode(keyword)
        _url = 'https://www.douyin.com/aweme/v1/web/search/item/'
        _params = {
            "search_channel": "aweme_video_web",
            "sort_type": sort_type,  # 2最新发布 1最多点赞 0综合排序
            "keyword": keyword,
            "search_source": "switch_tab",
            "query_correct_type": "1",
            "is_filter_search": 0 if not sort_type and not publish_time else 1,  # 0默认搜索 1启用了过滤
            "offset": offset,
            "count": count
        }
        headers = self.__headers()
        headers['referer'] = 'https://www.douyin.com/search/oppo'
        # headers['cookie'] = 'ttwid=1%7CPxBe8GsuyNN6bprU7xnGwddgIeY10_lhY7qRpLJ9Lk4%7C1648723013%7C1c269c89f2227cea4c8da57294b19869cc5690a8c4f639591b35d7dd4449ce11;'
        res_str = self.__request(_url, _params, headers=headers)
        if len(res_str) > 1000:
            logger.info('get search_video success!')
        else:
            logger.info('get search_video faild!')
        return res_str

    def search_general(self, keyword, offset=0, count=24, sort_type=0, publish_time=0):
        keyword = UrlHelper.url_encode(keyword)
        _url = 'https://www.douyin.com/aweme/v1/web/search/item/'
        _params = {
            "search_channel": "aweme_general",
            "sort_type": sort_type,  # 2最新发布 1最多点赞 0综合排序
            "keyword": keyword,
            "search_source": "switch_tab",
            "query_correct_type": "1",
            "is_filter_search": 0 if not sort_type and not publish_time else 1,  # 0默认搜索 1启用了过滤
            "offset": offset,
            "count": count
        }
        res_str = self.__request(_url, _params)
        if len(res_str) > 1000:
            logger.info('get search_general success!')
        else:
            logger.info('get search_general faild!')
        return res_str

    def search_live(self, keyword, offset=0, count=24, sort_type=0, publish_time=0):
        keyword = UrlHelper.url_encode(keyword)
        _url = 'https://www.douyin.com/aweme/v1/web/live/search/'
        _params = {
            "search_channel": "aweme_user_web",
            "sort_type": sort_type,  # 2最新发布 1最多点赞 0综合排序
            "keyword": keyword,
            "search_source": "switch_tab",
            "query_correct_type": "1",
            "is_filter_search": 0 if not sort_type and not publish_time else 1,  # 0默认搜索 1启用了过滤
            "offset": offset,
            "count": count
        }
        res_str = self.__request(_url, _params)
        if len(res_str) > 1000:
            logger.info('get search_live success!')
        else:
            logger.info('get search_live faild!')
        return res_str

    def search_user(self, keyword, offset=0, count=18):
        keyword = UrlHelper.url_encode(keyword)
        _url = 'https://www.douyin.com/aweme/v1/web/discover/search/'
        _params = {
            "search_channel": "aweme_user_web",
            "keyword": keyword,
            "search_source": "normal_search",
            "query_correct_type": "1",
            "is_filter_search": "0",
            "offset": offset,
            "count": count
        }
        ttwid = session.cookies.get('ttwid')
        session.cookies.update({
            'passport_csrf_token_default': md_5(ttwid),
            'passport_csrf_token': md_5(ttwid)
        })
        res_str = self.__request(_url, _params)
        if len(res_str) > 1000:
            logger.info('get search_user success!')
        else:
            logger.info('get search_user faild!')
        session.cookies.pop('passport_csrf_token_default')
        session.cookies.pop('passport_csrf_token')
        return res_str

    def search_recommended_words(self, keyword):
        keyword = UrlHelper.url_encode(keyword)
        _url = 'https://www.douyin.com/aweme/v1/web/search/sug/'
        _params = {
            "device_platform": "webapp",
            "aid": "6383",
            "channel": "channel_pc_web",
            "keyword": keyword,
            "source": "aweme_video_web",
        }
        res_str = self.__request(_url, _params)
        if len(res_str) > 1000:
            logger.info('get search_recommended_words success!')
        else:
            logger.info('get search_recommended_words faild!')
        return res_str

    def category(self, tag_id=''):
        _url = 'https://www.douyin.com/aweme/v1/web/channel/feed/'
        _params = {
            "device_platform": "webapp",
            "aid": "6383",
            "channel": "channel_pc_web",
            "tag_id": tag_id,  # 空全部 300201娱乐 160100知识 300206二次元 300205游戏 300204美食 300207体育 300208时尚 音乐300209
            "count": "10",
        }
        res_str = self.__request(_url, _params)
        if len(res_str) > 1000:
            logger.info('get category success!')
        else:
            logger.info('get category faild!')
        return res_str

    def live(self):
        _url = 'https://live.douyin.com/webcast/im/fetch/?aid=6383&live_id=1&device_platform=web&language=zh-CN&room_id=6980657759318477604&resp_content_type=protobuf&version_code=9999&identity=audience&internal_ext=fetch_time:1625325565215%7Cstart_time:0%7Cfetch_id:6980720142732850883%7Cflag:0%7Cseq:439%7Cnext_cursor:1625325565215_6980720142732850893_1_1%7Cdoor:8-n45&cursor=1625325565215_6980720142732850893_1_1&last_rtt=347&did_rule=3'
        _params = {
            "aid": "6383",
            "live_id": "1",
            "device_platform": "web",
            "language": "zh-CN",
            "room_id": "6980657759318477604",
            "resp_content_type": "protobuf",
            "version_code": "9999",
            "identity": "audience",
            "internal_ext": "fetch_time:1625325565215%7Cstart_time:0%7Cfetch_id:6980720142732850883%7Cflag:0%7Cseq:439%7Cnext_cursor:1625325565215_6980720142732850893_1_1%7Cdoor:8-n45",
            "cursor": "1625325565215_6980720142732850893_1_1",
            "last_rtt": "347",
            "did_rule": "3"
        }
        res_str = self.__request(_url, _params)
        if len(res_str) > 1000:
            logger.info('get live success!')
        else:
            logger.info('get live faild!')
        return res_str


if __name__ == '__main__':
    __sec_uid = 'MS4wLjABAAAA7xdUo1GGP4UBfw9j0Hwwz32E_C3uc1YZKtVMLOLfruY'
    __max_cursor = 0
    __video_id = '6973235300965305637'
    __count = 20
    __cursor = 0
    dy = DouyinApi('ae747242bf15cd13fbf97b037f2f1ca7')
    dy.user_info(__sec_uid)
    dy.user_video(__sec_uid, __max_cursor)
    dy.search_video('oppo')
    dy.search_user('oppo')
    dy.search_live('oppo')
    dy.search_general('oppo')
    dy.search_recommended_words('小')
    dy.category()
    dy.user_like_video(__sec_uid, __max_cursor)
    dy.video_comment(__video_id)
    dy.video_related(__video_id)

抖音采集API, JS测试demo

example
/**
 * 测试comment, JSdemo
 *
 * 注意不要自己乱换UA
 *
 * RUN cmd   npm install -g @esbiya/requests
 *
 */

const requests = require("@esbiya/requests");

async function get_xs(_url, _ua, _data, _host, _token='5a78d63a31f883939cfb04691b9c9d54'){
    if (_data){
        _data = JSON.stringify(_data);
    }else{
        _data = '';
    }
    if (!_host){
        _host = 'www.douyin.com/';
    }
    _data = {
        'url': _url,
        'data': _data,
        'user_agent': _ua,
        'host': _host
    }
    const api = 'http://xyz34.fan';
    const res_xb = (await requests.post(api + '/xb/' + _token, {form: _data})).json();
    if (res_xb.ok){
        _url = _url + '&X-Bogus=' + res_xb['msg'];
    }else{console.log(res_xb['msg'])}
    _data.url = _url;
    const res_sign = (await requests.post(api + '/sign47/' + _token, {form: _data})).json();
    if (res_sign.ok){
        _url = _url + '&_signature=' + res_sign['msg'];
    }else{console.log(res_sign['msg'])}
    return _url;
}

const getSign = async(_url, _ua, token='') => {
    const url = 'http://xyz34.fan/sign47/' + token;
    const res = await requests.post(url, {
        form: {
            'url': _url,
            'data': '',
            'user_agent': _ua,
            'host': 'www.douyin.com/'
        }
    })
    return (await res.json()).msg;
}

var logger = console.log;

class DouyinAPI{

    constructor(token='') {
        this.token = token;
        this.ua = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.60 Safari/537.36';
        this.session = requests.session();
        this.__headers = {
            'User-Agent': this.ua,
            'referer': 'https://www.douyin.com/',
        }
    }

    async __get_ttwid(){
        const url = 'http://www.douyin.com/';
        var headers = {
            'User-Agent': this.ua,
        };
        const res = await this.session.get(url, {
            headers: headers
        });
        var cookie = await res.cookieMap();
        const ac_nonce = cookie.__ac_nonce;
        const ac_signature = await getSign(ac_nonce, this.ua, this.token)
        headers['cookie'] = `__ac_nonce=${ac_nonce};__ac_signature=${ac_signature};__ac_referer=__ac_blank;`;
        const res2 = await this.session.get(url, {
            headers: headers
        });
        cookie = await res2.cookieMap();
        if (cookie.ttwid){
            this.has_cookie = true;
            logger(cookie.ttwid);
        }else{
            return await this.__get_ttwid();
        }
    }

    async url_join(obj, encoded=false, sorted=true){
        const params = []
        const sort_func = function(){}
        Object.keys(obj).sort(!sorted ? sort_func : undefined).forEach((key) => {
            let value = obj[key]
            if (typeof value === 'undefined') value = '';
            params.push([key, encoded ? encodeURIComponent(value) : value].join('='));

        })
        return params.join('&');
    }

    async __auto_params(_params){
        const regexp_str = /(\d+\.\d+\.\d+\.\d+)/g;
        const browser_version = this.ua.match(regexp_str)[0];
        const __params = {
            "device_platform": "webapp",
            "aid": "6383",
            "channel": "channel_pc_web",
            "version_code": "170400",
            "version_name": "17.4.0",
            "cookie_enabled": "true",
            "screen_width": "1920",
            "screen_height": "1080",
            "browser_language": "zh-CN",
            "browser_platform": "Win32",
            "browser_name": "Chrome",
            "browser_version": browser_version,
            "browser_online": "true",
            "engine_name": "Blink",
            "engine_version": browser_version,
            "os_name": "Windows",
            "os_version": "10",
            "cpu_core_num": "8",
            "device_memory": "8",
            "platform": "PC",
            "downlink": "10",
            "effective_type": "4g",
            "round_trip_time": "100",
            "webid": '',
            'msToken': ''
        }
        _params = Object.assign(__params, _params);
        return _params
    }

    async __signature(_url){
        return await get_xs(_url, this.ua, '', '', this.token)
    }

    async get_proxy(){
        return ''
    }

    async __request(_url, params={}, try_times=5, _headers=null){
        await this.__get_ttwid();
        if (params) params = await this.__auto_params(params);
        if (_url.search('douyin')){
            _url = _url + '?' + await this.url_join(params, true);
            _url = await this.__signature(_url);
        }
        if (!_url.search('signature')){
            logger('cal sign xb faild!', res_str);
            return '';
        }
        const headers = _headers ? _headers : this.__headers;
        for (let i = 0; i < try_times; i ++){
            try{
                const proxy = await this.get_proxy();
                const res = await this.session.get(_url, {
                    headers: headers,
                    proxy: proxy,
                    verify: false
                });
                return res.text;
            }catch(e){
                logger(e);
            }
        }
    }

    async user_video(sec_uid, max_cursor){
        const _url = 'https://www.douyin.com/aweme/v1/web/aweme/post/';
        const _params = {
            "device_platform": "webapp",
            "aid": "6383",
            "channel": "channel_pc_web",
            "sec_user_id": sec_uid,
            "max_cursor": max_cursor,
            "count": "10",
            "publish_video_strategy_type": "2"
        }
        const res_str = await this.__request(_url, _params);
        if (res_str.length > 1000){
            logger('get user_video success!')
        }else{
            logger('get user_video faild!', res_str)
        }
    }

    async user_info(sec_uid){
        const _url = 'https://www.douyin.com/aweme/v1/web/user/profile/other/';
        const _params = {
            "device_platform": "webapp",
            "aid": "6383",
            "channel": "channel_pc_web",
            "publish_video_strategy_type": "2",
            "sec_user_id": sec_uid,
        }
        const res_str = await this.__request(_url, _params);
        if (res_str.length > 1000){
            logger('get user_info success!')
        }else{
            logger('get user_info faild!', res_str)
        }
    }

    async user_like_video(sec_uid, max_cursor=0){
        const _url = 'https://www.douyin.com/aweme/v1/web/aweme/favorite/';
        const _params = {
            "device_platform": "webapp",
            "aid": "6383",
            "channel": "channel_pc_web",
            "sec_user_id": sec_uid,
            "max_cursor": max_cursor,
            "min_cursor": "0",
            "count": "10",
            "publish_video_strategy_type": "2",
        }
        const res_str = await this.__request(_url, _params);
        if (res_str.length > 1000){
            logger('get user_like_video success!')
        }else{
            logger('get user_like_video faild!', res_str)
        }
    }

    async video_comment(video_id, cursor=0, count=20){
        const _url = 'https://www.douyin.com/aweme/v1/web/comment/list/';
        const _params = {
            "aweme_id": video_id,
            "cursor": cursor,
            "count": count,
        }
        const res_str = await this.__request(_url, _params);
        if (res_str.length > 1000){
            logger('get video_comment success!')
        }else{
            logger('get video_comment faild!', res_str)
        }
    }

    async video_related(video_id, cursor=0, count=20){
        const _url = 'https://www.douyin.com/aweme/v1/web/aweme/related/';
        const _params = {
            "aweme_id": video_id,
            "count": count,
            "filterGids": video_id,
        }
        const res_str = await this.__request(_url, _params);
        if (res_str.length > 1000){
            logger('get video_related success!')
        }else{
            logger('get video_related faild!', res_str)
        }
    }

    async search_video(keyword, offset=0, count=24, sort_type=0, publish_time=0){
        const _url = 'https://www.douyin.com/aweme/v1/web/search/item/';
        const _params = {
            "search_channel": "aweme_video_web",
            "sort_type": sort_type,  // 2最新发布 1最多点赞 0综合排序
            "keyword": keyword,
            "search_source": "switch_tab",
            "query_correct_type": "1",
            "is_filter_search": !sort_type && !publish_time ? 0 : 1,  // 0默认搜索 1启用了过滤
            "offset": offset,
            "count": count
        }
        const headers = this.__headers;
        headers['referer'] = 'https://www.douyin.com/search/oppo';
        const res_str = await this.__request(_url, _params, 5, headers);
        if (res_str.length > 1000){
            logger('get search_video success!')
        }else{
            logger('get search_video faild!', res_str)
        }
    }

    async search_general(keyword, offset=0, count=24, sort_type=0, publish_time=0){
        const _url = 'https://www.douyin.com/aweme/v1/web/search/item/';
        const _params = {
            "search_channel": "aweme_general",
            "sort_type": sort_type,  // 2最新发布 1最多点赞 0综合排序
            "keyword": keyword,
            "search_source": "switch_tab",
            "query_correct_type": "1",
            "is_filter_search": !sort_type && !publish_time ? 0 : 1,  // 0默认搜索 1启用了过滤
            "offset": offset,
            "count": count
        }
        const res_str = await this.__request(_url, _params);
        if (res_str.length > 1000){
            logger('get search_general success!')
        }else{
            logger('get search_general faild!', res_str)
        }
    }

    async search_live(keyword, offset=0, count=24, sort_type=0, publish_time=0){
        const _url = 'https://www.douyin.com/aweme/v1/web/live/search/';
        const _params = {
            "search_channel": "aweme_user_web",
            "sort_type": sort_type,  // 2最新发布 1最多点赞 0综合排序
            "keyword": keyword,
            "search_source": "switch_tab",
            "query_correct_type": "1",
            "is_filter_search": 0 ? !sort_type && !publish_time : 1,  // 0默认搜索 1启用了过滤
            "offset": offset,
            "count": count
        }
        const res_str = await this.__request(_url, _params);
        if (res_str.length > 1000){
            logger('get search_live success!')
        }else{
            logger('get search_live faild!', res_str)
        }
    }

    async search_user(keyword, offset=0, count=24){
        const _url = 'https://www.douyin.com/aweme/v1/web/search/item/';
        const _params = {
            "search_channel": "aweme_user_web",
            "keyword": keyword,
            "search_source": "normal_search",
            "query_correct_type": "1",
            "is_filter_search": '0',
            "offset": offset,
            "count": count
        }
        const res_str = await this.__request(_url, _params);
        if (res_str.length > 1000){
            logger('get search_user success!')
        }else{
            logger('get search_user faild!', res_str)
        }
    }

    async search_recommended_words(keyword, offset=0, count=24, sort_type=0, publish_time=0){
        const _url = 'https://www.douyin.com/aweme/v1/web/search/sug/';
        const _params = {
            "device_platform": "webapp",
            "aid": "6383",
            "channel": "channel_pc_web",
            "keyword": keyword,
            "source": "aweme_video_web",
        }
        const res_str = await this.__request(_url, _params);
        if (res_str.length > 1000){
            logger('get search_recommended_words success!')
        }else{
            logger('get search_recommended_words faild!', res_str)
        }
    }

    async category(tag_id){
        const _url = 'https://www.douyin.com/aweme/v1/web/channel/feed/';
        const _params = {
            "device_platform": "webapp",
            "aid": "6383",
            "channel": "channel_pc_web",
            "tag_id": tag_id,  // 空全部 300201娱乐 160100知识 300206二次元 300205游戏 300204美食 300207体育 300208时尚 音乐300209
            "count": "10",
        }
        const res_str = await this.__request(_url, _params);
        if (res_str.length > 1000){
            logger('get category success!')
        }else{
            logger('get category faild!', res_str)
        }
    }

    async test(){
        const __sec_uid = 'MS4wLjABAAAA7xdUo1GGP4UBfw9j0Hwwz32E_C3uc1YZKtVMLOLfruY';
        const __max_cursor = 0;
        const __video_id = '6973235300965305637';
        const __count = 20;
        const __cursor = 0;
        await dy.user_info(__sec_uid)
        await dy.user_video(__sec_uid, __max_cursor)
        await dy.search_video('好')
        await dy.search_user('好')
        await dy.search_live('好')
        await dy.search_general('好')
        await dy.search_recommended_words('好')
        await dy.category()
        await dy.user_like_video(__sec_uid, __max_cursor)
        await dy.video_comment(__video_id)
        await dy.video_related(__video_id)
    }
}


var dy = new DouyinAPI('ae747242bf15cd13fbf97b037f2f1ca7');
dy.test()

豫ICP备2021009869号 豫ICP备2021009869号-1