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

爬虫程序陷入死循环无法终止,请求排查解决

亚马逊土耳其站爬虫死循环问题排查与修复

问题概述

基于Python开发的亚马逊土耳其站爬虫,使用requests、BeautifulSoup和multiprocessing.Pool实现批量商品数据爬取,设计逻辑为每次批量处理12页数据(如1-12页、13-24页依次推进),但主进程main函数中的while循环始终无法终止,陷入死循环。

核心原因

  1. 主进程无终止触发逻辑:传入main函数的loop变量始终为True,没有任何逻辑修改该值,导致while循环无限执行。
  2. 子进程终止不影响主进程:urlAmazon函数中,检测到页面无分页容器时调用exit(),仅终止当前子进程,无法将“无更多页面”的信号传递给主进程,主进程仍会继续创建新的爬取任务。
  3. 额外潜在问题:多进程直接写入同一个文件products.txt存在竞态条件,可能导致内容错乱;exit()终止子进程的方式不够优雅,易引发资源泄漏。

修复方案

1. 子进程返回状态,主进程控制循环终止

将urlAmazon中的exit()替换为返回布尔值,标记当前页面是否存在分页容器(即是否还有更多页面)。主进程收集所有子进程的返回结果,若存在任意一个子进程返回“无更多页面”,则设置loop为False终止循环。

2. 处理多进程异步任务结果

使用apply_async的get()方法获取子进程的返回值,判断是否需要终止主循环。

3. 解决多进程文件写入竞态问题

使用multiprocessing.Lock确保同一时间只有一个进程写入文件,避免内容错乱。

修改后完整代码

from selenium import webdriver
import requests
from bs4 import BeautifulSoup
import time
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
from multiprocessing.pool import Pool
from multiprocessing import Lock

# 初始化文件锁,解决多进程写文件竞态问题
file_lock = Lock()

def urlAmazon(url=str(), paging_method=int()):
    headers = {"user-agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36"}
    url = url.format(paging_method)
    req = requests.get(url, headers=headers)
    soup = BeautifulSoup(req.content, "lxml")
    
    # 捕获页面结构变化导致的异常
    try:
        productList = soup.find("div","s-main-slot s-result-list s-search-results sg-row").findAll("div","sg-col-4-of-24 sg-col-4-of-12 s-result-item s-asin sg-col-4-of-16 sg-col s-widget-spacing-small sg-col-4-of-20")
    except AttributeError:
        productList = []
    
    # 检查是否存在分页容器,返回布尔值给主进程
    has_pagination = bool(soup.find("div","a-section a-text-center s-pagination-container"))
    
    print(paging_method, len(productList))
    for product in productList:
        try:
            productName = product.find("h2").getText(strip=True)
        except AttributeError:
            productName = "Unknown Product"
        try:
            productPrice = product.find("span","a-offscreen").getText(strip=True)
        except:
            productPrice = None
        
        # 使用文件锁确保安全写入
        with file_lock:
            with open("products.txt","a",encoding="UTF-8") as f:
                f.write(f"{productName}: {productPrice} - {paging_method}\n")
    
    return has_pagination

def main(pool):  
    page = 1  
    url = "https://www.amazon.com.tr/s?i=electronics&bbn=13709880031&rh=n%3A13709880031%2Cp_n_fulfilled_by_amazon%3A21345978031&dc&page={}&rnid=21345970031&ref=sr_pg_2"        
    loop = True
    
    while loop:
        results = []
        # 提交12页的爬取任务
        for i in range(11,-1,-1):           
            p = pool.apply_async(func=urlAmazon, args=[url, 12*page - i])
            results.append(p)
        
        # 等待所有子进程完成,获取返回结果
        has_more_pages = all([res.get() for res in results])
        # 若有任意一个页面无分页,则终止循环
        if not has_more_pages:
            loop = False
        
        page += 1
    
    print("End of the code")
    
if __name__ == '__main__': 
    pool = Pool()
    start = time.perf_counter()    
    main(pool)
    # 关闭进程池,等待所有子进程完成
    pool.close()
    pool.join()
    finish = time.perf_counter()
    print(f"Total time: {round(finish-start,2)} seconds")

关键修改点说明

  • 子进程状态返回:urlAmazon不再调用exit(),而是返回has_pagination布尔值,告知主进程当前页面是否存在分页。
  • 主进程循环控制:主进程等待当前批次所有子进程完成,若任意子进程返回False(无分页),则设置loop=False终止循环。
  • 文件写入安全:添加multiprocessing.Lock,确保多进程下文件写入的原子性,避免内容错乱。
  • 进程池资源清理:主进程结束前调用pool.close()和pool.join(),确保所有子进程完成后再退出,避免资源泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 15:29:57