爬虫入门指南(5): 分布式爬虫与并发控制 【提高爬取效率与请求合理性控制的实现方法】

news2024/11/16 16:40:33

文章目录

  • 前言
  • 多线程与多进程
    • 多线程
    • 多进程
    • 多线程和多进程的选择
  • 使用Scrapy框架实现分布式爬虫
    • 1. 创建Scrapy项目
    • 2. 配置Scrapy-Redis
    • 3. 创建爬虫
        • 4. 启动爬虫节点
        • 5. 添加任务到队列
  • 并发控制与限制请求频率
    • 并发控制
    • 限制请求频率
  • 未完待续...

前言

在进行爬虫任务时,我们常常会面临两个重要问题:如何提高爬取效率以及如何合理控制请求的并发量,以避免对目标网站造成过大的压力。针对这些问题,本文将介绍分布式爬虫与并发控制的相关知识点,并演示使用Scrapy框架实现分布式爬虫,并对并发控制进行限制请求频率。

多线程与多进程

多线程与多进程

当涉及到并发处理时,多线程和多进程是两种常用的技术。它们可以同时执行多个任务,提高程序的效率和性能。下面我将详细讲解多线程和多进程的概念、特点以及使用方法。

多线程

多线程

多线程是指在一个进程内创建多个线程来执行任务。线程是程序执行中的最小单元,多个线程共享同一个进程的资源。多线程有以下几个特点:

  1. 资源共享:多个线程可以共享同一个进程的地址空间、文件描述符等资源,因此可以方便地进行数据交换和通信。
  2. 轻量级:相对于多进程而言,多线程的创建和切换成本更低,占用的系统资源更少。
  3. 异步编程:多线程可以实现异步操作,使得程序可以同时执行多个任务,提高程序的响应速度。

在Python中,可以使用标准库中的threading模块实现多线程编程。具体步骤如下:

  1. 导入threading模块:import threading
  2. 定义线程函数:编写需要在每个线程中执行的任务。
  3. 创建线程对象:使用threading.Thread(target=函数名)创建线程对象,并设置线程的目标函数。
  4. 启动线程:使用start()方法启动线程,开始执行线程中的任务。
  5. 等待线程结束:使用join()方法等待线程执行完毕。

示例代码:

 import threading

def task():
    # 线程执行的任务
    print("Thread ID: {} - Hello, World!".format(threading.get_ident()))

# 创建4个线程并启动
for _ in range(4):
    thread = threading.Thread(target=task)  # 创建线程对象,设置目标函数为task
    thread.start()  # 启动线程
    thread.join()  # 等待线程结束

代码使用threading模块创建了4个线程,并在每个线程中执行task()函数。每个线程将打印出当前线程的ID,然后输出"Hello, World!"。通过循环创建和启动线程,并使用join()方法等待线程结束,确保每个线程都执行完毕。

多进程

多进程

多进程是指在操作系统中同时运行多个进程,每个进程独立执行任务。不同进程之间有自己独立的内存空间和资源环境,彼此之间不会相互影响。多进程有以下几个特点:

  1. 数据隔离:每个进程拥有独立的地址空间和资源环境,数据之间相互隔离,保证了程序的安全性。
  2. 并发处理:多个进程可以同时执行不同的任务,提高程序的并发处理能力。
  3. 稳定性:由于进程之间相互独立,一个进程崩溃不会影响其他进程,提高了程序的稳定性。

在Python中,可以使用标准库中的multiprocessing模块实现多进程编程。具体步骤如下:

  1. 导入multiprocessing模块:import multiprocessing
  2. 定义进程函数:编写需要在每个进程中执行的任务。
  3. 创建进程对象:使用multiprocessing.Process(target=函数名)创建进程对象,并设置进程的目标函数。
  4. 启动进程:使用start()方法启动进程,开始执行进程中的任务。
  5. 等待进程结束:使用join()方法等待进程执行完毕。

示例代码:

  import multiprocessing

def task():
    # 进程执行的任务
    print("Process ID: {} - Hello, World!".format(multiprocessing.current_process().pid))

# 创建4个进程并启动
processes = []
for _ in range(4):
    process = multiprocessing.Process(target=task)  # 创建进程对象,设置目标函数为task
    process.start()  # 启动进程
    processes.append(process)

# 等待所有进程结束
for process in processes:
    process.join()

代码使用multiprocessing模块创建了4个进程,并在每个进程中执行task()函数。每个进程将打印出当前进程的ID,然后输出"Hello, World!"。通过循环创建和启动进程,并使用join()方法等待所有进程结束,确保每个进程都执行完毕。

注意,在多进程示例中,我们使用了一个列表来保存所有的进程对象,然后在最后使用循环和join()方法等待所有进程结束。

