python协程gevent案例 爬取斗鱼图片过程解析

yizhihongxing

下面是关于“python协程gevent案例 爬取斗鱼图片过程解析”的完整攻略。

1. 什么是协程

协程是一种轻量级线程,Python的协程是基于生成器的协程。协程与线程的区别在于,线程是抢占式多任务,需要操作系统进行上下文切换,而协程是非抢占式多任务,通过协程程序员来控制何时上下文切换。

Python的协程一般使用yield关键字来实现,使用yield来挂起一个协程,使用next()函数继续一个挂起的协程。

2. 什么是gevent

gevent是一个基于协程的Python网络库,gevent封装了Python标准库中的socket库和subprocess库,使得在使用socket和subprocess时可以简化代码,避免出现多线程和多进程。

gevent使用Greenlet来实现协程,Greenlet是一个协程库,基于C实现。gevent使用Greenlet来实现协程,避免使用Python标准库的yield关键字,因此代码更加容易理解。

3. 爬取斗鱼图片过程解析

爬取斗鱼图片的过程可以分为以下几步:

  1. 获取斗鱼直播网站的页面。
  2. 解析页面,获取直播间地址。
  3. 进入直播间,获取直播间里的图片。
  4. 下载图片。

这个任务需要使用协程来完成,因为我们需要同时进行页面请求和图片下载,而这两个操作可能会有相互等待的状况。

下面是具体实现的代码:

import os
import gevent
import requests
from lxml import etree
from gevent import monkey

# 打补丁,让gevent能够在代码中发挥作用
monkey.patch_all()


def get_page(url):
    """
    获取斗鱼房间列表页面
    """
    try:
        headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 Edge/16.16299'
        }
        response = requests.get(url, timeout=10, headers=headers)
        if response.status_code == 200:
            return response.text
    except Exception as e:
        print('failed to load page: %s' % url)
        return None


def parse_page(page_source):
    """
    解析页面,获取直播间地址
    """
    try:
        html_obj = etree.HTML(page_source)
        room_list = html_obj.xpath('//div[@class="ListContent"]/ul[@class="clearfix"]/li')
        room_list = list(filter(lambda x: x.xpath('descendant::a[contains(@class, "Title")]'), room_list))

        room_urls = [room.xpath('descendant::a[contains(@class, "Title")]/@href')[0] for room in room_list]
        print('found %s room urls' % len(room_urls))
        return room_urls
    except Exception as e:
        print('failed to parse page')
        return []


def download_image(image_url, image_path):
    """
    下载图片
    """
    try:
        response = requests.get(image_url, timeout=10)
        if response.status_code == 200:
            with open(image_path, 'wb') as f:
                f.write(response.content)
                print('downloaded image: %s' % image_path)
    except Exception as e:
        print('failed to download image: %s' % image_url)


def download_room_images(room_url, img_dir):
    """
    下载一个直播间内的所有图片
    """
    try:
        headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 Edge/16.16299'
        }
        response = requests.get(room_url, timeout=10, headers=headers)
        if response.status_code == 200:
            html_obj = etree.HTML(response.text)
            images = html_obj.xpath('//div[@class="layout-Module-container"]/div/div[@class="swiper-wrapper"]/div[@class="swiper-slide"]/a/div/img/@data-original')
            for image in images:
                image_path = os.path.join(img_dir, image.split('/')[-1])
                gevent.spawn(download_image, image, image_path)
    except Exception as e:
        print('failed to download images in room %s' % room_url)


def download_images(base_url):
    """
    下载每个直播间内的图片
    """
    page_source = get_page(base_url)
    if page_source:
        room_urls = parse_page(page_source)
        if room_urls:
            img_dir = os.path.join(os.getcwd(), 'images')
            os.makedirs(img_dir, exist_ok=True)
            for room_url in room_urls:
                gevent.spawn(download_room_images, room_url, img_dir)

# 测试下载斗鱼直播的图片
if __name__ == "__main__":
    download_images('https://www.douyu.com/g_qqcp')  # 以QQ飞车直播房间为例
    gevent.joinall()

这个代码会下载斗鱼直播网站下面的QQ飞车直播房间的图片。在代码中,我们使用了gevent来实现协程,使用Greenlet来挂起和恢复协程的执行,从而实现了异步爬取和下载。
我们通过gevent.spawn和gevent.joinall来创建和管理多个协程,多个协程可以在想象象的资源(例如CPU,网络IO)中自由切换,因此可以大大提高爬取效率。

4. 示例说明

在上述代码中,有两个例子可以展现协程和gevent的用法:

例子一

def download_image(image_url, image_path):
    """
    下载图片
    """
    try:
        response = requests.get(image_url, timeout=10)
        if response.status_code == 200:
            with open(image_path, 'wb') as f:
                f.write(response.content)
                print('downloaded image: %s' % image_path)
    except Exception as e:
        print('failed to download image: %s' % image_url)

