爬虫学习-异步爬虫

  • 目的:在爬虫中使用异步实现高性能的数据爬取操作

  • 方式

  • 多线程、多进程(不建议)

  • 好处:可以为相关阻塞的操作单独开启进程或者线程,阻塞操作就可以异步执行

  • 弊端:无法无限制的开启多线程或者多进程

  • 线程池、进程池(适当使用)

  • 好处:我们可以降低系统对进程或者线程创建和销毁的一个频率,从而更好地降低系统的开销

  • 弊端:池中线程或者进程的数量是有上限

  • 实例:下载视频

# 爬取视频的视频数据
import requests
from lxml import etree
import re
from multiprocessing.dummy import Pool

# 原则:线程池处理的是阻塞且耗时的操作
# 对下述url发起请求解析出视频详情页的url和视频的名称
if __name__ == '__main__':
    # 人物页url
    homr_url = 'https://www.pearvideo.com/category_1'
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36 Edg/108.0.1462.54'
    }
    # 获取该页的响应数据
    page_text = requests.get(url=homr_url, headers=headers).text
    # 实例化etree对象
    tree = etree.HTML(page_text)
    # 获取该页中跳转到视频页的地址
    mp4_text = tree.xpath('//*[@id="listvideoListUl"]/li/div/a/@href')
    # 同时获取对应的名称
    mp4_title = tree.xpath('//*[@id="listvideoListUl"]/li/div/a/div[2]/text()')
    # 建立空列表,后面用来芳名称和链接
    urls = []
    i = 0
    for src in mp4_text:
        # 拼接跳转到视频页的链接
        page_src = 'https://www.pearvideo.com/' + src
        # 从中取出contId
        contld = page_src.split('_')[-1]
        # page_src是referer,contld是contId,必须要有这俩才能获取到相应的视频假链接
        # print(contld)
        headers = {
            'referer': page_src,
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36 Edg/108.0.1462.54'
        }
        params = {
            'contId': contld
        }
        # 获取视频假链接
        mp4_url = 'https://www.pearvideo.com/videoStatus.jsp'
        mp4 = requests.get(url=mp4_url, headers=headers, params=params).text
        # 利用正则来找更
        ex = '"srcUrl":"(.*?)"'
        securl = re.findall(ex, mp4)[0]
        # 对链接进行分割和拼接,得到真的视频链接
        url = securl.split('-')
        new_url = 'https://video.pearvideo.com/mp4/short/20180313/cont-' + str(contld) + '-' + url[-2] + '-' + url[-1]
        # 将名称和链接以字典形式保存,并放进列表里
        dic = {
            'name': mp4_title[i],
            'url': new_url
        }
        urls.append(dic)
        i += 1
    print(urls)


# 下载视频的封装函数
def get_video_data(dic):
    url = dic['url']
    print(dic['name'] + '正在下载...')
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36 Edg/108.0.1462.54'
    }
    mp4_data = requests.get(url=url, headers=headers).content
    filename = '梨视频/' + dic['name'] + '.mp4'
    # 持久化保存
    with open(filename, 'wb') as fp:
        fp.write(mp4_data)
    print(dic['name'] + '下载成功')


# 创建进程池
pool = Pool(4)
pool.map(get_video_data, urls)
pool.close()
pool.join()
  • 单线程+异步协程(推荐)

  • event_loop: 事件循环,相当于一个无限循环,我们可以把一些函数注册到这个事件循环上当满足某些条件的时候,函数就会被循环执行。

    扫描二维码关注公众号,回复: 16665781 查看本文章
  • coroutine:协程对象,我们可以将协程对象注册到事件循环中,它会被事件循环调用。async 关键字来定义一个方法,这个方法在调用时不会立即被执行,而是返回我们可以使用个协程对象

  • task: 任务,它是对协程对象的进一步封装,包含了任务的各个状态

  • future: 代表将来执行或还没有执行的任务,实际上和 task 没有本质区别

  • async 定义一个协程

  • await 用来挂起阻塞方法的执行

  • requests.get是基于同步,必须使用基于异步的网络请求模块进行指定url的请求发送,若是用get还是6s,换成异步会变成2s

  • aiohttp:基于异步网络请求的模块

  • pip install aiohttp

  • 使用方法:变为2s

  • 协程

  • 协程不是计算机提供,是程序员人为创造

  • 协程也可以被称为微线程,是一种用户态内的上下文切换技术,简而言之,就是通过一个线程实现代码块相互切换执行

  • 协程意义

  • 在一个线程中如果遇到IO等待时间,线程不会傻傻等待,会利用空闲的时候干点其他事

猜你喜欢

转载自blog.csdn.net/qq_61897309/article/details/128552325
今日推荐