多线程和多进程的选择

多线程和多进程的选择

在实际开发中,选择多线程还是多进程需要根据具体的需求和情况进行权衡。一般来说:

  • 如果任务涉及到I/O密集型操作(如网络请求、文件读写等),多线程通常是一个不错的选择,因为线程之间可以很好地共享资源和交互。
  • 如果任务涉及到CPU密集型操作(如复杂的计算、图像处理等),多进程可能更适合,因为每个进程有独立的计算资源,可以充分利用多核处理器。

此外,需要注意的是,多线程和多进程的并发操作涉及到共享资源的访问,可能引发一些并发控制和同步机制的问题,例如线程安全性、锁、信号量等,开发者需要注意处理这些问题,保证程序的正确执行。

使用Scrapy框架实现分布式爬虫

 使用Scrapy框架实现分布式爬虫

Scrapy是一个强大的Python爬虫框架,提供了分布式爬虫的支持。通过使用Scrapy的分布式架构,我们可以将爬取任务分发到多个节点上,以提高爬取效率。

  • 当使用Scrapy框架实现分布式爬虫时,可以利用Scrapy-Redis扩展来实现任务队列的管理和分布式爬取。Scrapy-Redis扩展通过使用Redis作为任务队列实现多个爬虫节点之间的任务调度和数据共享。下

首先安装好Scrapy和Scrapy-Redis扩展。

命令如下:

pip install scrapy scrapy-redis

接下来,创建一个Scrapy项目,并在该项目中进行相应的配置。

1. 创建Scrapy项目

scrapy startproject myproject

这会生成一个名为myproject的Scrapy项目。

2. 配置Scrapy-Redis

进入项目目录,打开settings.py文件,添加以下内容:

# 开启Scrapy-Redis扩展
import scrapy_redis

# 将默认的Scheduler替换为Scrapy-Redis提供的Scheduler
SCHEDULER = "scrapy_redis.scheduler.Scheduler"
# 使用Redis的去重器
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
# 设置Redis为队列的存储方式
SCHEDULER_QUEUE_CLASS = "scrapy_redis.queue.SpiderPriorityQueue"
# 允许暂停后,恢复之前的爬取进度
SCHEDULER_PERSIST = True
# 在Redis中保留请求队列和去重集合的时间,单位为秒
SCHEDULER_IDLE_BEFORE_CLOSE = 10

# 设置Redis连接参数
REDIS_HOST = 'localhost'  # Redis服务器地址
REDIS_PORT = 6379  # Redis端口号

# 启用RedisPipeline将数据存储到Redis中
ITEM_PIPELINES = {
    'scrapy_redis.pipelines.RedisPipeline': 300,
}

以上配置启用了Scrapy-Redis扩展并设置了Redis的连接参数,指定了使用Redis作为队列的存储方式,并使用RedisPipeline将数据存储到Redis中。

3. 创建爬虫

进入项目目录,在命令行中运行以下命令创建一个Spider:

cd myproject
scrapy genspider example example.com

这将在spiders目录下生成一个名为example.py的Spider文件。

打开example.py文件,将其内容修改为以下代码:

import scrapy
from scrapy_redis.spiders import RedisSpider

class ExampleSpider(RedisSpider):
    name = 'example'
    allowed_domains = ['example.com']

    def parse(self, response):
        self.logger.info('Crawled (%d) %s' % (response.status, response.url))

        # 在这里编写你的解析逻辑
        # ...

        yield {
            'url': response.url,
            # ...
        }

这个Spider继承自RedisSpider,使得它能够与Scrapy-Redis扩展配合工作。在parse函数中,你可以编写你的解析逻辑,解析页面中的数据。

4. 启动爬虫节点

在命令行中运行以下命令启动爬虫节点:

scrapy crawl example

此时,爬虫节点会连接到Redis队列,并开始从队列中获取任务并执行。

5. 添加任务到队列

最后,可以通过将任务添加到Redis队列来分发给爬虫节点。可以使用以下代码将任务添加到队列中:

import redis
import json

# 连接到Redis
redis_client = redis.Redis(host='localhost', port=6379)

# 添加任务到队列
task = {
    'url': 'http://www.example.com',
    # ...
}
redis_client.lpush('example:start_urls', json.dumps(task))

代码通过Redis的连接客户端redis.Redis连接到Redis服务器,并将任务封装为JSON格式的字符串,然后使用lpush()方法将任务添加到名为example:start_urls的队列中。

通过以上步骤,你就可以实现使用Scrapy框架和Scrapy-Redis扩展来实现分布式爬虫。每个爬虫节点都可以从Redis队列中获取任务,并将结果存储到Redis中,实现数据的共享和分布式爬取。

并发控制与限制请求频率