这个函数下载单张图片。我们通过gevent.spawn来创建一个协程来下载这张图片,调用这个函数的线程不会被阻塞,可以立即返回,而协程会在下载完成之后自动恢复执行。

例子二

for room_url in room_urls:
    gevent.spawn(download_room_images, room_url, img_dir)

这段代码会下载每个直播间内的图片,我们使用gevent.spawn来创建从位置下载每个直播间的协程,这样当我们使用gevent.joinall()来等待所有协程执行完成时,这些协程会被异步执行,从而大大提高爬虫的效率。

这就是一个完整的“python协程gevent案例 爬取斗鱼图片过程解析”的攻略。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:python协程gevent案例 爬取斗鱼图片过程解析 - Python技术站

(0)
上一篇 2023年6月3日
下一篇 2023年6月3日

相关文章

  • Python 高阶函数获取命名属性

    Python 高阶函数是指能够接收函数作为参数、并/或者返回函数的函数。这类函数在函数式编程中十分常见,能够提高代码的可重用性和简洁性。本篇攻略将详细讲解如何使用 Python 高阶函数获取命名属性。 获取命名属性 获取命名属性是指从一个对象中获取其属性的过程。在 Python 中可以通过 . 运算符或 getattr() 函数两种方式获取对象的命名属性。例…

    python-answer 2023年3月25日
    00
  • python中的字典详细介绍

    下面我来详细讲解“Python中的字典详细介绍”完整攻略。 一、什么是字典 在Python中,字典是一种“键-值”(key-value)的数据结构,其中键(key)是唯一的,对应一个值(value)。字典是无序的,即字典中的元素是没有固定顺序的。 字典的创建方式有两种: 1. 字面量创建 使用大括号{}可以创建一个空字典,使用冒号:分隔键和值,逗号,分隔不同…

    python 2023年5月13日
    00
  • 爬山算法简介和Python实现实例

    爬山算法简介和Python实现实例 爬山算法简介 爬山算法(Hill Climbing Algorithm)是一种简单且常用的启发式优化算法。该算法的基本思想是从当前解出发,每次搜索邻域中比当前解更优的解,直到达到一个局部最优解。 但是,爬山算法容易陷入局部最优解,并且不能保证找到全局最优解。因此,在实际应用中常常会利用多次随机化生成多个初始解,或者使用其他…

    python 2023年5月19日
    00
  • Python内置异常类型全面汇总

    以下是关于Python内置异常类型全面汇总的完整攻略: 问题描述 在Python中,有许多内置的异常类型,用于处理不同类型的错误或异常情况。了解这些异常类型可以帮助我们更好地处理程序中的错误和异常情况。 解决方法 可以使用以下步骤了解Python内置异常类型: 查看Python官方文档。 Python官方文档中包含了所有内置异常类型的详细说明和用法。可以查看…

    python 2023年5月13日
    00
  • Python脚本传参数argparse模块的使用

    下面是 Python 脚本传参数 argparse 模块的使用攻略。 什么是 argparse 模块 argparse 是 Python 标准库中的一个命令行解析工具,可以帮助开发者构建用户友好的命令行程序,包括定义可选参数、必选参数、默认值、参数类型、帮助信息等。argparse 模块可以帮助你管理命令行中的参数和选项。 安装 argparse 模块 ar…

    python 2023年6月3日
    00
  • python线程池 ThreadPoolExecutor 的用法示例

    下面是关于 Python 的线程池 ThreadPoolExecutor 的用法示例攻略。 什么是 ThreadPoolExecutor ThreadPoolExecutor 是 Python 库里的一个线程池库,用于管理和调度线程。通过使用线程池,可以简化线程的创建、维护和销毁等操作,提高线程的利用率和效率。 ThreadPoolExecutor 的基础用…

    python 2023年5月19日
    00
  • Python基础之函数原理与应用实例详解

    Python基础之函数原理与应用实例详解 1. 什么是函数? 函数是一个可重复使用的代码块,它接受一些输入参数,并根据这些参数进行操作,最后返回输出结果。 函数可以帮助我们把一个大问题分成若干个小问题,从而提高代码的复用性和可读性。 在Python中,我们可以使用def关键字来定义函数,如下所示: def function_name(parameters):…

    python 2023年5月19日
    00
  • Python 实操显示数据图表并固定时间长度

    下面是关于“Python 实操显示数据图表并固定时间长度”的完整攻略。 1. 确定所需工具与环境 Python编程语言:需要先安装Python编程语言 数据可视化工具:常用的数据可视化工具有Matplotlib、Seaborn等,我们在本文中将使用Matplotlib 数据集:选定需要绘制图表的数据集,可以使用自己收集的数据或者从网上获取 安装Matplot…

    python 2023年6月2日
    00
合作推广
合作推广
分享本页
返回顶部