36. 实战:基于上一节的全面升级——实现某音批量下载功能

news2024/11/18 12:21:30

目录

前言

目的

思路

代码实现

1. 先将下载单个视频的功能封装成函数

2. 获取下载列表

3. 创建线程池调用下载函数

完整源码

运行效果

总结


前言

上一节我们实现了某短视频平台的去水印下载功能,本节我们实现批量抓取:给定某一个用户主页,抓取他的全部视频。


目的

基于多线程实现高效批量抓取任意主页的全部视频


思路

1. 我们实际上已经实现了单个视频的无水印下载,那么我们只需要从主页获得大量的视频链接即可

2. 访问用户主页,审查元素,找到视频列表,获取大量链接

3. 创建线程池,将视频链接放入单个视频下载的函数批量执行


代码实现

1. 先将下载单个视频的功能封装成函数

def grab_single_video(link):
    url = f'{link}'
    headers = {
        'cookie': 'douyin.com; __ac_nonce=063d749310021f8bd394b; __ac_signature=_02B4Z6wo00f01R8urHgAAIDBnyxWOmwmfMUfDqjAACQfd6; ttwid=1%7CtRZY98IpvYfhjM-VRDQHgX3mgPcfWwWxylxnwwC7fFk%7C0%7C9af2c384c7d2b4e10ec0497fce797af996c72dd3868ec040595de36132c01ad0; home_can_add_dy_2_desktop=%220%22; passport_csrf_token=ee0cbadbf97ac430daac207c46997ca1; passport_csrf_token_default=ee0cbadbf97ac430daac207c46997ca1; strategyABtestKey=%221675053365.079%22; s_v_web_id=verify_ldibiwgl_ycqaypzT_aJxd_4ZEW_9iGD_XkAPFGlhzwd3; AB_LOGIN_GUIDE_TIMESTAMP=%221675053363589%22; msToken=L3xfxnCP4kW9_qabjW3S1cud_5DmI99tIEOw1_lJDMgdp1GJ9KQd6HWXKepYY-7iLlj4SR_V02zL3lYO6FVnXoPPVNneC5bD9cEnYN4nNpXzaNmvq7oA; ttcid=a598309ef5f3442b95f1d979574083f925; tt_scid=Px0Q21O38QIdeziR7nBXUqfZYJaS4qKakt5Zkfio72r9U4XaJdOYTb37LsjIrRLQca96; msToken=xibNm7RgEpzX8c6UaAgkzAOHMr5TcWNmNbfFR1vD-3uNUhtRXEqVQrmPIV6iDsnsA3WhMCTIOGDtST_F9GEyq8In6Dj7ug-RXsQ6dWDIjzE3OXKr5dlj',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36'
    }
    resp = requests.get(url=url, headers=headers)
    # resp = urllib.parse.unquote(resp.text)
    # print(resp.text)

    # 正则抓标题
    obj = re.compile(r"<span><span><span><span>(?P<title>.*?)</span></span></span></span>", re.S)
    title = obj.search(resp.text).group("title")
    # print(title)

    # 正则抓视频信息
    info = re.findall('<script id="RENDER_DATA" type="application/json">(.*?)</script', resp.text)[0]
    # print(info)

    # url解码
    html_data = urllib.parse.unquote(info)
    html_data = json.loads(html_data)
    # pprint(html_data)  # 让字典更加美观

    # 字典取值,拿视频播放链接
    video_url = 'https:' + html_data['41']['aweme']['detail']['video']['bitRateList'][0]['playAddr'][0]['src']
    # print(video_url)

    # 获取视频二进制数据
    video_content = resp = requests.get(url=video_url, headers=headers).content

    # 保存视频
    if not os.path.exists('./4_video_batch'):
        os.mkdir('./4_video_batch')
    with open('./4_video_batch/' + title + '.mp4', mode='wb') as f:
        f.write(video_content)

 详细讲解见上一节:35. 实战:Python实现视频去水印(文末源码)

2. 获取下载列表

这里用了selenium的循环滚动功能,一直拉到主页最下面才停止,而判断它停止的方法就是滚动条上下的距离相等,还是比较巧妙的。

然后审查元素发现视频列表放在CSS选择器里面,并且都在一个class里,那么就用我们刚学过的知识,用CSS选择器筛选出这个class的所有列表项。

创建一个空列表,遍历所有的列表项,将其中的href写入列表即可,最后返回列表。 

