Python爬虫如何加速?异步、协程还是多进程?分享一个常用做法,萌新也能看懂

简介: 天下代码,唯快不破

最近在知识星球:Python读者圈,遇到读者提问:Python爬虫如何加速?

这个问题涉及到一个爬虫里,甚至是整个Python编程里都非常重要的问题:

如果同时下载1w张图片,如何有效地加速程序运行,缩短下载时间?

今天我们一起来看一下常用的解决方案。

1、为什么慢?

首先我们先看一下,原来的代码里,是什么原因导致程序慢的?
下面是代码和运行结果:

import office

for i in range(1, 18):
    url = 'https://www.python-office.com/api/img-cdn/test/spider/{}.jpg'.format(str(i))
    office.image.down4img(url, output_name=str(i))

顺序执行看起来很完美,但是完美的背后是不是有陷阱呢?

为了更好的理解这个代码,我们先举一个例子:你面前有10台洗衣机编号是从1到10,里面转满了衣服需要你清洗,有的脏可能要强力洗洗的久,有的干净只需要速洗洗的快。

清洗以后,需要你记录下他们的清理顺序,有下列2种方案供你选择:

  1. 一个挨一个的洗完。先启动洗衣机1号,等1号洗完了,再启动2号,依次类推。这样你记录的结果和上图一样,是完美的按顺序完成。
  2. 先同时打开所有的洗衣机,哪一个洗完了就记录哪一个。因为有的洗得快,有的洗得慢,这样你记录的结果是混乱的。

哪种方式最快呢?毫无疑问是第2种,因为可以让所有的洗衣机同时工作,时间资源可以复用。

回到我们的程序,我们下载一张图片也是分为2步:请求图片资源,保存到本地。

上面的代码之所以慢,就是因为它是请求到第1张的资源,保存到本地之后,再去请求第2张的资源。看起来很完美,但其实问题很大。

如何加快速度呢?我们如果可以先请求到所有的图片资源(打开所有的洗衣机),然后再统一保存图片(哪台洗完衣服,就先记录哪台),这样是不是就会快很多呢?

下面我们按照第2种思路,在Python里的实现实现一下。

2、解决代码

Talk is cheap,show me the code.
先上代码和运行结果。

import asyncio
from aiohttp import ClientSession

tasks = []
url = "https://www.python-office.com/api/img-cdn/test/spider/{}.jpg"

async def hello(url, i='wanfeng', type='jpg'):
    async with ClientSession() as session:
        async with session.get(url) as response:
            if response.status==200:
                response = await response.read()
                # print(response)
                async with aiofiles.open('.'.join((str(i), type)), 'wb') as output_img:
                    # for chunk in response:
                    await output_img.write(response)
                    output_img.close()
                print(f"下载成功,图片名称:{'.'.join((str(i), type))}")


def run():
    for i in range(1, 18):
        task = asyncio.ensure_future(hello(url.format(i), i))
        tasks.append(task)

def main():
    loop = asyncio.get_event_loop()
    run()
    loop.run_until_complete(asyncio.wait(tasks))

if __name__ == '__main__':
    main()


主要使用的库是:

  • asyncio:协程,让图片下载不按顺序,可以加快速度
  • aiohttp:替代requests,用来异步发送请求。
  • aiofiles:异步写入文件内容

3、还有其它方法吗?

还有多进程也可以试试,但是多进程更大的优势体现在计算密集型的场景下。
爬虫获取网络请求属于I/O密集型操作,多进程的优势不大。

# -*- coding:utf-8 -*-
import multiprocessing
import os, time
from multiprocessing import Pool

import requests

url = "https://www.python-office.com/api/img-cdn/test/spider/{}.jpg"

def down4img(url, output_name, type):
    """
    下载指定url的一张图片,支持所有格式:jpg\png\gif .etc
    """
    # print("子进程开始执行>>> pid={},ppid={},编号{}".format(os.getpid(), os.getppid(), output_name))

    response = requests.get(url, stream=True)
    with open('.'.join((output_name, type)), 'wb') as output_img:
        for chunk in response:
            output_img.write(chunk)
        output_img.close()
        print(f"下载成功,图片名称:{'.'.join((output_name, type))}")
    # print("子进程终止>>> pid={},ppid={},编号{}".format(os.getpid(), os.getppid(), output_name))



def main():
    print("主进程开始执行>>> pid={}".format(os.getpid()))
    ps = Pool(multiprocessing.cpu_count())
    ps = Pool(3)
    for i in range(1, 18):
        # ps.apply(worker,args=(i,))          # 同步执行
        output_name = str(i)
        type = 'jpg'
        ps.apply_async(down4img, args=(url.format(str(i)), output_name, type,))  # 异步执行
        # ps.apply(down4img, args=(url.format(str(i)), output_name[0], type,))  # 同步执行

    # 关闭进程池,停止接受其它进程
    ps.close()
    # 阻塞进程
    ps.join()
    print("主进程终止")


