如何确保Python Queue的线程和进程安全性:使用锁的技巧

本文涉及的产品
实时数仓Hologres,5000CU*H 100GB 3个月
实时计算 Flink 版,5000CU*H 3个月
检索分析服务 Elasticsearch 版,2核4GB开发者规格 1个月
简介: 本文探讨了在Python爬虫技术中使用锁来保障Queue(队列)的线程和进程安全性。通过分析`queue.Queue`及`multiprocessing.Queue`的基本线程与进程安全特性,文章指出在特定场景下使用锁的重要性。文中还提供了一个综合示例,该示例利用亿牛云爬虫代理服务、多线程技术和锁机制,实现了高效且安全的网页数据采集流程。示例涵盖了代理IP、User-Agent和Cookie的设置,以及如何使用BeautifulSoup解析HTML内容并将其保存为文档。通过这种方式,不仅提高了数据采集效率,还有效避免了并发环境下的数据竞争问题。

爬虫代理.png

背景/引言

在Python的并发编程中,Queue(队列)是一种常用的数据结构,特别是在多线程和多进程环境下,Queue能够有效地在不同线程或进程之间传递数据。Python提供了queue.Queuemultiprocessing.Queue两种标准实现,分别用于线程和进程之间的数据通信。
然而,在爬虫技术中,随着任务复杂度的增加,尤其是涉及到多线程或多进程时,确保Queue的线程和进程安全性变得至关重要。虽然Python的Queue提供了基本的线程和进程安全性,但在某些场景下,如实现“只读”模式或防止数据竞争,还需要额外使用锁(Lock)来确保数据的完整性。
本文将探讨如何在Python中使用锁来保障Queue的线程和进程安全性,并通过一个使用代理IP、user-agent、cookie、多线程技术的实际爬虫示例,展示如何提高数据采集效率。

正文

1. Queue的线程和进程安全性

在Python中,queue.Queuemultiprocessing.Queue都提供了基本的线程和进程安全性。具体来说,.put().get()方法是线程安全和进程安全的,意味着多个线程或进程可以安全地同时调用这些方法而不会引起数据竞争。
然而,其他操作(如遍历队列内容)并没有被保证是安全的。尤其是在需要将队列内容设置为只读时,使用锁是确保数据一致性和防止竞态条件的有效手段。

2. 使用锁实现Queue的安全性

在需要对Queue进行“只读”操作时,可以使用threading.Lockmultiprocessing.Lock来确保在操作期间没有其他线程或进程可以修改Queue的内容。下面的代码展示了如何使用锁来确保Queue的线程和进程安全性。

3. 代理IP、user-agent、cookie设置

在网络爬虫中,使用代理IP、user-agent和cookie是绕过网站反爬措施的常见手段。本文将使用亿牛云爬虫代理服务来设置代理IP,并展示如何在多线程环境下实现高效的数据采集。

实例

以下是一个示例代码,展示了如何在Python中使用锁来确保Queue的安全性,并结合代理IP、多线程技术来实现高效的网页数据采集。

import threading
import requests
from queue import Queue
from bs4 import BeautifulSoup

# 设置代理IP相关信息(使用亿牛云爬虫代理 www.16yun.cn)
proxy_host = "代理服务器域名"  # 例如:"proxy.einiuyun.com"
proxy_port = "代理服务器端口"  # 例如:"12345"
proxy_username = "代理用户名"  # 例如:"your_username"
proxy_password = "代理密码"  # 例如:"your_password"

proxy_url = f"http://{proxy_username}:{proxy_password}@{proxy_host}:{proxy_port}"
proxies = {
   
   
    "http": proxy_url,
    "https": proxy_url,
}

# 设置User-Agent和Cookie
headers = {
   
   
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3",
    "Cookie": "your_cookie_data"  # 这里替换为实际的cookie
}

# 初始化队列和锁
queue = Queue()
lock = threading.Lock()

# 多线程数据采集函数
def fetch_data(url):
    with lock:  # 使用锁确保线程安全
        try:
            response = requests.get(url, headers=headers, proxies=proxies)
            if response.status_code == 200:
                # 将数据放入队列
                queue.put(response.text)
                print(f"成功采集数据:{url}")
            else:
                print(f"采集失败:{url},状态码:{response.status_code}")
        except Exception as e:
            print(f"请求发生错误:{e}")

# 解析个人简历信息并存储为文档
def parse_and_save(html_content, resume_id):
    soup = BeautifulSoup(html_content, 'html.parser')

    # 假设的简历字段,实际需要根据51job的页面结构进行调整
    name = soup.find('div', class_='name').text.strip() if soup.find('div', class_='name') else "未提供"
    contact = soup.find('div', class_='contact').text.strip() if soup.find('div', class_='contact') else "未提供"
    experience = soup.find('div', class_='experience').text.strip() if soup.find('div', class_='experience') else "未提供"

    # 构建简历信息文本
    resume_content = f"姓名: {name}\n联系方式: {contact}\n工作经验: {experience}\n"

    # 将简历信息保存到文档
    with open(f'resume_{resume_id}.txt', 'w', encoding='utf-8') as file:
        file.write(resume_content)

    print(f"简历 {resume_id} 已保存.")