并发控制与限制请求频率

当进行爬虫开发时,为了避免对目标网站造成过大的压力或触发反爬措施,我们通常需要对并发请求数量进行控制,并限制请求频率。

并发控制

并发控制是指控制同时发送给目标网站的请求数量,以避免对其服务器造成过大的负载。Scrapy提供了几种方式来实现并发控制:

  1. settings.py中设置CONCURRENT_REQUESTS参数来控制同时发送的请求数量。例如,可以将其设置为CONCURRENT_REQUESTS = 16

    CONCURRENT_REQUESTS = 16
    
  2. 可以使用CONCURRENT_REQUESTS_PER_DOMAIN参数来限制每个域名同时发送的请求数量。例如,可以将其设置为CONCURRENT_REQUESTS_PER_DOMAIN = 8

    CONCURRENT_REQUESTS_PER_DOMAIN = 8
    
  3. 还可以使用CONCURRENT_REQUESTS_PER_IP参数来限制每个IP地址同时发送的请求数量。例如,可以将其设置为CONCURRENT_REQUESTS_PER_IP = 4

    CONCURRENT_REQUESTS_PER_IP = 4
    

注意:在设置并发控制参数时,要根据目标网站的承受能力和自身的网络带宽来合理调整,避免给目标网站和自己带来不必要的困扰。

限制请求频率

限制请求频率是指控制发送请求的时间间隔,以避免短时间内发送过多的请求。Scrapy提供了几种方式来实现请求频率限制:

  1. 可以在Spider中使用download_delay属性来设置每个请求之间的时间间隔(单位为秒)。

    class MySpider(scrapy.Spider):
        name = 'example'
        allowed_domains = ['example.com']
        start_urls = ['http://www.example.com']
    
        download_delay = 3  # 设置下载延迟为3秒
    
        def parse(self, response):
            # 解析页面数据
            pass
    
  2. 还可以在Spider中重写start_requests()方法,在方法中使用time.sleep()方法来控制请求的时间间隔。

    import time
    
    class MySpider(scrapy.Spider):
        name = 'example'
        allowed_domains = ['example.com']
    
        start_urls = ['http://www.example.com']
    
        def start_requests(self):
            for url in self.start_urls:
                time.sleep(3)  # 每个请求之间等待3秒
                yield scrapy.Request(url=url, callback=self.parse)
    
        def parse(self, response):
            # 解析页面数据
            pass
    
  3. 可以使用AUTOTHROTTLE_ENABLED参数启用自动限速扩展。

    AUTOTHROTTLE_ENABLED = True
    

以上是实现并发控制和请求频率限制的几种方式

未完待续…

未完待续....

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/706075.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

STM32外设系列—红外遥控

文章目录 一、红外遥控简介二、红外遥控的原理三、二进制脉冲编码3.1 NEC码的位定义3.2 NEC遥控指令的数据格式 四、红外遥控程序设计思路五、红外遥控程序设计5.1 红外遥控初始化程序5.2 记录高电平持续时间函数5.3 中断服务函数5.4 读取键值5.5 参数定义 六、应用实例 一、红…

ADB原理,常用命令汇总及示例