if __name__ == '__main__':
    main()

主要使用的库是:

  • multiprocessing:创建进程池

4、写在最后

希望能给你带来帮助。如果想系统的学习Python,欢迎大家扫码加入我的知识星球👉Python读者圈,我们一起学习提高~

相关文章
|
8天前
|
数据采集 测试技术 C++
无headers爬虫 vs 带headers爬虫:Python性能对比
无headers爬虫 vs 带headers爬虫:Python性能对比
|
5月前
|
数据采集 存储 JSON
Python网络爬虫:Scrapy框架的实战应用与技巧分享
【10月更文挑战第27天】本文介绍了Python网络爬虫Scrapy框架的实战应用与技巧。首先讲解了如何创建Scrapy项目、定义爬虫、处理JSON响应、设置User-Agent和代理,以及存储爬取的数据。通过具体示例,帮助读者掌握Scrapy的核心功能和使用方法,提升数据采集效率。
269 6
|
13天前
|
数据采集 存储 监控
Python 原生爬虫教程:网络爬虫的基本概念和认知
网络爬虫是一种自动抓取互联网信息的程序,广泛应用于搜索引擎、数据采集、新闻聚合和价格监控等领域。其工作流程包括 URL 调度、HTTP 请求、页面下载、解析、数据存储及新 URL 发现。Python 因其丰富的库(如 requests、BeautifulSoup、Scrapy)和简洁语法成为爬虫开发的首选语言。然而,在使用爬虫时需注意法律与道德问题,例如遵守 robots.txt 规则、控制请求频率以及合法使用数据,以确保爬虫技术健康有序发展。
|
2月前
|
数据采集 Java 数据处理
Python实用技巧:轻松驾驭多线程与多进程,加速任务执行
在Python编程中,多线程和多进程是提升程序效率的关键工具。多线程适用于I/O密集型任务,如文件读写、网络请求;多进程则适合CPU密集型任务,如科学计算、图像处理。本文详细介绍这两种并发编程方式的基本用法及应用场景,并通过实例代码展示如何使用threading、multiprocessing模块及线程池、进程池来优化程序性能。结合实际案例,帮助读者掌握并发编程技巧,提高程序执行速度和资源利用率。
70 0
|
5月前
|
并行计算 数据处理 调度
Python中的并发编程:探索多线程与多进程的奥秘####
本文深入探讨了Python中并发编程的两种主要方式——多线程与多进程,通过对比分析它们的工作原理、适用场景及性能差异,揭示了在不同应用需求下如何合理选择并发模型。文章首先简述了并发编程的基本概念,随后详细阐述了Python中多线程与多进程的实现机制,包括GIL(全局解释器锁)对多线程的影响以及多进程的独立内存空间特性。最后,通过实例演示了如何在Python项目中有效利用多线程和多进程提升程序性能。 ####
|
5月前
|
数据采集 前端开发 中间件
Python网络爬虫:Scrapy框架的实战应用与技巧分享
【10月更文挑战第26天】Python是一种强大的编程语言,在数据抓取和网络爬虫领域应用广泛。Scrapy作为高效灵活的爬虫框架,为开发者提供了强大的工具集。本文通过实战案例,详细解析Scrapy框架的应用与技巧,并附上示例代码。文章介绍了Scrapy的基本概念、创建项目、编写简单爬虫、高级特性和技巧等内容。
245 4
|
5月前
|
数据采集 Web App开发 JavaScript
爬虫策略规避:Python爬虫的浏览器自动化
爬虫策略规避:Python爬虫的浏览器自动化
|
5月前
|
调度 iOS开发 MacOS
python多进程一文够了!!!
本文介绍了高效编程中的多任务原理及其在Python中的实现。主要内容包括多任务的概念、单核和多核CPU的多任务实现、并发与并行的区别、多任务的实现方式(多进程、多线程、协程等)。详细讲解了进程的概念、使用方法、全局变量在多个子进程中的共享问题、启动大量子进程的方法、进程间通信(队列、字典、列表共享)、生产者消费者模型的实现,以及一个实际案例——抓取斗图网站的图片。通过这些内容,读者可以深入理解多任务编程的原理和实践技巧。
314 1
|
6月前
|
Python
Python中的多线程与多进程
本文将探讨Python中多线程和多进程的基本概念、使用场景以及实现方式。通过对比分析,我们将了解何时使用多线程或多进程更为合适,并提供一些实用的代码示例来帮助读者更好地理解这两种并发编程技术。
|
5月前
|
监控 JavaScript 前端开发
python中的线程和进程(一文带你了解)
欢迎来到瑞雨溪的博客,这里是一位热爱JavaScript和Vue的大一学生分享技术心得的地方。如果你从我的文章中有所收获,欢迎关注我,我将持续更新更多优质内容,你的支持是我前进的动力!🎉🎉🎉
71 0