最近在学视频剪辑,从网上找了很多视频素材,也发现了一些好的素材网站,比如这个网站:www.mazwai.com,就有很多免费的高清视频素材。我有时想获取通过某个关键字搜索到的所有相关视频素材的信息,手工点击效率太低,正好最近在学Python爬虫,于是想到了用爬虫来获取视频素材信息。
比如我想搜索无人机相关的视频,我在搜索框里输入drone,出来的网址是这样的。
我们打开chrome的开发者工具,刷新网页,可以看到第一条请求的响应,其中就包括了很多视频素材的信息。
随着我们把页面往下拉,我们看到有新的视频素材被刷新出来,这让我们想到页面是通过ajax异步更新的,我们选择XHR来查看ajax请求。
首先第一条,我们分析了一下,没有我们网页上的视频信息,应该是一个外链信息,我们用不上,我们直接看后面的请求。后面每一条请求格式看起来都一样,我们拿第一个来分析一下。
我们可以看到这是一个GET类型的请求,请求的参数有两个:path和params。其中params的值又是一个字典,里面又包含了很多其他参数。我们再对比一下其他请求的参数可以发现,path参数内容完全一致,params参数中只有pge和offset_resp_videos在更新。并且pge值从1更新到4后就不再改变,而offset_resp_videos更新到106后也不再改变。
我们通过查看Elements信息,可以看到每个视频的html信息。
其中通过静态请求获取的是前30个视频,其余的是通过ajax异步请求获取。静态获取的是html格式,我们可以直接解析;通过ajax获取的响应是json格式,我们需要用json库来处理,获取其中的视频信息的html文本。
可以看到ajax的响应中,elements元素是个列表,其中的每个元素就是视频信息的html文本,与静态网页中的格式相同,所以我们需要用json库来获取ajax响应中的视频信息元素。
对于视频素材,我们比较关心的包括id,时长,分辨率,标题,预览图链接,视频链接。我们可以通过xpath来获取相关信息。
下面是相关代码:
from urllib.parse import urlencode
import requests
import json
from lxml import etree
import time
import csv
items = []
headers = {
'Host': 'mazwai.com',
'Referer': 'https://mazwai.com/stock-video-footage/drone',
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36',
'X-Requested-With': 'XMLHttpRequest',
}
# 获取静态网页
def get_first_page():
base_url = "https://mazwai.com/stock-video-footage/drone"
try:
rsp = requests.get(base_url, headers=headers)
if rsp.status_code == 200:
return rsp.text
except requests.ConnectionError as e:
print('Error:', e.args)
# 解析静态网页
def parse_html_result(result):
html = etree.HTML(result)
elements = html.xpath('//div[contains(@class, "video-responsive")]')
print(len(elements))
for element in elements:
element = etree.HTML(etree.tostring(element))
parse_html_element(element)
# 模拟ajax请求获取动态网页
def get_follow_page(page, start_idx):
base_url = "https://mazwai.com/api/?"
params = '{' + '"pge":{},"recordsPerPage":30,"recordsPerPage":30,"rec":30,"json_return":true,"infinite_scroll": true,"offset_resp_videos":{},"category": "drone"'.format(page, start_idx + (page-1)*30) + '}'
total = {
'path': 'elasticsearch/listResults',
'params': params
}
url = base_url + urlencode(total)
print(url)
try:
rsp = requests.get(url, headers=headers)
if rsp.status_code == 200:
return rsp.text
except requests.ConnectionError as e:
print('Error:', e.args)
# 解析ajax响应
def parse_json_result(result):
rsp = json.loads(result)
for element in rsp['elements']:
element = etree.HTML(element)
parse_html_element(element)
# 解析包含视频信息的单个元素
def parse_html_element(element):
item = []
id = element.xpath('//div[contains(@class, "video-responsive")]/@id')
imgsrc = element.xpath('//img/@src')
videosrc = element.xpath('//img/@data-video-source')
title = element.xpath('//img/@title')
duration = element.xpath('//div[@class="video-resolution-length-info"]/span[@class="duration"]/text()')
resolution = element.xpath('//div[@class="video-resolution-length-info"]/span[@class="resolution"]/text()')
item.append(id[0])
item.append(title[0])
item.append(duration[0])
item.append(resolution[0])
item.append(imgsrc[0])
item.append(videosrc[0])
items.append(item)
def write_csv():
with open('data.csv', 'w') as csvfile:
writer = csv.writer(csvfile)
writer.writerow(['id', 'title', 'duration', 'resolution', 'img_url', 'video_url'])
writer.writerows(items)
# 主函数
def main():
# 获取第一页并解析
result = get_first_page()
if result is not None:
parse_html_result(result)
time.sleep(2)
# 获取后续页并解析
for page in range(1, 4):
result = get_follow_page(page, 37)
parse_json_result(result)
time.sleep(2)
# 存成csv文件
write_csv()
if __name__ == '__main__':
main()
执行结果:
最终把提取到的信息存成csv文件,后续也可以通过链接自动下载图片和视频文件进行保存。
我们可以通过修改程序支持输入关键字信息爬取其他的搜索信息,并且通过总条数自动计算需要爬取多少页,这里不再赘述。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。