前言

搞社会实践(da gong)的地方是做网站的,公司把视频放到了*拍短视频的服务器上,通过在自有的页面中引用链接来给别人看。然而,在前几天,*拍把公司的视频引用链接给ban了,客户无法在浏览器上看网页中的视频,但是单独通过视频链接还是可以看的。为了客户能正常观看视频,公司决定将视频手动下载,转移到自有的服务器上。

python批量下载网页pdf文件 python批量下载网页视频_ide

我说停停,能不能给我二十几首歌的时间,我来整一个自动下载。

技术路线:python3.8; requests, re.

import requests
import re

效果图:

python批量下载网页pdf文件 python批量下载网页视频_字符串_02

实现方案

大概要做这么一些事:
获取文章页面,分析文章页面的源代码,从源代码中找出视频链接,通过视频链接下载视频,循环以上过程。

1、获取文章源代码

python批量下载网页pdf文件 python批量下载网页视频_错误信息_03

通过观察文章列表,发现每个文章有个唯一的id,那就是说,有可能可以通过id来获取文章链接,从而下载文章源代码。
公司在公网上的url:

https://域名/yushi/manao/10000.html
https://域名/shuijing/caomeijing/10086.html

文章链接中确实有文章的id。然而,文章是分类生成的,被系统放到了不同的目录中,这给单独使用id获取页面源代码设置了障碍。

一上来找不到链接,卡在了第一步属实难受,二十几首歌的时间有限,我慌张地后台胡乱翻找翻找,直到发现了这个:

python批量下载网页pdf文件 python批量下载网页视频_错误信息_04

 内部预览链接

https://域名/管理系统/plus/view.php?aid=10000
https://域名/管理系统/plus/view.php?aid=10086

这个链接就很整齐美观,非常适合爬虫的胃口。这样可以确定文章链接了,获取文章页面及其源代码了:

url = f'https://域名/管理系统/plus/view.php?aid={id}'

2、获取文章页面

人在江湖飘,不得不给自己套上一层伪装,网上冲浪也是。让机器人去做事总有点不放心,需要让它装成一个用浏览器的人。
设置全局User Agent :

userAgent = {
    'User-Agent':
    'Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:91.0) \
Gecko/20100101 Firefox/91.0'
}

创建一个获取页面文本内容的函数,获取并返回url链接的网页文本的内容,并输出正在获取的url对应的文章id,如遇错误,返回空字符串,输出错误信息。

def getPage(url , id):
    print(f"Geting '{id}'.")
    try:
        response = requests.get(url, headers= userAgent)
        response.encoding = 'utf-8'
        response = response.text
        return response
    except:
        print(f"'{id}' get error!")
        return ''

@url: 字符串,待爬取的网页链接
@id: 字符串,所爬取的文章id

3、分析源码获取视频链接

我html不怎么会,标签辣么多我也没时间看。既然是找视频那就直接冲mp4吧,一搜索还真有两个,比对了一下两个是一样的。

python批量下载网页pdf文件 python批量下载网页视频_python批量下载网页pdf文件_05


正则表达式直接匹配不用分析了

r'http.+?mp4'

http开头,mp4结尾,中间要有东西,如果匹配到了多个,取最短的。
创建一个获取视频链接的函数,从text文本内容中获取并返回视频链接,如遇错误,返回空字符串,输出错误信息。

def getUrl(id, text):
    try:
        pat = re.compile(r'http.+?mp4')
        url = re.findall(pat, text)
        url = url[0]
        return url
    except:
        print(f"'{id}' re match error!")
        return ''

@id: 字符串,所爬取的文章id
@text: 字符串,用于查找视频链接的网页源码

4、下载和保存视频

视频和一般网页内容不一样,是个二进制文件。区别于页面源代码的text属性,在从服务器响应中获取时,requests库中,需要用到Response类的content属性。在保存文件时,也不能单独使用‘w'写入模式,需要使用’wb'这个二进制写入模式。
创建一个下载和保存视频的函数,将在url链接的视频以'name.mp4'的名字保存在videos文件夹,如遇错误,记录错误后输出错误信息。
 

def saveVideo(url, name):
    try:
        response = requests.get(url, stream= 1, headers= userAgent)
        response = response.content # 二进制访问视频
        file = open(f'./videos/{name}.mp4', 'wb') # 二进制文件模式
        file.write(response)
        file.close()
    except:
        errorIDs.append(name)
        print(f"{name} save video error!")

