【Python爬虫实战】多进程结合 BeautifulSoup 与 Scrapy 构建爬虫项目

ops/2024/11/1 4:14:45/

#1024程序员节|征文#

  🌈个人主页:易辰君-CSDN博客
🔥 系列专栏:https://blog.csdn.net/2401_86688088/category_12797772.html

前言

在大数据时代,爬虫技术是获取和处理网络数据的利器。面对需要处理大量网页的爬取任务,如何提升效率成为了一个重要的问题。Python 的多进程技术结合 BeautifulSoupScrapy,可以在保证解析能力的同时,大大提高并发抓取的效率。这篇文章将详细介绍如何利用多进程模块进行爬虫、结合 JoinableQueue 管理任务,以及在更复杂的场景中使用 BeautifulSoupScrapy,打造功能强大的爬虫项目。


一、多进程爬虫

多进程爬虫是利用Python的多进程模块(如multiprocessing)来并发地抓取网页数据的一种方法。这种方法能够显著提高爬虫的效率,特别是在面对需要处理大量网页时。以下是一些关键点和实现步骤:

(一)多进程的基本概念

  • 多进程:通过创建多个进程来并行执行任务。每个进程都有自己的内存空间和解释器,可以独立工作,适合 CPU 密集型任务。

  • 进程池:使用multiprocessing.Pool可以方便地管理多个进程,自动调度任务。

(二)使用多进程爬虫的好处

  • 提高速度:可以同时请求多个网页,缩短抓取时间。

  • 避免 GIL 限制:Python 的全局解释器锁(GIL)会限制单线程执行,但多进程可以绕过这一限制。

(三)示例

python">import requests
from multiprocessing import Pooldef fetch_url(url):try:response = requests.get(url)print(f"Fetched {url}: {response.status_code}")return response.textexcept Exception as e:print(f"Failed to fetch {url}: {e}")def main(urls):with Pool(processes=4) as pool:  # 创建4个进程results = pool.map(fetch_url, urls)  # 并发抓取return resultsif __name__ == '__main__':urls = ['https://www.example.com','https://www.example.org','https://www.example.net',# 添加更多网址]main(urls)

(四)注意事项

  • 请求频率:要合理控制请求频率,避免被目标网站封禁。

  • 异常处理:确保处理网络请求中的异常情况,防止程序崩溃。

  • 资源管理:爬取大量数据时,要合理管理内存和 CPU 资源。


二、多进程结合JoinableQueue队列

(一)介绍

使用多进程结合 JoinableQueue 来实现爬虫,可以有效管理任务的执行和跟踪任务完成情况。JoinableQueue 允许你在所有任务完成后进行一些后续操作,这对于处理大量网页的爬虫项目非常有用。

以下是一个使用 multiprocessing.JoinableQueue 的爬虫示例,结合 requestsBeautifulSoup 进行网页抓取和解析。

示例:

python">import requests
from bs4 import BeautifulSoup
from multiprocessing import Process, JoinableQueue
import time# 定义爬虫工作函数
def worker(queue):while True:url = queue.get()  # 从队列中获取 URLif url is None:  # 用于退出条件queue.task_done()breakprint(f"Fetching: {url}")try:response = requests.get(url, timeout=5)if response.status_code == 200:soup = BeautifulSoup(response.text, 'html.parser')# 假设提取文章标题titles = soup.find_all('h2')for title in titles:print(f"Title: {title.get_text()}")else:print(f"Failed to fetch {url}: {response.status_code}")except Exception as e:print(f"Error fetching {url}: {e}")finally:queue.task_done()  # 标记任务完成# 主函数
def main(urls):queue = JoinableQueue()processes = []# 启动多个工作进程for _ in range(4):  # 根据需要启动的进程数p = Process(target=worker, args=(queue,))p.start()processes.append(p)# 向队列中添加 URLfor url in urls:queue.put(url)# 等待队列中所有任务完成queue.join()  # 阻塞直到所有任务调用 task_done()# 发送退出信号给每个进程for _ in processes:queue.put(None)# 等待所有进程完成for p in processes:p.join()if __name__ == '__main__':urls = ['https://www.example.com/page1','https://www.example.com/page2','https://www.example.com/page3',# 添加更多网址]start_time = time.time()main(urls)print(f"All tasks completed in {time.time() - start_time:.2f} seconds.")

代码解释:

  • 引入库:引入 requests 进行 HTTP 请求,BeautifulSoup 进行 HTML 解析,multiprocessing 模块进行多进程管理。

  • 工作函数 worker

    • JoinableQueue 中获取 URL。

    • 请求页面并解析 HTML 内容。

    • 提取标题,并在控制台打印。

    • 每处理完一个 URL,调用 queue.task_done() 标记任务完成。

  • 主函数 main

    • 创建 JoinableQueue 实例。

    • 启动多个工作进程。

    • 向队列中添加待爬取的 URL。

    • 调用 queue.join(),阻塞主线程,直到所有任务都标记为完成。

    • 发送退出信号(None)给每个进程,确保所有进程能够正常退出。

  • 执行

    • if __name__ == '__main__' 下执行爬虫逻辑,开始爬取指定的 URL。

