Python爬虫中的并发编程详解

Python爬虫中的并发编程详解

在Python爬虫中,为了提高爬虫效率,通常需要使用并发编程。本文将介绍Python爬虫中的并发编程,包括多线程、协程和异步IO等技术。同时,还会提供两个示例讲解。

多线程

多线程是指在一个进程中存在多个线程,每个线程都可以独立执行不同的任务。在Python中,可以使用threading模块实现多线程编程。

下面是一个简单的示例,使用多线程爬取多个网页内容:

import threading
import requests

urls = ['https://www.baidu.com', 'https://www.hao123.com', 'https://www.sogo.com']

def fetch(url):
    response = requests.get(url)
    print(url, response.status_code)

threads = []
for url in urls:
    t = threading.Thread(target=fetch, args=(url,))
    threads.append(t)

for t in threads:
    t.start()

for t in threads:
    t.join()

在上述示例中,首先定义了一个fetch函数,用于发送HTTP请求并打印响应状态码。然后定义了一个urls列表,其中包含要爬取的网页地址。接着,使用threading.Thread类创建多个线程,并将它们添加到threads列表中。最后,分别启动所有线程并等待它们执行完成。

协程

协程是一种更轻量级的线程,由于不需要线程上下文切换的开销,因此协程的并发量通常比多线程要高。在Python中,可以使用asyncio模块实现协程编程。

下面是一个简单的示例,使用协程爬取多个网页内容:

import asyncio
import aiohttp

urls = ['https://www.baidu.com', 'https://www.hao123.com', 'https://www.sogo.com']

async def fetch(url):
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as response:
            print(url, response.status)

async def main():
    tasks = [fetch(url) for url in urls]
    await asyncio.gather(*tasks)

asyncio.run(main())

在上述示例中,首先定义了一个fetch协程函数,使用aiohttp库发送HTTP请求并打印响应状态码。然后定义了一个urls列表,其中包含要爬取的网页地址。接着,使用asyncio.gather()函数将多个协程任务合并为一个main协程任务,并使用asyncio.run()函数运行它。

异步IO

异步IO是一种高效的IO模型,它允许程序在等待IO操作完成时执行其他任务。在Python中,可以使用asyncio模块实现异步IO编程。

下面是一个简单的示例,使用异步IO爬取多个网页内容:

import asyncio
import aiohttp

urls = ['https://www.baidu.com', 'https://www.hao123.com', 'https://www.sogo.com']

async def fetch(url):
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as response:
            return await response.text()

async def main():
    tasks = [fetch(url) for url in urls]
    responses = await asyncio.gather(*tasks)
    for url, response in zip(urls, responses):
        print(url, len(response))

asyncio.run(main())

在上述示例中,首先定义了一个fetch协程函数,使用aiohttp库发送HTTP请求并返回响应内容。然后定义了一个urls列表,其中包含要爬取的网页地址。接着,使用asyncio.gather()函数将多个协程任务合并为一个main协程任务,并使用asyncio.run()函数运行它。最后,将每个网页的URL和响应内容长度打印出来。

示例说明

示例1:使用多线程下载图片

假设需要从多个网站下载图片,为了提高下载速度,可以使用多线程进行并发下载。可以定义一个download函数用于下载图片,然后使用多线程启动多个download函数进行下载。

import requests
import threading

urls = [
    'https://www.baidu.com/img/PCfb_5bf082d29588c07f842ccde3f97243ea.png',
    'https://www.hao123.com/static/img/newindex/logo_efe5aabd.png',
    'https://www.sogou.com/images/logo/new/sogou.png'
]

def download(url):
    response = requests.get(url)
    filename = url.split('/')[-1]
    with open(filename, 'wb') as f:
        f.write(response.content)
    print(f'{url}下载完成')

threads = []
for url in urls:
    t = threading.Thread(target=download, args=(url,))
    t.start()
    threads.append(t)

for t in threads:
    t.join()

在上述示例中,首先定义了一个download函数,用于下载指定URL的图片,并将其保存到本地文件。然后定义了一个urls列表,其中包含要下载的图片URL。接着,使用多线程启动多个download函数进行下载,并等待所有线程执行完成。

示例2:使用协程爬取豆瓣电影Top250

假设需要爬取豆瓣电影Top250页面,并获取每部电影的名称、评分和简介。可以先分析页面结构,然后使用aiohttpasyncio库进行异步IO爬取。

import aiohttp
import asyncio
from lxml import etree

async def fetch(session, url):
    async with session.get(url) as response:
        return await response.text()

async def parse(html):
    tree = etree.HTML(html)
    items = tree.xpath('//div[@class="info"]')
    for item in items:
        title = item.xpath('.//span[@class="title"]/text()')[0]
        rating = item.xpath('.//span[@class="rating_num"]/text()')[0]
        desc = item.xpath('.//span[@class="inq"]/text()')[0]
        print(f'{title}{rating}  {desc}')

