在Python中,队列(Queue)是一种常用的数据结构,用于在多线程或多进程之间高效地传递数据。在网络爬虫的开发中,队列可以帮助我们管理待抓取的URL,实现生产者消费者模型,以提高爬虫的效率和稳定性。 以下是一个简单的使用队列实现生产者消费者模型的网络爬虫例子:
import threading
import time
from queue import Queue
from urllib.parse import urljoin
import requests
from bs4 import BeautifulSoup
# 生产者线程函数
def worker_producer(queue):
base_url = "http://example.com/"
# 生产一些URL放入队列中
for i in range(10):
url = urljoin(base_url, f'page_{i}')
queue.put(url)
print(f"生产者放入URL: {url}")
queue.put(None) # 表示生产结束,使用None作为特殊标记
# 消费者线程函数
def worker_consumer(queue):
while True:
url = queue.get()
if url is None:
break
try:
response = requests.get(url)
soup = BeautifulSoup(response.text, 'html.parser')
# 这里可以添加代码提取数据,打印或者保存
print(f"消费者处理URL: {url}")
except Exception as e:
print(f"处理URL {url} 时出错: {e}")
finally:
queue.task_done() # 标记任务完成
# 队列初始化
queue = Queue()
# 创建并启动生产者线程
producer_thread = threading.Thread(target=worker_producer, args=(queue,))
producer_thread.start()
# 创建多个消费者线程
consumer_threads = []
for i in range(3): # 假设我们有三个消费者
consumer_thread = threading.Thread(target=worker_consumer, args=(queue,))
consumer_thread.start()
consumer_threads.append(consumer_thread)
# 等待生产者线程完成任务
producer_thread.join()
# 通知消费者线程结束
for _ in consumer_threads:
queue.put(None)
for consumer_thread in consumer_threads:
consumer_thread.join()
print("爬虫结束")
在这个例子中:
worker_producer
函数是生产者线程的函数,它负责生成初始的URL并将它们放入队列中。worker_consumer
函数是消费者线程的函数,它从队列中取出URL并模拟爬取网页的过程。- 使用
threading.Thread
创建多线程,分别启动生产者和消费者。 queue.get()
用于从队列中获取URL,queue.put(None)
用于标识生产结束。- 在消费者函数中,使用
try-except
块处理可能出现的异常,并在每个任务完成后调用queue.task_done()
。 请根据实际情况调整爬虫逻辑和异常处理,确保遵守相关的法律法规和网站的robots.txt协议。