Python爬虫:使用线程池快速下载视频

旁白:上一篇利用python爬取了虎牙星秀的图片,这一篇利用线程池对视频进行爬取。


前言

问题:爬虫每次只能request一个url?那也太慢了吧!
解决方案:利用线程池,加快爬虫效率,节省电脑消耗。


提示:以下是本篇文章正文内容,下面案例可供参考

一、为什么要使用线程池?

系统启动一个新线程的成本是比较高的,因为它涉及与操作系统的交互。在这种情形下,使用线程池可以很好地提升性能,尤其是当程序中需要创建大量生存期很短暂的线程时,更应该考虑使用线程池。

线程池在系统启动时即创建大量空闲的线程,程序只要将一个函数提交给线程池,线程池就会启动一个空闲的线程来执行它。当该函数执行结束后,该线程并不会死亡,而是再次返回到线程池中变成空闲状态,等待执行下一个函数。

此外,使用线程池可以有效地控制系统中并发线程的数量。当系统中包含有大量的并发线程时,会导致系统性能急剧下降,甚至导致 Python 解释器崩溃,而线程池的最大线程数参数可以控制系统中并发线程的数量不超过此数。

二、使用步骤

1.引入模块

代码如下:

import requests
from lxml import etree
import re
import os
from multiprocessing.dummy import Pool

2.创建文件夹

代码如下:

if not os.path.exists('./li_video'):
     os.mkdir('./li_video')

3.存储文件

代码如下:

with open('./li_video/' + dic['video_name'], 'wb') as fp:
    fp.write(video_data)
    print(dic['video_name'], '下载完成!')

4.完整代码

代码如下:

# -*- coding: utf-8 -*-
# @Date: 2020/8/14 12:29
# @Author: Ricky Rau

import requests
from lxml import etree
import re
import os
from multiprocessing.dummy import Pool

def main():
    if not os.path.exists('./li_video'):
        os.mkdir('./li_video')     #先创建一个文件夹,用于存储视频
    url = 'https://www.pearvideo.com/category_59'
    headers = {
        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'
    }
    dic_list = getDic(url, headers)
    pool = Pool(4)
    pool.map(get_video_data, dic_list)   #使用线程池对视频数据进行请求(主要用于处理较为耗时的阻塞操作)
    pool.close()   #关闭进程池,不再接受新的进程
    pool.join()    #主进程阻塞等待子进程的退出

def getDic(url, headers):
    page_text = requests.get(url=url,headers=headers).text
    tree = etree.HTML(page_text)
    li_list = tree.xpath('//*[@id="listvideoListUl"]/li')
    video_data_list = []   #用来储存视频名称与链接
    for li in li_list:
        video_name = li.xpath('./div/a/div[2]/text()')[0] + '.mp4'
        detail_url = 'https://www.pearvideo.com/' + li.xpath('./div/a/@href')[0]
        detail_text = requests.get(url=detail_url, headers=headers).text
        #此处解析到的源代码(可通过开发者工具中的network进行查看),与一般的网页源代码有所差异,只能使用正则表达式进行匹配
        ex = 'srcUrl="(.*?)",vdoUrl=srcUrl'
        video_url = re.findall(ex, detail_text)[0]
        dic = {
            'video_name': video_name,
            'video_url': video_url
        }
        video_data_list.append(dic)
    return video_data_list

def get_video_data(dic):
    url = dic['video_url']
    headers = {
        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'
    }
    #对视频链接发起请求,获取视频的二进制数据
    video_data = requests.get(url=url, headers=headers).content
    #持久化存储操作
    with open('./li_video/' + dic['video_name'], 'wb') as fp:
        fp.write(video_data)
        print(dic['video_name'], '下载完成!')

if __name__ == '__main__':
    main()

三、运行结果

在这里插入图片描述


总结

本文主要利用multiprocessing模块中的Pool方法,对程序进行多线程控制,同步进行多条url的访问与数据爬取,示例中是对梨视频中的<音乐栏目>进行爬取,通过运行代码,可以发现节省了大部分时间。但是,线程池的缺点在于,不能无限次的爬取,需要设定数值。

//只要在变好,慢一点也没关系//

猜你喜欢

转载自blog.csdn.net/weixin_43037350/article/details/108005735