@url: 字符串,视频链接
@name:字符串,视频的名称

5、完善逻辑

剩下完善整个程序的逻辑,把函数放在一起就好了。

file = open('ids.txt', 'r', encoding= 'utf-8')
ids = file.readlines()
file.close()

将要下载的文章id放在一个文件里,通过文件的方式输入,更稳健。遍历所有文章id,逐个下载。

for id in ids:
    id = id.strip()
    url = f'https://域名/管理系统/plus/view.php?aid={id}'
    webPage = getPage(url , id)
    videoUrl = getUrl(id, webPage)
    saveVideo(videoUrl, id)
    print(f'{id} completed!')
print("Finish!")

展示运行的结果,并保持结果持续显示:

if len(errorIDs) != 0:
    print("error IDs:")
    for id in errorIDs:
        print(id, end=' ')
    print('\n')
else : 
    print('No error.')

Ispause = 1
while 1 :
    Ispause = input()
    if Ispause == 'exit' : 
        break

完整代码,3kB不到,自动爬~

python批量下载网页pdf文件 python批量下载网页视频_python批量下载网页pdf文件_06

import requests
import re

userAgent = {
    'User-Agent':
    'Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:91.0) Gecko/20100101 Firefox/91.0'
}
errorIDs = []

def getPage(url , id):
    '''
    获取并返回url链接的网页文本的内容,
    并输出正在获取的url对应的文章id,
    如遇错误,返回空字符串,输出错误信息。
    @url: 字符串,待爬取的网页链接
    @id: 字符串,所爬取的文章id
    ''' 
    print(f"Geting '{id}'.")
    try:
        response = requests.get(url, headers= userAgent)
        response.encoding = 'utf-8'
        response = response.text
        return response
    except:
        print(f"'{id}' get error!")
        return ''

def getUrl(id, text):
    '''
    从text文本内容中获取并返回视频链接,
    如遇错误,返回空字符串,输出错误信息。
    @id: 字符串,所爬取的文章id
    @text: 字符串,匹配视频链接的网页内容
    '''
    try:
        pat = re.compile(r'http.+?mp4')
        url = re.findall(pat, text)
        url = url[0]
        return url
    except:
        print(f"'{id}' re match error!")
        return ''

def saveVideo(url, name):
    '''
    将在url的视频以'name.mp4'的名字保存在videos文件夹,
    如遇错误,记录错误后输出错误信息。
    @url: 字符串,视频链接
    @name:字符串,视频的名称
    '''
    try:
        response = requests.get(url, stream= 1, headers= userAgent)
        response = response.content
        file = open(f'./videos/{name}.mp4', 'wb')
        file.write(response)
        file.close()
    except:
        errorIDs.append(name)
        print(f"{name} save video error!")


if __name__=='__main__':
    # 读取需要获取视频的文章id
    file = open('ids.txt', 'r', encoding= 'utf-8')
    ids = file.readlines()
    file.close()

    # 获取视频
    for id in ids:
        id = id.strip()
        url = f'https://域名/管理系统/plus/view.php?aid={id}'
        webPage = getPage(url , id)
        videoUrl = getUrl(id, webPage)
        saveVideo(videoUrl, id)
        print(f'{id} completed!')
    print("Finish!")

    # 展示运行结果
    if len(errorIDs) != 0:
        print("error IDs:")
        for id in errorIDs:
            print(id, end=' ')
        print('\n')
    else : 
        print('No error.')

    # 保持运行结果持续显示
    Ispause = 0
    while 1 :
        Ispause = input()
        if Ispause == 'exit' : 
            break

反思

真正运用到工作中的时候,此程序并不高效。对于没有参与编写的人员,这个小程序不太友好,使用需要建文件夹、创建文件手动输入id,过于麻烦。以至于公司把我作为一个下载器,我一个人处理下载,其他人负责转移,虽提高了一定效率,但仍不是最优解。

需要改进的地方:

1、不能多个下载任务并行处理;
2、不能灵活调整下载位置;
3、没有友好易上手的用户图形界面;
4、不能自动获取文章id;
5、下载失败不会自动重试;
6、没有进度条。

可以尝试一下:

1、不使用正则表达式,使用bs库解析html;
2、使用成熟的scrapy等爬虫框架再开发。