Как сканировать список видео Douyin с помощью python

рептилия

Введение

Если вы видите видео блогера Douyin, которое вам особенно интересно, и хотите сбросить их все, что вам делать? Ниже показано, как использовать python для экспорта всей видеоинформации определенного пользователя.

img

Анализ захвата пакетов

  • Инструменты разработчика Chrome Инструменты разработчика браузера Chrome

В приложении Douyin скопируйте адрес домашней страницы видеоблогера, например:http://v.douyin.com/kGcU4y/, Используйте браузер Chrome, чтобы зарегистрироваться на стороне ПК, и имитируйте мобильный телефон, выберите здесь iPhone, а затем поместите скопированный адрес домашней страницы в браузер для доступа, и страница перейдет кhttps://www.iesdouyin.com/share/user/110677980134

  • Потяните вниз домашнюю страницу, выберите вкладку Network => XHR и увидите аналогичный запрос.
:authority: www.iesdouyin.com
:method: GET
:path: /web/api/v2/aweme/post/?user_id=110677980134&sec_uid=&count=21&max_cursor=1561112910000&aid=1128&_signature=3Xf-nxAQgGfUO4SKisB.Ld13.o&dytk=061ae6e81229e178146aa674327eba89
:scheme: https
accept: application/json
accept-encoding: gzip, deflate, br
accept-language: zh-CN,zh;q=0.9,en;q=0.8,ja;q=0.7,zh-TW;q=0.6,da;q=0.5
cookie: tt_webid=6690145457198417412; _ga=GA1.2.605400954.1557670882; _ba=BA0.2-20181226-5199e-GIJXgXk9ajNkyFhmv7Wy; _gid=GA1.2.1914501522.1562857517
referer: https://www.iesdouyin.com/share/user/110677980134
user-agent: Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1
x-requested-with: XMLHttpRequest

Скриншот возврата данных

img

Анализируя URL-адрес запроса ajaxhttps://www.iesdouyin.com/web/api/v2/aweme/post/?user_id=110677980134&sec_uid=&count=21&max_cursor=1559299764000&aid=1128&_signature=3Xf-nxAQgGfUO4SKisB.Ld13.o&dytk=061ae6e81229e178146aa674327eba89Полученные параметры запроса в основном включают в себя:

поле тип инструкция
user_id int Идентификатор учетной записи Douyin
count int Количество возвращаемых данных, используйте значение по умолчанию 21.
max_cursor int Запрошенный курсор, каждый запрос принимает значение max_cursor, возвращенное предыдущим запросом.
aid int Используйте значение по умолчанию 11128
_signature string Подпись параметра при каждом запросе
dytk string Один параметр на запрос

