• 抖音 uper 视频爬取


    提示:

    1.本代码实例仅供学习使用,请遵守你所在地的法律法规。

    2.IDE:PyCharm 2021.1.1 python:3.9 

    3.selenium,browsermobproxy库的安装方法请自行百度

    4.感谢 极客挖掘机(https://www.geekdigging.com/) 分享的python学习内容

    import os
    import re
    import time
    import random
    import requests
    from pyquery import PyQuery
    from urllib.parse import urlencode
    from tqdm import tqdm  # 下载进度条
    from browsermobproxy import Server  # 代理,用于抓取 har 中的视频列表请求参数
    from selenium import webdriver  # 调用浏览器,用于访问 uper 页面以产生访问视频列表 api 地址的行为
    from selenium.webdriver.chrome.options import Options
    
    
    # 中文、英文标点符号两者之间互换
    def exchange_char(char_in, char_type='cn'):
    
        char_cn = ['', '', '', '*', '', '', '', '', '', '|', '', '']   # 中文标点符号
        char_en = ['/', '\', ':', ' ', '?', '"', '"', '<', '>', ' ', "'", "'"]     # 要互换的英文标点符号,与上面的中文列表对应
        char_out = str(char_in)
    
        for i in range(0, len(char_en)):
            if char_type == 'cn':
                # 英文2成中文
                char_out = char_out.replace(char_en[i], char_cn[i])
            else:
                # 中文2成英文
                char_out = char_out.replace(char_cn[i], char_en[i])
    
        return char_out
    
    
    # 新建文件夹
    def create_dir(path):
        if os.path.exists(path) is False:
            os.makedirs(path)
        # 切换到路径
        os.chdir(path)
    
    
    # 视频下载
    def down_video(vedio_url, file_path):
        file_name = os.path.basename(file_path)
        try:
            '''
            tqdm 参数:
                使用手动设置更新
                total 设置总大小
                initial 当前操作文件的大小
                desc 进度条前的描述
                ncols 设置进度条显示长度
                nit_scale 如果设置,迭代的次数会自动按照十、百、千来添加前缀,默认为false
            '''
            # 下载视频
            rsp = requests.get(vedio_url, stream=True, headers=headers)
            length = float(rsp.headers['content-length'])
            with open(file_path, 'wb') as fb:
                global down_count
                down_count += 1
                msg = '~~~下载中' + str(down_count) + '' + file_name
                pbar = tqdm(initial=os.path.getsize(file_path), desc=msg,
                            total=length, unit_scale=True, ncols=150, mininterval=0.5)
                for chuck in rsp.iter_content(chunk_size=512):
                    if chuck:
                        fb.write(chuck)
                        pbar.update(512)  # 手动进度条
                pbar.close()
        except requests.exceptions.ConnectionError:
            print('
    !!!连接错误:' + file_name + '
    ' + vedio_url)
        except requests.exceptions.Timeout:
            print('
    !!!连接超时:' + file_name + '
    ' + vedio_url)
    
    
    # 下载单个分享的视频
    def down_one(share_url):
        # 真实url
        url_real = requests.head(share_url).headers['Location']  # 302 后的url
    
        # 视频id
        item_ids = re.compile(r'video/(d+)').findall(url_real)[0]  # 获取视频 id
        item_info_url = f"https://www.iesdouyin.com/web/api/v2/aweme/iteminfo/?item_ids={item_ids}"  # 拼接请求
    
        # 获取视频源路径
        res_json = session.get(item_info_url, headers=headers).json()
        vedio_url = res_json['item_list'][0]['video']['play_addr']['url_list'][0]
        video_name = res_json['item_list'][0]['share_info']['share_title'].split('#')[0].split('@')[0].replace(' ', '')
        video_name = exchange_char(video_name)  # 英文标点符号无法作为文件名
    
        file_path = video_name + fileFormat
    
        # 下载视频
        down_video(vedio_url, file_path)
    
    
    # 获取视频列表查询参数
    def get_list_querypara(share_url):
        # 真实url
        url_real = requests.head(share_url).headers['Location']  # 302 后的url
    
        # 开启代理
        bmp_server = Server(".\browsermob-proxy-2.1.4\bin\browsermob-proxy.bat")
        bmp_server.start()
        bmp_proxy = bmp_server.create_proxy()
    
        # 配置 Proxy 启动 WebDriver
        chrome_options = Options()
        # 开启无窗口模式
        chrome_options.add_argument('--headless')
        # 禁用扩展插件,因为我也不是太懂,总之没了这句,浏览器会报警提示如下图。魔法,勿动。
        chrome_options.add_argument('--ignore-certificate-errors')
        # bmp_proxy.proxy返回的是localhost:8081端口
        chrome_options.add_argument('--proxy-server={0}'.format(bmp_proxy.proxy))
        # 如果Selenium驱动放在了python.exe同级目录下,executable_path参数可以省略
        # driver = webdriver.Chrome(executable_path="D:Apythonchromedriver.exe", options=chrome_options)
        driver = webdriver.Chrome(chrome_options=chrome_options)
    
        # 个人理解是new一个空的har准备接收爬取网站的交互信息
        bmp_proxy.new_har("douyin", options={'captureHeaders': True, 'captureContent': True})
        # 模拟浏览器
        driver.get(url_real)
    
        # 请求的har
        json_har = bmp_proxy.har
        # 输出 har 到文件
        # import json
        # result_json = json.dumps(json_har, indent=4)
        # with open("douyin.json", "w", errors="igone") as f:
        #     f.write(result_json)
        dict_query = {}
        for entry in json_har['log']['entries']:
            entry_url = entry['request']['url']
            # 根据URL找到数据接口
            if url_api_list in entry_url:
                for query in entry['request']['queryString']:
                    dict_query[query['name']] = query['value']
                break
            else:
                continue
    
        # 请求结果,uper主ID
        html = driver.page_source
        doc = PyQuery(html)
        uper_id = doc('p.shortid').text()
    
        bmp_server.stop()
        driver.quit()
    
        # 为 uper 新建目录
        dir_path = save_path + '\' + uper_id
        create_dir(dir_path)
    
        return {'dict_query': dict_query, 'dir_path': dir_path}
    
    
    # 下载视频列表
    def down_list(dict_info):
    
        dict_query = dict_info['dict_query']
        dir_path = dict_info['dir_path']
    
        if dict_query:
            # 视频列表
            url_json = url_api_list + '?' + urlencode(dict_query)
            # print('
    ###API请求URL:' + url_json)
            json_video_list = session.get(url_json, headers=headers).json()
            dict_info['dict_query']['max_cursor'] = json_video_list['max_cursor']  # 更新参数
            if json_video_list['has_more']:
                # 过滤空列表
                if json_video_list['aweme_list']:
                    # 遍历下载
                    for aweme in json_video_list['aweme_list']:
                        # aweme_id = aweme['aweme_id']
                        vedio_url = aweme['video']['play_addr']['url_list'][0]
                        video_name = aweme['desc'].split('#')[0].split('@')[0].replace(' ', '')
                        video_name = exchange_char(video_name)  # 英文标点符号无法作为文件名
                        file_path = dir_path + '\' + video_name + fileFormat
                        if os.path.isfile(file_path):
                            global down_count
                            down_count += 1
                            msg = '
    ***已存在' + str(down_count) + '' + os.path.basename(file_path)
                            print(msg)
                            pass
                        else:
                            time.sleep(random.random() * 1)  # 设置访问时间间隔,防止下载过于频繁
                            down_video(vedio_url, file_path)
                    else:
                        # 下载完毕,下一页
                        down_list(dict_info)
                else:
                    # 空列表,下一页
                    down_list(dict_info)
            else:
                print('
    ###全部下载完毕。')
        else:
            print('
    queryString 错误,无法开始下载')
    
    
    if __name__ == '__main__':
        # 保存路径
        save_path = 'D:\douyin_down'
        # 文件格式
        fileFormat = '.mp4'
        # 下载统计
        down_count = 0
        # 视频列表api
        url_api_list = 'https://www.iesdouyin.com/web/api/v2/aweme/post/'
        # 创建一个请求头
        headers = {
            'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15'
                          ' (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1'
        }
        session = requests.Session()
    
        # 单个分享视频下载
        # down_url_video = "https://v.douyin.com/efvrSgd/"  # 视频分享路径
        # down_one(down_url_video)
    
        # Uper所有视频下载
        down_url_uper = "https://v.douyin.com/eftqWpm/"  # uper主页分享URL
        dict_uper = get_list_querypara(down_url_uper)
        down_list(dict_uper)
  • 相关阅读:
    RMAN详细教程(三):备份脚本的组件和注释
    RMAN详细教程(二):备份、检查、维护、恢复
    RMAN详细教程(一):基本命令代码
    centos6和centos7的防火墙基本命令
    如何在Centos服务器上搭建起Oracle10、VNC、以及FTP
    添加Chrome插件时出现“程序包无效”等问题的解决办法
    配置服务器的磁盘阵列并正确分区
    配置VNC并远程控制服务器(电脑)
    .Net之路(十五)图解LoadRunner压力测试
    Mysql免安装版安装配置及常用操作
  • 原文地址:https://www.cnblogs.com/nb08611033/p/14790393.html
Copyright © 2020-2023  润新知