You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python多进程爬取车辆数据报错:无法pickle _thread.RLock对象

解决二手车数据爬取的多进程问题

嘿,我来帮你搞定这个爬取效率拉胯和多进程踩坑的问题!你的场景太典型了——单进程爬取速度感人,想转多进程又接连碰壁,咱们一步步拆解解决。

一、先搞定multiprocessing.Process的Pickle错误

问题根源

你遇到的TypeError: can't pickle _thread.RLock objects,90%的概率是因为你把**带锁的对象(比如requests.Session实例)**直接传给了子进程。requests的Session内部用了_thread.RLock来保证线程安全,而这个对象是没法被pickle序列化的——多进程之间传递数据必须序列化,自然就报错了。

解决方案

别在主进程创建Session,让每个子进程自己初始化独立的Session!这样既避开了序列化问题,还能让每个进程拥有专属的连接池,爬取效率反而更高。

示例代码:

import multiprocessing
import requests
from bs4 import BeautifulSoup  # 假设你用这个解析页面

def crawl_single_url(url):
    # 子进程内部单独创建Session
    session = requests.Session()
    try:
        response = session.get(url, timeout=15)
        response.raise_for_status()  # 主动抛出HTTP错误
        # 这里写你的解析逻辑,提取154种车辆属性
        data = parse_car_info(response.text)
        return data
    except Exception as e:
        print(f"爬取{url}失败: {str(e)}")
        return None
    finally:
        session.close()

def parse_car_info(html):
    soup = BeautifulSoup(html, "html.parser")
    # 示例:提取品牌、价格等属性,根据实际页面结构调整
    car_data = {
        "brand": soup.find("div", class_="brand").text.strip(),
        "price": soup.find("span", class_="price").text.strip(),
        # 剩下152种属性的提取逻辑...
    }
    return car_data

if __name__ == "__main__":
    # 假设你已经有了包含28万条URL的列表
    urls = ["https://example.com/car1", "https://example.com/car2", ...]
    processes = []
    max_concurrent = 20  # 根据你的CPU核心数调整,比如8核就开16-20个进程

    # 分批处理URL,避免一次性启动太多进程
    for batch_start in range(0, len(urls), max_concurrent):
        batch_urls = urls[batch_start:batch_start+max_concurrent]
        for url in batch_urls:
            p = multiprocessing.Process(target=crawl_single_url, args=(url,))
            p.start()
            processes.append(p)
        # 等待当前批次的进程全部完成,再处理下一批
        for p in processes:
            p.join()
        processes.clear()

二、解决multiprocessing.Pool在Jupyter Notebook无限卡住的问题

问题根源

Jupyter的运行环境和普通Python脚本不一样——它的主进程已经在交互式环境中运行,multiprocessing.Pool的启动机制(尤其是Windows下的spawn模式)会和Jupyter的事件循环冲突,导致进程彻底卡住。

解决方案

给你三个靠谱的解决办法,按推荐程度排序:

1. 用concurrent.futures.ProcessPoolExecutor替代multiprocessing.Pool

concurrent.futures是更上层的封装API,在Jupyter里的兼容性好得多,写法也更简洁:

from concurrent.futures import ProcessPoolExecutor
import multiprocessing
import requests

def crawl_single_url(url):
    # 和上面爬取逻辑一致
    session = requests.Session()
    try:
        response = session.get(url, timeout=15)
        data = parse_car_info(response.text)
        return data
    except Exception as e:
        print(f"爬取{url}失败: {str(e)}")
        return None
    finally:
        session.close()

def parse_car_info(html):
    # 你的解析逻辑
    pass

def save_to_db(data):
    # 示例:把数据保存到数据库或文件
    pass

if __name__ == "__main__":
    urls = ["https://example.com/car1", ...]
    # 进程数设为CPU核心数的2-4倍,平衡CPU和网络IO
    max_workers = multiprocessing.cpu_count() * 3

    with ProcessPoolExecutor(max_workers=max_workers) as executor:
        # 批量提交爬取任务
        results = executor.map(crawl_single_url, urls)
        # 逐个处理返回结果
        for result in results:
            if result:
                save_to_db(result)

2. 给multiprocessing.Pool指定启动方式(仅Windows)

如果你非要用multiprocessing.Pool,可以在代码开头强制设置启动方式为spawn,并且确保所有逻辑都在if __name__ == "__main__"块里:

import multiprocessing
# 强制设置启动方式为spawn,适配Windows和Jupyter环境
multiprocessing.set_start_method('spawn')

def crawl_single_url(url):
    # 爬取逻辑同上
    pass

if __name__ == "__main__":
    urls = ["https://example.com/car1", ...]
    with multiprocessing.Pool(processes=multiprocessing.cpu_count()*3) as pool:
        results = pool.map(crawl_single_url, urls)
        # 处理结果

3. 用Jupyter魔法命令脱离交互式环境

把你的多进程代码写成独立的Python脚本,然后用Jupyter的%%script魔法命令运行,彻底避开Jupyter主进程的干扰:

%%script python
import multiprocessing
import requests

def crawl_single_url(url):
    # 爬取逻辑
    pass

if __name__ == "__main__":
    urls = ["https://example.com/car1", ...]
    with multiprocessing.Pool() as pool:
        pool.map(crawl_single_url, urls)

三、额外的效率优化建议

  • 控制并发数:别贪多开几十上百个进程,一般CPU核心数的2-4倍就够了,太多会导致CPU上下文切换频繁,反而拖慢速度。
  • 代理IP池:如果爬取频繁被网站限制,一定要加代理池,避免IP被封导致大量失败请求。
  • 异步+多进程结合:如果你的爬取瓶颈是网络IO,可以用aiohttp做异步爬取,再配合多进程,效率能再上一个台阶。
  • 结果批量保存:别爬一条存一条,攒几十条再批量写入数据库/文件,减少IO开销。

内容的提问来源于stack exchange,提问作者Orhan Solak

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 04:22:33