async def main():
    async with aiohttp.ClientSession() as session:
        for i in range(0, 250, 25):
            url = f'https://movie.douban.com/top250?start={i}&filter='
            html = await fetch(session, url)
            await parse(html)

asyncio.run(main())

在上述示例中,首先定义了一个fetch协程函数,使用aiohttp库发送HTTP请求并返回响应内容。然后定义了一个parse协程函数,使用lxml库解析HTML页面,并提取电影名称、评分和简介等信息。接着,使用asyncio.gather()函数将多个协程任务合并为一个main协程任务,并使用asyncio.run()函数运行它。最后,根据豆瓣电影Top250页面的分页规则,循环下载每一页的HTML并解析获取电影信息。

以上是Python爬虫中的并发编程详解过程,包括多线程、协程和异步IO等技术,并提供了两个示例说明。理解并掌握这些技术,可以提高爬虫效率,缩短爬取时间。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Python爬虫中的并发编程详解 - Python技术站

(1)
上一篇 2023年5月14日
下一篇 2023年5月14日

相关文章

  • 一文详解Python如何优雅地对数据进行分组

    下面是详细讲解“一文详解Python如何优雅地对数据进行分组”的完整攻略。 什么是数据分组 在数据处理中,经常需要将数据按照某个特征进行分组,然后计算每组的统计量,如均值、中位数等。这个过程就是数据分组。在Python中,我们可以使用pandas库中的groupby方法进行数据分组。 如何使用groupby方法 groupby方法可以对DataFrame或S…

    python 2023年5月13日
    00
  • python tkinter canvas 显示图片的示例

    下面是详细的Python Tkinter Canvas显示图片的攻略。 准备工作 在开始编写代码之前,我们需要准备一些工作。 安装Python 首先,我们需要安装Python。 如果你已经安装了Python,可以跳过此步骤。如果还没有安装Python,建议选择Python 3.x版本进行安装。 你可以到官方网站 https://www.python.org/…

    python 2023年5月30日
    00
  • 关于你不想知道的所有Python3 unicode特性

    当我们在处理Python3中的字符串时,肯定会涉及到Unicode编码。Unicode是一种字符编码方案,它为每个字符分配了唯一的数字编码,让我们在处理各种不同语言的文本时更加容易。Python3中有很多的Unicode特性,这些特性虽然很强大,但对于初学者来说也许会非常困难。那么我们来一步一步详细讲解下面这份完整攻略。 什么是Unicode? Unicod…

    python 2023年5月31日
    00
  • 对python字典过滤条件的实例详解

    针对“对python字典过滤条件的实例详解”的攻略,我将从以下几个方面进行讲解: 什么是Python字典 字典过滤条件的介绍 Python字典过滤条件的实现方法 示例1:对字典按照值进行过滤 示例2:对字典按照键进行过滤 1. 什么是Python字典 Python字典是一种可变容器类型,可以存储任意数量的Python对象,每个对象都通过一个唯一的键(key)…

    python 2023年5月13日
    00
  • python迭代器常见用法实例分析

    Python迭代器常见用法实例分析 什么是迭代器? 在Python中,迭代器是支持迭代的对象,实现了__iter__和__next__方法。其中__iter__方法返回实例自身,__next__方法返回序列中的下一个元素。当迭代到序列末尾时,迭代器会引发StopIteration异常。 Python中内置了很多迭代器,如range、list、tuple、se…

    python 2023年5月14日
    00
  • python实现上传文件到linux指定目录的方法

    首先,实现上传文件到Linux指定目录的方法需要使用到Python的paramiko模块,该模块提供了SSH连接和文件传输功能。 安装paramiko模块 使用pip install命令安装paramiko模块: !pip install paramiko 连接Linux服务器 首先,需要进行SSH连接: import paramiko hostname =…

    python 2023年6月3日
    00
  • Python 2/3下处理cjk编码的zip文件的方法

    Python中的zipfile模块可以用来操作zip文件。当zip文件中含有cjk编码的文件名或文件内容时,可能会出现一些问题。 下面是在Python 2/3中处理cjk编码的zip文件的方法: 1. 使用ZipFile类读取zip文件 在Python中,我们可以使用ZipFile类来读取zip文件。ZipFile可以接受三个参数:文件名、模式和压缩方法。 …

    python 2023年5月31日
    00
  • pip报错“ValueError: invalid literal for int() with base 10: ‘1.9’”怎么处理?

    当使用Java的Hibernate框架时,可能会遇到“ObjectNotSerializableException”错误。这个错误通常是由以下原因之一引起的: 对象不可序列化:如果对象不可序列化,则可能会出现此错误。在这种情况下,需要确保对象实现了Serializable接口。 对象包含不可序列化的字段:如果对象包含不可序列化的字段,则可能会出现此错误。在这…

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