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读者圈,我们一起学习提高~

相关文章
|
1天前
|
数据采集 存储 数据挖掘
深入探索 Python 爬虫:高级技术与实战应用
本文介绍了Python爬虫的高级技术,涵盖并发处理、反爬虫策略(如验证码识别与模拟登录)及数据存储与处理方法。通过asyncio库实现异步爬虫,提升效率;利用tesseract和requests库应对反爬措施;借助SQLAlchemy和pandas进行数据存储与分析。实战部分展示了如何爬取电商网站的商品信息及新闻网站的文章内容。提醒读者在实际应用中需遵守法律法规。
103 66
|
5天前
|
SQL 关系型数据库 MySQL
SQLAlchemy + 协程,实现异步的 ORM
SQLAlchemy + 协程,实现异步的 ORM
15 1
|
9天前
|
数据库 开发者 Python
实战指南:用Python协程与异步函数优化高性能Web应用
在快速发展的Web开发领域,高性能与高效响应是衡量应用质量的重要标准。随着Python在Web开发中的广泛应用,如何利用Python的协程(Coroutine)与异步函数(Async Functions)特性来优化Web应用的性能,成为了许多开发者关注的焦点。本文将从实战角度出发,通过具体案例展示如何运用这些技术来提升Web应用的响应速度和吞吐量。
12 1
|
9天前
|
调度 Python
揭秘Python并发编程核心:深入理解协程与异步函数的工作原理
在Python异步编程领域,协程与异步函数成为处理并发任务的关键工具。协程(微线程)比操作系统线程更轻量级,通过`async def`定义并在遇到`await`表达式时暂停执行。异步函数利用`await`实现任务间的切换。事件循环作为异步编程的核心,负责调度任务;`asyncio`库提供了事件循环的管理。Future对象则优雅地处理异步结果。掌握这些概念,可使代码更高效、简洁且易于维护。
11 1
|
17天前
|
数据采集 存储 JSON
从零到一构建网络爬虫帝国:HTTP协议+Python requests库深度解析
在网络数据的海洋中,网络爬虫遵循HTTP协议,穿梭于互联网各处,收集宝贵信息。本文将从零开始,使用Python的requests库,深入解析HTTP协议,助你构建自己的网络爬虫帝国。首先介绍HTTP协议基础,包括请求与响应结构;然后详细介绍requests库的安装与使用,演示如何发送GET和POST请求并处理响应;最后概述爬虫构建流程及挑战,帮助你逐步掌握核心技术,畅游数据海洋。
48 3
|
17天前
|
数据采集 API 开发者
🚀告别网络爬虫小白!urllib与requests联手,Python网络请求实战全攻略
在网络的广阔世界里,Python凭借其简洁的语法和强大的库支持,成为开发网络爬虫的首选语言。本文将通过实战案例,带你探索urllib和requests两大神器的魅力。urllib作为Python内置库,虽API稍显繁琐,但有助于理解HTTP请求本质;requests则简化了请求流程,使开发者更专注于业务逻辑。从基本的网页内容抓取到处理Cookies与Session,我们将逐一剖析,助你从爬虫新手成长为高手。
41 1
|
5天前
|
数据采集 Linux 调度
Python之多线程与多进程
Python之多线程与多进程
12 0
|
9天前
|
数据采集
爬虫之协程异步 asyncio和aiohttp
爬虫之协程异步 asyncio和aiohttp
|
9天前
|
数据采集
高性能异步爬虫
高性能异步爬虫
|
10天前
|
调度 Python
python3多进程实战(python3经典编程案例)
该文章提供了Python3中使用多进程的实战案例,展示了如何通过Python的标准库`multiprocessing`来创建和管理进程,以实现并发任务的执行。
30 0
下一篇
无影云桌面