Как получить параметры:

  • user_id получает доступ к адресу домашней страницы и перенаправляет URL-адрес (https://www.iesdouyin.com/share/user/110677980134) может получить user_id
  • dytk включает этот параметр в исходный код веб-страницы главной страницы, фрагмент исходного кода веб-страницы
(function() {
    $(function(){
        __M.require('douyin_falcon:page/reflow_user/index').init({
            uid: "110677980134",
            dytk: '061ae6e81229e178146aa674327eba89'
        });
    });
})();

Этот параметр приобретается положительным

  • _signature получить сложнее, Douyin запутывает и сжимает внешний js-код, поэтому напрямую анализировать процесс алгоритма непросто, но он может выполнить код алгоритма подписи и вернуть соответствующий результат подписи.
  • Вы можете использовать nodejs или selenium webdriver для выполнения кода js. Здесь рекомендуется использовать selenium webdriver. Среда выполнения js для nodejs отличается от среды браузеров. Вычисленный результат подписи не может пройти проверку. Selenium webdriver может вызывать локальный браузер для расчета Подпись может быть согласована с подписью, рассчитанной путем прямого доступа браузера.
  • js код после форматирования,Нажмите, чтобы просмотреть, выполнить метод js_bytedAcrawler.sign("110677980134")Подпишите параметр

Реализация кода для экспорта списка видео на главной странице

def get_user_video_list_by_uid(user_id, cursor=0):
    url = 'https://www.iesdouyin.com/web/api/v2/aweme/post/?'
    sign, dytk = signature(user_id)
    tk_logger.info("sign:%s,dytk:%s" % (sign, dytk))
    if sign is None or dytk is None:
        tk_logger.log("sign [%s] or dytk [%s] is none" % (sign, dytk))
        return None
    headers = dict_merge(CHROME_HEADER, {
        "Accept": "application/json",
        "X-Requested-With": "XMLHttpRequest",
    })
    params = {
        "user_id": user_id,
        "count": "21",
        "max_cursor": cursor,
        "aid": "1128",
        "_signature": sign,
        "dytk": dytk
    }
    res = requests.get(url, headers=headers, params=params)
    tk_logger.info("request url: %s" % res.url)
    content = res.content.decode("utf8")
    jsn = json.loads(content)
    return jsn

Получить информацию о списке видео

视频列表

Получить фрагмент информационного кода видео

def get_video_detail_by_id(video_id):
    url = "https://aweme-hl.snssdk.com/aweme/v1/aweme/detail/?version_code=6.5.0&pass-region=1&pass-route=1&js_sdk_version=1.16.2.7&app_name=aweme&vid=9D5F078E-A1A9-4F64-81C7-F89CA6A3B1DC&app_version=6.5.0&device_id=34712926793&channel=App%20Store&mcc_mnc=46011&aid=1128&screen_width=750&openudid=263bd93f02801d126ca004edccbff8f6e1b19f51&os_api=18&ac=WIFI&os_version=12.3.1&device_platform=iphone&build_number=65014&device_type=iPhone9,1&iid=74239983401&idfa=F39B285A-4B4F-4874-9D7E-C728A892BF6D"
    data = {"aweme_id": video_id}
    headers = {
        "sdk-version": "1",
        "x-Tt-Token": "00fc1e7950db67b5f43a312e9265cdfee513ea70c36d918c871f3bb553347f3db50ffca143b8722327b345816a75efca071d",
        "User-Agent": "Aweme 6.5.0 rv:65014 (iPhone; iOS 12.3.1; en_CN) Cronet",
        "Content-Type": "application/x-www-form-urlencoded",
        "Cookie": "tt_webid=6636348554880222728; __tea_sdk__user_unique_id=6636348554880222728; odin_tt=76d9b82d6e6f2ddfc99719a5b5d44a7d703cf977f0f7bddf8537f93920d57cb9ec33162ee47868b760f6b09e69209bb2f90bad220b75678af850a0dfa9f056e2; install_id=74239983401; ttreq=1$dab0516952a4157c0c11d4993533c09d6e45fc94; sid_guard=fc1e7950db67b5f43a312e9265cdfee5%7C1559955316%7C5184000%7CWed%2C+07-Aug-2019+00%3A55%3A16+GMT; uid_tt=0afcb06309f632d872799ec0ac3b2c80; sid_tt=fc1e7950db67b5f43a312e9265cdfee5; sessionid=fc1e7950db67b5f43a312e9265cdfee5",
        "X-Khronos": "1559956401",
        "X-Gorgon": "8300000000002e40eee38cad71d14037bd1385d18bc973f094f5",
    }
    ret = {}
    res = requests.post(url, data=data, headers=headers)
    if res.status_code == 200:
        # tk_logger.info("video detail raw:%s" % res.content.decode("utf8"))
        jsn = json.loads(res.content)
        detail = jsn.get("aweme_detail", {})
        video_info = get_video_info(detail)
        user_info = get_user_info(detail)
        play_addr = get_play_address(detail)
        video_cover = get_video_cover(detail)
        ret["video_info"] = video_info
        ret["user_info"] = user_info
        ret["play_addr"] = play_addr
        ret["video_cover"] = video_cover
    else:
        raise TKException("get video detail failed [%s][%d]" % (url, res.status_code))
    return ret

Скачать фрагменты кода видео

detail =  get_video_detail_by_id(video_id)
def download_video(detail):
    url = detail.get("play_addr", {}).get("url_list", [])
    if len(url) == 0:
        raise TKException("cannot get video url list [%s]" % detail)

    url = url[0]
    folder = DOWNLOAD_DIR + '/' + detail.get('user_info', {}).get("uid", "unknown")
    if not os.path.exists(folder):
        os.mkdir(folder)
    video_id = detail.get('video_info', {}).get('statistics', {}).get('aweme_id')
    # filename = "%s/%s" % (folder, detail.get("video_info", {}).get("desc", video_id) + ".mp4")
    filename = "%s/%s" % (folder, video_id + ".mp4")
    tk_logger.info("download video %s" % url)
    if os.path.isfile(filename):
        file_size = get_remote_file_size(url)
        if file_size == os.path.getsize(filename):
            tk_logger.info("file already downloaded, skip ...")
            return
        else:
            tk_logger.info("download file , file size:%d" % file_size)
    res = requests.get(url, headers=IOS_HEADER)
    if res.status_code == 200:
        with open(filename, "wb") as fp:
            for chunk in res.iter_content(chunk_size=1024):
                fp.write(chunk)
    else:
        raise TKException("download video [%s] failed [%d]" % (url, res.status_code))

скачать видео

img

утверждение

Это руководство предназначено только для общения и обучения, а не для коммерческих целей.Посмотреть исходный текст