(二)使用场景

  • 适用于需要高并发、并且需要确保所有任务都能被处理的爬虫项目。

  • 适合处理大量网页抓取任务时,能够有效地管理工作流程和任务状态。


三、构建复杂的多进程项目

结合多进程与 BeautifulSoupScrapy 可以构建更高效、复杂的爬虫项目。根据项目规模和需求,可以选择不同的组合方式。下面介绍两种结合方式:使用 BeautifulSoup 与多进程实现一个轻量级爬虫,以及通过多进程管理多个 Scrapy 爬虫实例的方案。

(一)多进程 + BeautifulSoup 实现轻量级爬虫

这种方案适合中小型爬虫项目,手动管理请求和数据解析,同时使用多进程加速请求处理。适用于需要快速获取网页数据并做简单解析的场景。

示例:

python">import requests
from bs4 import BeautifulSoup
from multiprocessing import Process, JoinableQueue
import time# 定义爬虫工作函数
def worker(queue):while True:url = queue.get()if url is None:  # 退出条件queue.task_done()breaktry:response = requests.get(url, timeout=5)if response.status_code == 200:soup = BeautifulSoup(response.text, 'html.parser')# 假设需要提取所有标题和链接titles = soup.find_all('h2')  # 根据实际结构调整for title in titles:print(f"Title: {title.get_text()} - URL: {url}")else:print(f"Failed to fetch {url}: {response.status_code}")except Exception as e:print(f"Error fetching {url}: {e}")finally:queue.task_done()# 主函数
def main(urls):queue = JoinableQueue()processes = []# 启动多个进程for _ in range(4):  # 启动4个工作进程p = Process(target=worker, args=(queue,))p.start()processes.append(p)# 添加 URL 到队列for url in urls:queue.put(url)# 等待队列中所有任务完成queue.join()# 发送退出信号给每个进程for _ in processes:queue.put(None)# 等待所有进程完成for p in processes:p.join()if __name__ == '__main__':urls = ['https://www.example.com/page1','https://www.example.com/page2','https://www.example.com/page3',# 添加更多网址]start_time = time.time()main(urls)print(f"All tasks completed in {time.time() - start_time:.2f} seconds.")

代码解释:

  • 使用 requests 库抓取网页,BeautifulSoup 解析 HTML。

  • 利用 multiprocessing.JoinableQueue 管理 URL 队列,每个进程独立处理一个 URL。

  • JoinableQueuetask_donejoin 方法确保主进程在所有任务完成后继续执行。

(二)多进程 + Scrapy 管理大型爬虫项目

Scrapy 是一个功能强大的爬虫框架,自带异步处理和数据管道,但在某些场景下,可以通过多进程来管理多个独立的爬虫任务,尤其是当需要同时爬取多个不同网站时。

(1)编写 Scrapy 爬虫

spiders/my_spider.py 中创建一个简单的 Scrapy 爬虫。

python">import scrapyclass MySpider(scrapy.Spider):name = 'myspider'start_urls = ['https://www.example.com']def parse(self, response):titles = response.css('h2::text').getall()  # 假设要提取的内容为 <h2> 标签的文本for title in titles:yield {'title': title}

(2)多进程管理多个 Scrapy 实例

创建一个 Python 脚本 run_spiders.py,在其中使用 multiprocessing 启动多个 Scrapy 爬虫实例。

示例:

python">from multiprocessing import Process
from scrapy.crawler import CrawlerProcess
from scrapy.utils.project import get_project_settings
from myproject.spiders.my_spider import MySpiderdef run_spider():process = CrawlerProcess(get_project_settings())process.crawl(MySpider)process.start()if __name__ == '__main__':processes = []# 启动多个爬虫进程for _ in range(3):  # 根据需求启动多个爬虫实例p = Process(target=run_spider)p.start()processes.append(p)# 等待所有爬虫进程完成for p in processes:p.join()

解释:

  • Scrapy 爬虫:在 my_spider.py 中定义爬虫规则,解析 h2 标签内容。

  • 多进程管理:通过 multiprocessing.Process 启动多个 Scrapy 爬虫实例,每个实例可以处理不同的任务。

  • 适用场景:当需要同时抓取多个不同的网站或执行多个独立爬虫任务时,这种方式可以提高抓取效率。

