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

如何从实例化DownloadHandler的Crawler类持续获取更新后的new_files值?

问题:爬虫GUI无法更新Watchdog监控的下载计数

我开发了一个带GUI的Selenium网络爬虫Crawler,GUI会显示当前URL、爬虫深度和已下载文件数量。原本用requests下载文件时,完成后会直接让计数+1,一切正常。

最近新增了处理需要JS交互才能下载的文件的功能:用Watchdog监控下载目录,通过DownloadHandler类记录新增文件。现在文件监控功能正常,但GUI里的“已下载”计数始终无法更新——从Crawler类访问dl_handler.new_files时,数值一直是0。

精简代码示例

DownloadHandler初始版本

class DownloadHandler:
    def __init__(self):
        self.new_files = 0

    def handle_download(self):
        do_stuff()
        self.new_files += 1

Crawler类调用方式

class Crawler:
    def __init__(self):
        self.dl_handler = DownloadHandler()

问题表现

>>>print(self.dl_handler.new_files)
>>>output: 0

完整Watchdog相关代码

class DownloadHandler(Observer):
    def __init__(self, temp_dir):
        self.temp_dir = 'PATH'
        self.new_files = 0

    def handle_download(self):
        do_stuff()
        self.new_files += 1

    def monitor_directory(self):
        event_handler = MyHandler(self.temp_dir)
        observer = Observer()
        observer.schedule(event_handler, path=self.temp_dir.name, recursive=False)
        observer.start()

class MyHandler(DownloadHandler, FileSystemEventHandler):
    def __init__(temp_dir):
        self.temp_dir = temp_dir
    def on_created(self, event):
        if not re.search(r'.*crdownload$|\.com\.google\.Chrome.*', event.src_path) and event.src_path != self.temp_dir.name:
            try:
                self.handle_download()
            except FileNotFoundError as e:
                pass

问题根源

核心错误是对象实例不共享:MyHandler是DownloadHandler的子类,在monitor_directory里新建的MyHandler实例,和Crawler持有的dl_handler不是同一个对象。Watchdog触发事件时,调用的是MyHandler实例的handle_download,累加的是该实例的new_files,而Crawler读取的是自身持有的DownloadHandler实例的new_files,自然一直为0。

另外还有两个小问题:

  • MyHandler的__init__方法缺少self参数,且未调用父类构造函数,会导致属性初始化异常
  • DownloadHandler继承Observer后又在方法内新建Observer实例,设计冗余

修复方案

方案1:复用同一个DownloadHandler实例(推荐)

不让MyHandler继承DownloadHandler,而是将Crawler持有的DownloadHandler实例传给MyHandler,确保事件触发时操作的是同一个对象:

from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
import re

class DownloadHandler:
    def __init__(self, temp_dir):
        self.temp_dir = temp_dir
        self.new_files = 0
        self.observer = Observer()

    def handle_download(self):
        # 这里编写文件处理逻辑
        self.new_files += 1
        # 若需更新GUI,可在此触发回调
        print(f"已新增文件,当前计数:{self.new_files}")

    def start_monitoring(self):
        event_handler = MyHandler(self)
        self.observer.schedule(event_handler, path=self.temp_dir.name, recursive=False)
        self.observer.start()

    def stop_monitoring(self):
        self.observer.stop()
        self.observer.join()

class MyHandler(FileSystemEventHandler):
    def __init__(self, download_handler):
        self.download_handler = download_handler

    def on_created(self, event):
        if not event.is_directory and not re.search(r'.*crdownload$|\.com\.google\.Chrome.*', event.src_path):
            try:
                self.download_handler.handle_download()
            except FileNotFoundError as e:
                pass

# Crawler调用示例
class Crawler:
    def __init__(self, temp_dir):
        self.dl_handler = DownloadHandler(temp_dir)
        self.dl_handler.start_monitoring()

    def check_download_count(self):
        print(f"当前已下载文件数:{self.dl_handler.new_files}")

方案2:使用类属性共享计数(适合简单场景)

将new_files设为类属性,让所有实例共享同一个值:

class DownloadHandler(Observer):
    new_files = 0  # 类属性,所有实例共享
    def __init__(self, temp_dir):
        super().__init__()
        self.temp_dir = temp_dir

    def handle_download(self):
        do_stuff()
        DownloadHandler.new_files += 1

# 访问时直接调用类属性
>>>print(DownloadHandler.new_files)

额外:GUI实时更新建议

在DownloadHandler中加入GUI更新回调,每次计数变化时直接触发界面更新:

class DownloadHandler:
    def __init__(self, temp_dir, update_gui_callback):
        self.temp_dir = temp_dir
        self.new_files = 0
        self.observer = Observer()
        self.update_gui = update_gui_callback

    def handle_download(self):
        self.new_files += 1
        self.update_gui(self.new_files)  # 触发GUI更新

在Crawler初始化时传入GUI的更新方法,即可实现计数变化时实时同步界面。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 03:45:49