def grab_video_list():
    # 准备好参数配置
    opt = Options()
    opt.add_argument("--headless")
    opt.add_argument("--disable-gpu")

    driver = Chrome(options=opt)  # 把参数配置设置到浏览器中
    driver.get('见评论区')

    # 向下滚动至元素可见(翻完这人的主页)
    # 定义一个初始值
    temp_height = 0
    while True:
        # 循环将滚动条下拉
        driver.execute_script("window.scrollBy(0,1000)")
        # sleep一下让滚动条反应一下
        time.sleep(1)
        # 获取当前滚动条距离顶部的距离
        check_height = driver.execute_script(
            "return document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop;")
        # 如果两者相等说明到底了
        if check_height == temp_height:
            break
        temp_height = check_height
        print(check_height)

    lis = driver.find_elements(By.CSS_SELECTOR, '.Eie04v01')
    url_list = []
    for li in lis:
        url = li.find_element(By.CSS_SELECTOR, 'a').get_attribute('href')
        # print(url)
        url_list.append(url)
    return url_list

3. 创建线程池调用下载函数

其实就是主函数的逻辑

def main():
    video_list = grab_video_list()
    # 创建线程池
    with ThreadPoolExecutor(50) as t:
        for i in video_list:
            t.submit(grab_single_video, link=i)
    # 等待线程池中的任务全部执行完毕
    print("Clear!!!")

先用获取下载列表函数拿到主页所有链接,然后创建线程池,将所有链接扔进下载函数。

(其实这里可以改进,用异步的方法把链接全部输入进去) 


完整源码

import requests
import re
import json
import urllib
from urllib import parse
import os
from pprint import pprint
from selenium.webdriver import Chrome
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
import time
from concurrent.futures import ThreadPoolExecutor

"""
    常规找视频资源:到Network --> Media里面抓包,就能得到地址
    然后在Media里面拿到地址,去全局搜索URL来源
"""


def grab_video_list():
    # 准备好参数配置
    opt = Options()
    opt.add_argument("--headless")
    opt.add_argument("--disable-gpu")

    driver = Chrome(options=opt)  # 把参数配置设置到浏览器中
    driver.get('见评论区')

    # 向下滚动至元素可见(翻完这人的主页)
    # 定义一个初始值
    temp_height = 0
    while True:
        # 循环将滚动条下拉
        driver.execute_script("window.scrollBy(0,1000)")
        # sleep一下让滚动条反应一下
        time.sleep(1)
        # 获取当前滚动条距离顶部的距离
        check_height = driver.execute_script(
            "return document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop;")
        # 如果两者相等说明到底了
        if check_height == temp_height:
            break
        temp_height = check_height
        print(check_height)

    lis = driver.find_elements(By.CSS_SELECTOR, '.Eie04v01')
    url_list = []
    for li in lis:
        url = li.find_element(By.CSS_SELECTOR, 'a').get_attribute('href')
        # print(url)
        url_list.append(url)
    return url_list


def grab_single_video(link):
    url = f'{link}'
    headers = {
        'cookie': 'douyin.com; __ac_nonce=063d749310021f8bd394b; __ac_signature=_02B4Z6wo00f01R8urHgAAIDBnyxWOmwmfMUfDqjAACQfd6; ttwid=1%7CtRZY98IpvYfhjM-VRDQHgX3mgPcfWwWxylxnwwC7fFk%7C0%7C9af2c384c7d2b4e10ec0497fce797af996c72dd3868ec040595de36132c01ad0; home_can_add_dy_2_desktop=%220%22; passport_csrf_token=ee0cbadbf97ac430daac207c46997ca1; passport_csrf_token_default=ee0cbadbf97ac430daac207c46997ca1; strategyABtestKey=%221675053365.079%22; s_v_web_id=verify_ldibiwgl_ycqaypzT_aJxd_4ZEW_9iGD_XkAPFGlhzwd3; AB_LOGIN_GUIDE_TIMESTAMP=%221675053363589%22; msToken=L3xfxnCP4kW9_qabjW3S1cud_5DmI99tIEOw1_lJDMgdp1GJ9KQd6HWXKepYY-7iLlj4SR_V02zL3lYO6FVnXoPPVNneC5bD9cEnYN4nNpXzaNmvq7oA; ttcid=a598309ef5f3442b95f1d979574083f925; tt_scid=Px0Q21O38QIdeziR7nBXUqfZYJaS4qKakt5Zkfio72r9U4XaJdOYTb37LsjIrRLQca96; msToken=xibNm7RgEpzX8c6UaAgkzAOHMr5TcWNmNbfFR1vD-3uNUhtRXEqVQrmPIV6iDsnsA3WhMCTIOGDtST_F9GEyq8In6Dj7ug-RXsQ6dWDIjzE3OXKr5dlj',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36'
    }
    resp = requests.get(url=url, headers=headers)
    # resp = urllib.parse.unquote(resp.text)
    # print(resp.text)

    # 正则抓标题
    obj = re.compile(r"<span><span><span><span>(?P<title>.*?)</span></span></span></span>", re.S)
    title = obj.search(resp.text).group("title")
    # print(title)

    # 正则抓视频信息
    info = re.findall('<script id="RENDER_DATA" type="application/json">(.*?)</script', resp.text)[0]
    # print(info)

    # url解码
    html_data = urllib.parse.unquote(info)
    html_data = json.loads(html_data)
    # pprint(html_data)  # 让字典更加美观

    # 字典取值,拿视频播放链接
    video_url = 'https:' + html_data['41']['aweme']['detail']['video']['bitRateList'][0]['playAddr'][0]['src']
    # print(video_url)

    # 获取视频二进制数据
    video_content = resp = requests.get(url=video_url, headers=headers).content

    # 保存视频
    if not os.path.exists('./4_video_batch'):
        os.mkdir('./4_video_batch')
    with open('./4_video_batch/' + title + '.mp4', mode='wb') as f:
        f.write(video_content)