(三)设计复杂爬虫项目的建议

  • 合理选择并发模式:对于中小型项目,requests + BeautifulSoup + 多进程已经能达到较高的性能;对于大规模项目,Scrapy 是更好的选择。

  • 任务调度和监控:在多进程环境下,确保每个任务有清晰的调度和监控机制,防止资源浪费和任务卡死。

  • 错误处理:无论使用哪种组合方式,都要做好异常处理,避免因为某些 URL 或请求失败而导致整个爬虫崩溃。

  • 延迟和限速:为了避免被目标网站封禁,建议在多进程或异步请求中加入请求延迟和限速机制。

(四)多进行项目总结

  • 多进程 + BeautifulSoup:适合需要手动处理请求和解析的场景,通过 JoinableQueue 管理任务,简单易用。

  • 多进程 + Scrapy:适用于需要处理大规模数据抓取的场景,能够利用 Scrapy 的异步特性,同时通过多进程管理多个任务,适合大规模爬虫项目。


四、总结

通过结合 Python 的多进程能力与数据解析库,如 BeautifulSoupScrapy,我们可以打造高效且灵活的爬虫系统。对于中小型项目,使用多进程加速抓取和解析是一个便捷的选择,而在处理大规模任务时,Scrapy 的异步能力与多进程结合则更为适用。在实际应用中,合理设计爬虫结构和任务管理机制,能够显著提升数据抓取效率。这不仅可以帮助开发者应对数据采集的挑战,更为大数据分析和挖掘奠定了基础。希望本文的介绍能够为你的爬虫项目提供有价值的参考和帮助。


http://www.ppmy.cn/ops/130030.html

相关文章

RabbitMQ几大应用问题

目录 1.幂等性保障 2.顺序性保障 3.消息积压 1.幂等性保障 &#xff08;1&#xff09;介绍幂等性 幂等性&#xff0c;最早期是数学和计算机科学中某些运算的性质&#xff0c;它们可以被多次应用&#xff0c;而不会改变初始应用的结果 比如说&#xff0c;重复多次调用同一…

深度学习:交叉熵损失(Cross Entropy Loss)

交叉熵损失&#xff08;Cross Entropy Loss&#xff09; 定义和数学表达 交叉熵损失是一种常用于评估概率分类模型性能的损失函数。它衡量的是模型预测的概率分布与真实分布之间的差异。交叉熵损失特别适用于分类任务中&#xff0c;尤其是多类分类问题。 数学上&#xff0c;…

【K8S】kubernetes-dashboard.yaml

https://raw.githubusercontent.com/kubernetes/dashboard/v3.0.0-alpha0/charts/kubernetes-dashboard.yaml 以下链接的内容&#xff1a; 由于国内访问不了&#xff0c;找到一些方法下载了这个文件内容&#xff0c; 部署是mages 对象的镜像 WEB docker.io/kubernetesui/dash…

智能护栏碰撞监测终端:内蒙古高速的安全守护者

​ ​一、引言 ​ ​在内蒙古那辽阔的大地上&#xff0c;高速公路如动脉般纵横交错&#xff0c;是经济发展与人员流动的重要通道。而保障这些公路安全运行的关键因素之一&#xff0c;便是智能护栏碰撞监测终端。它以其卓越的性能&#xff0c;实时为公路安全保驾护航&…

vue封装信号强度

图标下载链接: https://pan.baidu.com/s/1828AidkCKU1KTkw1SvBwQg?pwd4k7n 共五格信号 信号5为绿色&#xff0c;信号4为绿色&#xff0c;信号3为黄色&#xff0c;信号2为黄色&#xff0c;信号1为红色&#xff0c;信号0为灰色。 子组件 /components/SignalStrength/index.vu…

SpringMVC实战(3):拓展

四、RESTFul风格设计和实战 4.1 RESTFul风格概述 4.1.1 RESTFul风格简介 RESTful&#xff08;Representational State Transfer&#xff09;是一种软件架构风格&#xff0c;用于设计网络应用程序和服务之间的通信。它是一种基于标准 HTTP 方法的简单和轻量级的通信协议&…

安全研究 | 不同编程语言中 IP 地址分类的不一致性

作为一名安全研究人员&#xff0c;我分析了不同编程语言中 IP 地址分类 的行为。最近&#xff0c;我注意到一些有趣的不一致性&#xff0c;特别是在循环地址和私有 IP 地址的处理上。在这篇文章中&#xff0c;我将分享我对此问题的观察和见解。 设置 我检查了多种编程语言&am…

如何应对PDF无法转换成其他格式?常见原因与解决方法解析

在日常工作中&#xff0c;PDF文件的格式转换是非常常见的操作&#xff0c;无论是转换为Word、Excel&#xff0c;还是其他格式&#xff0c;都会有一些方便的工具支持。然而&#xff0c;有时在转换PDF时可能会遇到无法转换的问题。这个时候&#xff0c;可以看看是不是以下几个原因…