【Python爬虫】批量下载短视频APP网页端的视频和图集
通过selenium和request实现作者视频的批量下载。更新于2023.12.13.
可能会随着时间的代码失效,需要更新请求头和response中url、标题等信息的获取位置。
【请求头中两个参数获取方法】:
打开某条视频->F12->点击media->刷新网页->找到视频元素并点击->复制其中一段文字->
点击搜索->输入搜索信息(这里可以复制元素的URL到浏览器,查看是否能够打开MP4链接)->
在header标头中找到response响应标头->获取其中的cookie和user-agent


【获取标题,时间,作者和视频信息的方法】:
print(response.text)在其中搜索相应信息的位置
然后定位,用(.*?)标识。
【获取视频下载链接url方法】:
将视频信息video_info转码后,用pprint标准化格式输出,寻找其中不同清晰度视频位置,用键值对取值方法定位video_url,之后便可以下载。
【关于脚本运行】先登录后在页面等待刷新出作者所有视频(这一步主要是selenium的爬取,也可以自己手动下拉),之后就是request的工作,因为所有的视频id都已经存到列表里,下一次运行可以将selenium部分省略掉,直接从request部分开始运行。
【关于失败重试】有时候因为网络原因会有几个视频下载失败,会存入失败列表,重新运行程序,把失败列表读进去重新下载就好。
上代码:
(特别加入了一个时间修正模块,将下载视频的时间修正为发布视频的时间)
# 同时下载视频或图集(主页版,没有发布时间信息)
import os
import winsound
from selenium import webdriver
from selenium.webdriver.common.by import By
import re
from requests import utils
import requests
import json
from datetime import datetime
from pprint import pprint
# 采集作者所有作品的ID的函数
def Get_IDs(her_web):
# 访问网站
wb = webdriver.Edge()
# 输入网址
wb.get(her_web)
print('验证')
input()
lis = wb.find_elements(By.CSS_SELECTOR, '.Eie04v01')
print('共采集到', len(lis), '条作品')
IDs_Video = []
IDs_Photo = []
for li in lis:
ID = li.find_element(By.CSS_SELECTOR, 'a').get_attribute('href')
if "note" in ID:
ID = ID.replace('https://www.XXXXXX.com/note/', '')
IDs_Photo.append(ID)
elif "video" in ID:
ID = ID.replace('https://www.XXXXXX.com/video/', '')
IDs_Video.append(ID)
else:
print('出现未定义格式!')
print(len(IDs_Video), '条视频', '\n ', IDs_Video)
# URLs_Video.reverse()
print(len(IDs_Photo), '条图集', '\n ', IDs_Photo)
return IDs_Video, IDs_Photo
# 通过ID获取响应的函数
def request_header(Uid, ID):
# 请求url
url = 'https://www.XXXXXX.com/user/' + Uid + '?modal_id=' + ID
print(url)
# 加上一个请求头,伪装成浏览器
headers = {
# cookie:用户信息,登录或不登录都有
'cookie': '',#登录后输入自己的cookie
# user-agent:浏览器信息,版本,电脑
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36 Edg/117.0.2045.36'
}
response = requests.get(url, headers=headers)
return response, headers
# 保存数据的函数
def Download_DY(video_name, video_url, headers): # 保存数据
# 获取视频的二进制内容
video_content = requests.get(url=video_url, headers=headers).content
with open(video_name, mode='wb') as f:
f.write(video_content)
print('下载成功!')
# 替换掉不能命名的字符
def replace_x(words):
words = words.replace('/', '')
words = words.replace(':', '')
words = words.replace('*', '')
words = words.replace('?', '')
words = words.replace('〈', '')
words = words.replace('〉', '')
words = words.replace('|', '')
# words = words.replace('"', '')
# words = words.replace('...', '')
return words
# 修改时间的函数
def modify_time(video_name, release_time):
release_time = release_time.replace(' ', 'T')
a = datetime.strptime(release_time, '%Y-%m-%dT%H:%M')
a.timestamp()
os.utime(video_name, (a.timestamp(), a.timestamp())) # 只能修改 访问时间 与 修改时间(不能修改创建时间)
# 发出提示音
def Sound_beep():
duration = 1000 # millisecond
freq = 440 # Hz
winsound.Beep(freq, duration)
# 主函数
# 文件保存位置
file_path = 'D:\\下载站\\DY下载\\'
# 作者主页
while True:
print('请输入作者主页')
her_web = input()
if her_web == '0':
break
Uid = 'MS4wLjABAAAA5ExKqjgHzZ3DaRhImU9EvklLe_9QPeTp0uIuf1kV2h4'
# 采集作者所有作品的URL
try:
(IDs_Video, IDs_Photo) = Get_IDs(her_web)
except:
print('获取主页失败,请重试。。。')
continue
# IDs_Video.reverse()
IDs_Photo_Failed = [] # 用于保存失败的URL
IDs_Video_Failed = [] # 用于保存失败的URL
# 先获取所有图集
for ID_Photo in IDs_Photo:
try:
# 将作品ID对应的URL请求响应输出(请求头写在函数里)
(response, headers) = request_header(Uid, ID_Photo)
# 视频信息
video_info = re.findall('<script id="RENDER_DATA" type="application/json">(.*?)</script', response.text)[0]
# 作者姓名
try:
name = re.findall('<span class="Nu66P_ba"><span><span><span><span>(.*?)</span>', response.text)[0]
except:
name = ''
# 作品文案
try:
title = re.findall('video_title" content="(.*?)"/>', response.text)[0]
except:
title = ''
title = replace_x(title)
print(title)
if not title == '':
title = '-' + title
video_name = file_path + ID_Photo + title
# 转码
html_data = requests.utils.unquote(video_info)
# 转换数据类型
json_data = json.loads(html_data)
# pprint(json_data)
# 提取视频连接 键值对取值--通过冒号左边的内容,提取冒号右边的内容
# (这一段还没改)video_url = json_data['app']['videoDetail']['images'][0]['urlList']
photo_number = int(len(json_data['app']['videoDetail']['images']))
print('共', photo_number, '张图')
for i in range(1, photo_number + 1):
photo_urls = json_data['app']['videoDetail']['images'][i - 1]['urlList'][3]
# print(photo_urls)
# 创建文件夹(并且判别文件夹是否存在)
is_exists = os.path.exists(video_name) # path是文件夹或者文件的相对路径或者绝对路径
if is_exists:
# print('文件夹已存在')
j = 1
else:
# print('文件夹不存在,已创建')
os.mkdir(video_name)
photo_name_i = video_name + '\\' + str(i) + '.jpg'
# 保存数据
# 获取视频的二进制内容
video_content = requests.get(url=photo_urls, headers=headers).content
with open(photo_name_i, mode='wb') as f:
f.write(video_content)
print('第', i, '张图片下载成功!')
# 更正时间
# modify_time(video_name, release_time)
except:
IDs_Photo_Failed.append(ID_Photo)
print('出现错误,可能导致下载失败!')
# 再获取所有视频
for ID_Video in IDs_Video:
# 将作品ID对应的URL请求响应输出(请求头写在函数里)
(response, headers) = request_header(Uid, ID_Video)
# 视频信息
try:
video_info = re.findall('<script id="RENDER_DATA" type="application/json">(.*?)</script', response.text)[0]
# 作者姓名
try:
name = re.findall('<span class="Nu66P_ba"><span><span><span><span>(.*?)</span>', response.text)[0]
except:
name = ''
# 作品文案
try:
title = re.findall('video_title" content="(.*?)"/>', response.text)[0]
except:
title = ''
title = replace_x(title)
print(title)
if not title == '':
title = '-' + title
video_name = file_path + ID_Video + title + '.mp4'
# 转码
html_data = requests.utils.unquote(video_info)
# 转换数据类型
json_data = json.loads(html_data)
# print(type(html_data))
# print(type(json_data))
# pprint(json_data)
# 提取视频连接 键值对取值--通过冒号左边的内容,提取冒号右边的内容
video_url = 'https:' + json_data['app']['videoDetail']['video']['bitRateList'][0]['playApi']
print(video_url)
# 下载视频
Download_DY(video_name, video_url, headers)
# 更正时间
# modify_time(video_name, release_time)
except:
IDs_Video_Failed.append(ID_Video)
print('出现错误,可能导致下载失败!')
print('视频失败列表:', '\n', IDs_Video_Failed)
print('图集失败列表:', '\n', IDs_Photo_Failed)
Sound_beep()
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐


所有评论(0)