# 多线程爬虫实现
def multi_thread_scraping(url_list):
    threads = []
    resume_id = 1
    for url in url_list:
        thread = threading.Thread(target=fetch_data, args=(url,))
        thread.start()
        threads.append(thread)

    for thread in threads:
        thread.join()

    # 读取Queue内容并处理数据
    while not queue.empty():
        html_content = queue.get()
        parse_and_save(html_content, resume_id)
        resume_id += 1

# 示例URL列表(假设这些URL指向简历页面)
urls = [
    "https://www.51job.com/resume_example1",
    "https://www.51job.com/resume_example2",
    "https://www.51job.com/resume_example3",
    # 添加更多简历URL
]

# 启动多线程爬虫
multi_thread_scraping(urls)

代码说明:

  1. 代理和请求设置:代码中使用亿牛云爬虫代理,并设置了User-Agent和Cookie以模拟正常用户访问。
  2. 多线程采集:使用多线程来提高采集效率,将从51job.com采集到的HTML内容放入队列中。
  3. 简历解析:通过BeautifulSoup解析HTML内容,提取简历信息。这里假设简历包含姓名、联系方式、和工作经验的字段,实际解析时需要根据页面实际结构进行调整。
  4. 保存为文档:将提取的简历信息以文本文件的形式存储,每个简历对应一个文件,文件名格式为resume_x.txt
  5. 多线程实现:通过启动多个线程来并发执行数据采集任务,并在队列中依次处理采集到的数据。

结论

在Python中,确保Queue的线程和进程安全性对于构建高效稳定的爬虫系统至关重要。本文通过一个使用锁的多线程爬虫示例,展示了如何在网络数据采集中使用代理IP、user-agent和cookie,并结合锁机制实现对Queue的安全操作。
通过合理使用锁和多线程技术,可以大幅提升数据采集的效率,同时避免在并发环境下可能出现的数据竞争问题。

相关文章
|
8天前
|
安全 Java 调度
Java编程时多线程操作单核服务器可以不加锁吗?
Java编程时多线程操作单核服务器可以不加锁吗?
22 2
|
8天前
|
存储 消息中间件 资源调度
「offer来了」进程线程有啥关系?10个知识点带你巩固操作系统基础知识
该文章总结了操作系统基础知识中的十个关键知识点,涵盖了进程与线程的概念及区别、进程间通信方式、线程同步机制、死锁现象及其预防方法、进程状态等内容,并通过具体实例帮助理解这些概念。
「offer来了」进程线程有啥关系?10个知识点带你巩固操作系统基础知识
|
7天前
|
资源调度 算法 调度
深入浅出操作系统之进程与线程管理
【9月更文挑战第29天】在数字世界的庞大舞台上,操作系统扮演着不可或缺的角色,它如同一位精通多门艺术的导演,精心指挥着每一个进程和线程的演出。本文将通过浅显的语言,带你走进操作系统的内心世界,探索进程和线程的管理奥秘,让你对这位幕后英雄有更深的了解。
|
11天前
|
Java
直接拿来用:进程&进程池&线程&线程池
直接拿来用:进程&进程池&线程&线程池
|
9天前
|
Python
5-5|python开启多线程入口必须在main,从python线程(而不是main线程)启动pyQt线程有什么坏处?...
5-5|python开启多线程入口必须在main,从python线程(而不是main线程)启动pyQt线程有什么坏处?...
|
7天前
|
数据采集 消息中间件 并行计算
进程、线程与协程:并发执行的三种重要概念与应用
进程、线程与协程:并发执行的三种重要概念与应用
17 0
|
7天前
|
数据采集 Linux 调度
Python之多线程与多进程
Python之多线程与多进程
13 0
|
7天前
|
并行计算 关系型数据库 MySQL
30天拿下Python之使用多线程
30天拿下Python之使用多线程
18 0
|
11天前
|
存储 算法 Java
关于python3的一些理解(装饰器、垃圾回收、进程线程协程、全局解释器锁等)
该文章深入探讨了Python3中的多个重要概念,包括装饰器的工作原理、垃圾回收机制、进程与线程的区别及全局解释器锁(GIL)的影响等,并提供了详细的解释与示例代码。
15 0
|
11天前
|
安全 Java 调度
python3多线程实战(python3经典编程案例)
该文章提供了Python3中多线程的应用实例,展示了如何利用Python的threading模块来创建和管理线程,以实现并发执行任务。
12 0
下一篇
无影云桌面