def main():
    video_list = grab_video_list()
    # 创建线程池
    with ThreadPoolExecutor(50) as t:
        for i in video_list:
            t.submit(grab_single_video, link=i)
    # 等待线程池中的任务全部执行完毕
    print("Clear!!!")


if __name__ == '__main__':
    main()

运行效果

这里用我家咯咯的主页为例演示一下(纯路人):

把主页链接复制进URL,运行:

(输出的数字是滚动条高度,下载过程因网速而异,只要不报错就在下载。)

(如果想看得清楚可以在下载单个视频的函数那里自己加一个print输出,我就不加了)


总结

本节基于多线程实现了高效批量抓取任意主页的全部视频,只需要替换主页URL即可。示例URL我放在评论区了,有需要的自取即可!也可以选自己喜欢的博主测试一下。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/192067.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Cache的PLRU替换策略

LRU(Least Recently Used)替换策略是cache的经典替换策略之一,然而,LRU替换策略的硬件开销较大。因此,一些现代处理器,例如Intel 486和PowerPC,它们使用的cache替换策略是PLRU(pseudo-LRU)。 PLRU是LRU的一种近似方法,本文介绍PLRU中的tree-PLRU(tree-based pseudo-…

VSCode 配置 C/C++ 开发环境( MSVC )

0.绿色版本下载地址&#xff1a;https://www.aliyundrive.com/s/DMK13owZSrC绿色版本采用 VSCode User 1.7.4.2 X64 版本。绿色便携版本采用的生成工具来自 Visual C 2010 版本提供的 32 位工具链。Win 7 Win10 Win 11 可以正常运行。使用方法&#xff0c;下载文件后&#xff0…

微信小程序021理发店美容预约系统java nodejs php

美容预约小程序微信端要求在系统的手机上可以运行&#xff0c;主要实现了管理端&#xff1b;首页、个人中心、用户管理、服务项目管理、美容师管理、预约管理、类型管理、系统管理&#xff0c;微信端&#xff1b;首页、预约、我的等主要功能模块的操作和管理。 小程序前端框架&…

ML LightGBM详细原理讲解+面试必考知识点

&#x1f604; 三大竞赛杀器&#xff1a;XGBoost、LightGBM、CatBoost。之前我已更新完XGBoost的讲解&#xff0c;这次来讲讲LightGBM。我也是看网上看了多篇文章做总结的(我是遇到不会问题的就去搜&#xff0c;实在记不起来看过哪些&#xff0c;如果有侵权问题&#xff0c;可私…

Spark 读取、写入时序数据库TDengine以及TDengine概述

一、TDengine是什么TDengine 是一款高性能、分布式、支持 SQL 的时序数据库&#xff0c;其核心代码&#xff0c;包括集群功能全部开源&#xff08;开源协议&#xff0c;AGPL v3.0&#xff09;。TDengine 能被广泛运用于物联网、工业互联网、车联网、IT 运维、金融等领域。除核心…

Postman form-data、x-www-form-urlencoded的区别

我们在平时的postman请求调试&#xff0c;以及web的http请求开发时&#xff0c;常常能看到以下几种传参的形式 form-data、x-www-form-urlencoded、raw、binary&#xff0c;那么这些请求方式的区别是什么呢&#xff1f; 1、form-data: 就是http请求中的multipart/form-data,它…

一文读懂!2023量子计算行业发展方向

&#xff08;图片来源&#xff1a;网络&#xff09;量子计算是一个引人入胜的主题&#xff0c;放眼全球&#xff0c;很多文章报道了商业量子计算的项目和应用&#xff0c;关于量子计算行业在2023年的可能发展方向&#xff0c;本文从大量文章中筛选罗列了一些主要发展方向。McKi…

postman生成测试报告

一、newman插件生成测试报告安装nodejs官网下载适合自己设备的包&#xff0c;下载后直接傻瓜式安装&#xff1b;安装完成验证&#xff1a;打开终端&#xff0c;输入 node -v&#xff0c;即可查看安装版本&#xff1b;安装newman安装好nodejs后&#xff0c;通过npm来安装newman&…

VueJS 基础之组件

文章目录参考描述组件化开发组成templatescriptstylemain.js使用嵌套关系组件的使用LeftRight举个栗子全局组件及私有组件私有组件全局组件举个栗子main.jsApp.vue参考 项目描述VueJS官方文档搜索引擎Bing哔哩哔哩黑马程序员 描述 项目描述Edge109.0.1518.70 (正式版本) (64 …

计算机网路6-详述网路层:数据交换、路由算法和协议、网络协议

一、网络层基本概念 1、主要任务 把分组从源端传到目的端&#xff0c;为分组交换网上的不同主机提供通信服务 2、网络层传输单位--数据报 数据报与分组之间关系&#xff1a; 分组是数据报通过切割划分出来的一个片段&#xff0c;多个分组组成数据报 3、网络层的几大功能 路…

LeetCode-122. 买卖股票的最佳时机 II

目录暴力递归动态规划贪心题目来源 122. 买卖股票的最佳时机 II 暴力递归 根据题意&#xff1a;由于不限制交易次数&#xff0c;在每一天&#xff0c;就可以根据当前是否持有股票选择相应的操作。「暴力搜索」在树形问题里也叫「回溯搜索」、「回溯法」。 首先画出树形图&…

如何实现报表集成?(二)——用户同步和单点登录

在上一篇&#xff0c;我们对报表集成进行了一个整体的介绍&#xff0c;从报表集成的背景、痛点、需求、集成架构等几个方面进行了阐述。 这一篇&#xff0c;我们来聊一下用户同步和单点登录。行文过程中得到了来自报表软件厂商 Smartbi 的报表产品&#xff1a;电子表格软件的协…

c++11 标准模板(STL)(std::multiset)(三)

定义于头文件 <set> template< class Key, class Compare std::less<Key>, class Allocator std::allocator<Key> > class multiset;(1)namespace pmr { template <class Key, class Compare std::less<Key>> usi…

怎么给视频配音好听?这些好方法快学起来

应该不少小伙伴每天都会刷各种短视频&#xff0c;有些视频很搞笑&#xff0c;有些却很无趣&#xff0c;让人想直接的划走。很多制作短视频的小伙伴应该都知道&#xff0c;很多视频都需要配音来衬托&#xff0c;吸引别人的眼球。当你想给自己的视频配上好听的声音&#xff0c;但…

QT/C++——网络编程

目录 一、基础知识复习 二、UDP 客户端&#xff1a; 服务器&#xff1a; 三、TCP 服务器&#xff1a; 客户端&#xff1a; 四、小项目 客户端&#xff1a; 服务器&#xff1a; 一、基础知识复习 这部分内容前面讲的比较详细&#xff0c;现在就是简单复习一下。 两台主…

OAuth2授权机制介绍指南

目录 一、什么是OAuth2&#xff1f; 二、OAuth2中有哪些角色&#xff1f; 三、OAuth2的授权流程&#xff1f; 四、OAuth2令牌的特点&#xff1f; 五、OAuth2有哪些授权方式&#xff1f; 5.1 授权码 5.2 隐藏方式 5.3 密码方式 5.4 凭证方式 一、什么是OAuth2&#xff1f; …

PowerCLi 批量多esxi主机创建登陆用户

官网PowerCLI参数配置参考 New-VMHostAccount 创建用户参考New-VIRole 创建权限组参考Get-VIPrivilege 查询所有角色层配置信息参考创建esxi登陆用户一键脚本,目前只能单

2023年软考报哪门比较好?

2023年软考报名还有一个月左右就会启动了&#xff0c;大家有想好报考哪门吗&#xff1f;不妨看看下文&#xff0c;让你的思路更加清晰。 软考科目汇总&#xff1a; (1)高级资格&#xff1a;网络规划设计师、系统规划与管理师、系统架构设计师、信息系统项目管理师、系统分析师…

磨金石教育技能干货分享|年味摄影作品选登:你的春节怎么过的

要问年味是什么&#xff1f;味&#xff0c;是一种感觉&#xff0c;年味就是&#xff1a;除夕夜里&#xff0c;红灯笼挂满街道&#xff0c;各种年货摆满长街。各种美食充满餐桌&#xff0c;亲人团聚&#xff0c;欢笑一堂。这种让人放松、快乐的感觉就是过年特有的味道。最近由长…

MySQL(一)

性能监控 使用show profile查询剖析工具&#xff0c;可以指定具体的type type all&#xff1a;显示所有性能信息 show profile all for query n block io&#xff1a;显示块io操作的次数 show profile block io for query n context switches&#xff1a;显示上下文切换次数&a…