Python多线程爬虫编程中队列的问题详解

Python多线程爬虫能够快速有效的完成数据采集的工作,他的工作效率高,深受各类互联网公司的青睐,那么在多线程爬虫中如果有下面的问题可以尝试的我的方法来解决。

在Python中,queue模块提供了多种队列类,用于在多线程编程中安全地交换信息。其中,queue.Queue 和queue.SimpleQueue 是两个常用的先进先出(FIFO)的队列类,它们有以下区别和优缺点:

queue.Queue 是一个更复杂的队列类,它提供了一些方法和功能,如限制队列大小、等待队列中的任务完成、检查队列是否为空或满等。这些功能可以方便地在多线程环境中同步生产者和消费者的行为,并且使得代码更易于设计、阅读和维护。
在这里插入图片描述

queue.Queue 的缺点是它的实现涉及到多个锁和条件变量,因此可能会影响性能和内存效率。另外,它不能处理重入性的问题,即如果在同一线程中调用put()或get()方法时被打断,可能会导致死锁或数据丢失。

queue.SimpleQueue 是一个更简单的队列类,它只提供了put()和get()两个方法,并且可以处理重入性的问题。因此,它有更好的性能和内存效率,并且可以在一些特殊情况下安全地调用put()或get()方法,如del方法、weakref回调或信号处理器。

queue.SimpleQueue 的缺点是它只提供了put()和get()两个方法,并且不支持maxsize参数。因此,它不能限制队列大小,也不能等待队列中的任务完成。如果需要这些功能,可以使用queue.Queue 或者queue.JoinableQueue。

下面分别用Queue和queue.SimpleQueue,根据多线程网络请求的需求进行实现。

import queue
import threading
import requests
# 定义一个队列对象,用于在多线程中传递数据
q = queue.Queue()
# 定义一个函数,用于在子线程中发送请求,并使用代理IP
def send_request():
    # 从队列中获取数据,如果队列为空,则阻塞等待
    data = q.get()
    # 获取代理IP地址、用户名和密码,以及目标URL
    proxy_ip = data["proxy_ip"]   
    username = data["username"]
    password = data["password"]
    url = data["url"]
    # 设置代理参数,包括代理IP、用户名和密码
    proxies = {
    
    
        "http": f"http://{
      
      username}:{
      
      password}@{
      
      proxy_ip}",
        "https": f"http://{
      
      username}:{
      
      password}@{
      
      proxy_ip}"
    }
    # 发送请求,并打印响应状态码和内容
    try:
        response = requests.get(url, proxies=proxies)
        print(f"Response status: {
      
      response.status_code}")
        print(f"Response content: {
      
      response.text}")
    except Exception as e:
        print(f"Error: {
      
      e}")
    # 通知队列任务已完成,并释放资源
    q.task_done()
# 在主线程中创建三个子线程对象,并传入send_request函数作为参数,并设置为守护线程(daemon)
threads = []
for i in range(3):
    thread = threading.Thread(target=send_request, daemon=True)
    threads.append(thread)
# 启动三个子线程,并将它们加入到主线程的等待列表中
for thread in threads:
    thread.start()
# 在主线程中向队列中放入数据,这里假设有三组代理IP和URL的组合
data_list = [
    {
    
    "proxy_ip": "jshk.com.cn:3100", "username": "jshk", "password": "16IP-ps1", "url": "Example Domain"},
    {
    
    "proxy_ip": "jshk.com.cn:3100", "username": "jshk", "password": "16IP-ps2", "url": "Example Domain"},
    {
    
    "proxy_ip": "jshk.com.cn:3100", "username": "jshk", "password": "16IP-ps3", "url": "Example Domain"}
]
for data in data_list:
    q.put(data)
# 等待队列中的所有任务完成,并阻塞主线程直到所有子线程结束
q.join()

上面代码使用Queue实现了一个多线程的爬虫程序,通过3个线程采集不同的url,然后等待队列中的所有任务完成,并阻塞主线程直到所有子线程结束。

import queue
import threading
import requests
# 定义一个SimpleQueue对象,用于在多线程中传递数据
q = queue.SimpleQueue()
# 定义一个函数,用于在子线程中发送请求,并使用代理IP
def send_request():
    # 从队列中获取数据,如果队列为空,则阻塞等待
    data = q.get(
    # 获取代理IP地址和目标URL
    proxy_ip = data["proxy_ip"]
    url = data["url"]
    # 获取用户名和密码
    username = data["username"]
    password = data["password"]
    # 设置代理参数,并添加认证信息
    proxies = {
    
    
        "http": f"http://{
      
      proxy_ip}",
        "https": f"http://{
      
      proxy_ip}"
    }
    auth = requests.auth.HTTPProxyAuth(username, password)


    # 发送请求,并打印响应状态码和内容
    try:
        response = requests.get(url, proxies=proxies, auth=auth)
        print(f"Response status: {
      
      response.status_code}")
        print(f"Response content: {
      
      response.text}")
    except Exception as e:
        print(f"Error: {
      
      e}")


# 在主线程中创建三个子线程对象,并传入send_request函数作为参数,并设置为守护线程(daemon)
threads = []
for i in range(3):
    thread = threading.Thread(target=send_request, daemon=True)
    threads.append(thread)
# 启动三个子线程,并将它们加入到主线程的等待列表中
for thread in threads:
    thread.start


# 在主线程中向队列中放入数据,这里假设有三组代理IP和URL的组合,以及对应的用户名和密码
data_list = [
    {
    
    "proxy_ip": "jshk.com.cn:3100", "url": "Example Domain", "username": "jshk", "password": "16IP-ps1"},
    {
    
    "proxy_ip": "jshk.com.cn:3100", "url": "Example Domain", "username": "jshk", "password": "16IP-ps2"},
    {
    
    "proxy_ip": "jshk.com.cn:3100", "url": "Example Domain", "username": "jshk", "password": "16IP-ps3"}
]
for data in data_list:
    q.put(data)
# 等待所有子线程结束(由于是守护线程,所以当主线程结束时会自动结束)

上面代码使用SimpleQueue对象,实现了一个生产者-消费者模式的多线程爬虫程序程序。它的功能是在多个子线程中使用爬虫IP向目标URL发送HTTP请求,并打印响应状态码和内容,等待所有子线程结束。由于子线程设置为守护线程,所以当主线程结束时,子线程也会自动结束。

通过上述示例,可以分别根据目前的应用场景和需求选择适合的方式。

猜你喜欢

转载自blog.csdn.net/weixin_44617651/article/details/129580766