一. ADB简介 ADB,即 Android Debug Bridge 是一种允许模拟器或已连接的 Android 设备进行通信的命令行工具,它可为各种设备操作提供便利,如安装和调试应用,并提供对 Unix shell(可用来在模拟器或连接的设备上运行各种…

基于Java+SpringBoot+vue的食品安全管理系统设计与实现

博主介绍:✌擅长Java、微信小程序、Python、Android等,专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇🏻 不然下次找不到哟 Java项目精品实战案…

基于Java+Vue前后端分离网络教学平台设计实现(源码+lw+部署文档+讲解等)

博主介绍:✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专…

Ubuntu连不上网,在windows安装docker后

在windows上安装docker后,会依赖于virtualbox虚拟机,并且有虚拟网络,与ubuntu虚拟机网络产生冲突。 解决办法,打开网络适配器,禁用VirtualBox网络 这个时候就可以了。 ubuntu上使用docker pull镜像的时候&#xff0c…

线性代数克莱姆法则的几何含义

以二元一次方程组的求解为例: { a c a 1 b c b 1 c 1 a c a 2 b c b 2 c 2 \left\{\begin{array}{l} a_{c}a_{1} b_{c}b_{1} c_{1} \\ a_{c}a_{2} b_cb_{2} c_{2} \end{array}\right. {ac​a1​bc​b1​c1​ac​a2​bc​b2​c2​​ 其中 a c a_c ac​和 b c b_…

【Lua】ZeroBrane Studio免费专业IDE使用详解

▒ 目录 ▒ 🛫 问题描述环境 1️⃣ IDE界面说明项目目录编辑器控制台窗口输出窗口选择解释器堆栈窗口监视窗口大纲窗口 2️⃣ 调试程序3️⃣ 自定义lua解释器编译自己的lua解释器增加interpreters配置文件重启IDE 4️⃣ 其它IDE比较Lua EditorVSCode 🛬 …

精密电阻的丝印识别方法

在PCB上经常会出现一些精密的电阻丝印和普通的电阻的丝印识别方式不太一样,比如图1所示。 图1 这种电阻的丝印主要是由两部分组成,第一部分是两个数字,第二部分是一个字母,电阻的阻值的计算就是根据这这个丝印编码。例如图2中的丝…

css中鼠标悬停和点击触发样式变换(:hover和:active)

效果 代码 /*hover--光标(鼠标指针)悬停在元素上时触发*/ .el-card:hover{background: #f5f5f6; } /*active--按下按键和松开按键之间的时间触发*/ .el-card:active{background: #e0dfdf; }

Linux--管道文件:|

作用: 传输资源,你现在可以单纯的把资源看作是数据 》管道的作用是传导数据 构成:入口与出口 存储: 内存级的文件,没有在磁盘上!

Emacs之sr-speedbar替代neotree显示目录(一百一十六)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 人生格言: 人生…

【Linux进程】进程优先级和其他概念 {查看进程优先级,PRI和NI,修改进程优先级;竞争性,独立性,并发和并行,进程上下文}

进程优先级和其他概念 一、进程优先级 1.1 基本概念 什么是优先级? 进程的优先权(priority)就是用来确定CPU资源分配的先后顺序的。进程的优先级是调度器调度进程到CPU执行的重要指标。 为什么要存在优先级? 由于CPU资源有限…

注册登录账号系统

目录 前言 一、项目介绍 二、项目分析 1.框架介绍 框架流程图:​ 板块分析: 前提: (1)注册板块 (2)登录板块 (3)main方法主板块 2.实操展示 (1&#x…

并发List:CopyOnWriteArrayList

CopyOnWriteArrayList 适合写多读少 介绍 JUC包中的并发List只有CopyOnWriteArrayList。CopyOnWriteArrayList是一个线程安全的ArrayList,使用了写时复制策略,对其进行的修改操作都是在底层的一个复制的数组上进行的。 CopyOnWriteList 实现的接口和 Ar…

async异步任务_同步任务选项

需要先看完上文:async创建异步任务_御坂美琴1的博客-CSDN博客 让类里面的一个成员函数当作线程的参数。 async里面有三个参数,一个是成员函数的地址,第二个是 类,第三个是传入的参数。 接下来介绍async的同步线程创建。 asy…

C++类Day2,作业思维

1.昨天的基础上完成运算符重载 #include <iostream> using namespace std;class Complex { private:int real;int vir; public://无参构造Complex(){cout << "无参构造" << endl;}//有参构造Complex(int a,int b):real(a),vir(b){cout << &q…

Ubuntu18.04本地部署Stable-Diffusion-webui绘画

记录Ubuntu下安装Stable-Diffusion-webui&#xff0c;比较简单,以供参考。 系统&#xff1a;Ubuntu 18.04.4 LTS 内存&#xff1a;40G 显卡&#xff1a;32G 硬盘&#xff1a;500G 一、安装cuda 支持安装的cuda版本可以用nvidia-smi命令查看&#xff1a; ----------------…

Tomcat的优化及多实例部署

文章目录 一.Tomcat的优化1.tomcat启动速度优化——random2.Tomcat配置文件参数优化2.1 常用的优化相关参数2.2 优化的配置文件 二.Tomcat多实例部署1.为什么会有tomcat多实例部署2.多实例部署图示3.多实例部署的配置3.1 安装JDK3.2 安装启动Tomcat3.3 配置 tomcat 环境变量3.4…

筹码分布图高级用法——历史换手衰减系数自动计算公式

在使用筹码分布图时&#xff0c;很多人习惯于采用软件的默认设置&#xff0c;然而默认设置不一定能满足我们的要求。今天将向大家介绍筹码分布图的高级用法——历史换手衰减系数&#xff0c;并编写历史换手衰减系数自动计算公式。有些网友认为通过修改衰减系数&#xff0c;可以…

【远程控制】向日葵连接Ubuntu黑屏

Ubuntu 远程黑屏 Ubuntu 22.04 方法 1&#xff1a;切换桌面工作模式方法 2&#xff1a;安装 lightdm 插件来渲染界面客服工单回答 Ubuntu 22.04 方法 1&#xff1a;切换桌面工作模式 进入到登录页 点击用户名 点击右下角&#xff0c;切换桌面工作模式为Ubuntu on xorg即可 …