如何通过 QNetworkAccessManager 等待两个异步下载完成?
How do I wait for two asynchronous downloads to finish via QNetworkAccessManager?
===总结======================================= ==
我使用 QNetworkAccessManager 和 QNetworkRequests 同时下载两个图像。我如何确定两次下载已完成?
===详细说明===============================
我有两个图像的 URL,我想异步下载它们。为此,我初始化 QNetworkAccessManager 并使用两个 QNetworkRequest。完成后,每个请求都会将图像的内容写入文件。
问题是两个请求彼此一无所知,因此,无法验证另一个请求是否完成。
你能告诉我吗我怎样才能等待两个请求完成?
完整代码如下:
import sys
from PyQt5.QtCore import QUrl, QFile, QIODevice
from PyQt5.QtNetwork import QNetworkAccessManager, QNetworkRequest
from PyQt5.QtWidgets import QApplication, QWidget
class MainWindow(QWidget):
def __init__(self):
super(MainWindow, self).__init__()
img_url1 = "https://somesite.com/image1.jpg"
img_url2 = "https://somesite.com/image2.jpg"
self.downloader = QNetworkAccessManager()
self.requests = []
self.temp_files = []
for index, mediafile_url in enumerate([img_url1, img_url2]):
self.requests.append(self.downloader.get(QNetworkRequest(QUrl(mediafile_url))))
request = self.requests[index]
self.temp_files.append(QFile(f'{mediafile_url.split("/")[-1]}'))
temp_file = self.temp_files[index]
request.finished.connect(lambda *args, r=request, tf=temp_file: self.download_image(r, tf))
self.show()
@staticmethod
def download_image(request, temp_file):
image_data = request.readAll()
temp_file.open(QIODevice.WriteOnly)
temp_file.write(image_data)
temp_file.close()
app = QApplication(sys.argv)
window = MainWindow()
app.exec_()
您必须创建一个 class 来跟踪下载:
from dataclasses import dataclass
import sys
from PyQt5.QtCore import pyqtSignal, QObject, QUrl, QFile, QIODevice
from PyQt5.QtNetwork import QNetworkAccessManager, QNetworkRequest, QNetworkReply
from PyQt5.QtWidgets import QApplication, QWidget
@dataclass
class DownloadRequest:
url: QUrl
filename: str
class DownloadManager(QObject):
finished = pyqtSignal()
def __init__(self, parent=None):
super().__init__(parent)
self._manager = QNetworkAccessManager()
self._pending_downloads = 0
self.manager.finished.connect(self.handle_finished)
@property
def manager(self):
return self._manager
@property
def pending_downloads(self):
return self._pending_downloads
def download(self, requests):
for request in requests:
qrequest = QNetworkRequest(request.url)
qrequest.setAttribute(QNetworkRequest.User, request.filename)
self.manager.get(qrequest)
self._pending_downloads += 1
def handle_finished(self, reply):
self._pending_downloads -= 1
if reply.error() != QNetworkReply.NoError:
print(f"code: {reply.error()} message: {reply.errorString()}")
else:
print("successful")
filename = reply.attribute(QNetworkRequest.User)
file = QFile(filename)
if file.open(QIODevice.WriteOnly):
file.write(reply.readAll())
print(f"pending downloads {self.pending_downloads}")
if self.pending_downloads == 0:
self.finished.emit()
class MainWindow(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self._manager = DownloadManager()
self._manager.finished.connect(self.handle_finished)
img_url1 = "https://docs.python.org/3/_static/py.png"
img_url2 = "https://somesite.com/image2.jpg"
request1 = DownloadRequest(QUrl(img_url1), img_url1.split("/")[-1])
request2 = DownloadRequest(QUrl(img_url2), img_url2.split("/")[-1])
self._manager.download([request1, request2])
def handle_finished(self):
print("finished")
def main():
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()
if __name__ == "__main__":
main()
===总结======================================= ==
我使用 QNetworkAccessManager 和 QNetworkRequests 同时下载两个图像。我如何确定两次下载已完成?
===详细说明===============================
我有两个图像的 URL,我想异步下载它们。为此,我初始化 QNetworkAccessManager 并使用两个 QNetworkRequest。完成后,每个请求都会将图像的内容写入文件。
问题是两个请求彼此一无所知,因此,无法验证另一个请求是否完成。
你能告诉我吗我怎样才能等待两个请求完成?
完整代码如下:
import sys
from PyQt5.QtCore import QUrl, QFile, QIODevice
from PyQt5.QtNetwork import QNetworkAccessManager, QNetworkRequest
from PyQt5.QtWidgets import QApplication, QWidget
class MainWindow(QWidget):
def __init__(self):
super(MainWindow, self).__init__()
img_url1 = "https://somesite.com/image1.jpg"
img_url2 = "https://somesite.com/image2.jpg"
self.downloader = QNetworkAccessManager()
self.requests = []
self.temp_files = []
for index, mediafile_url in enumerate([img_url1, img_url2]):
self.requests.append(self.downloader.get(QNetworkRequest(QUrl(mediafile_url))))
request = self.requests[index]
self.temp_files.append(QFile(f'{mediafile_url.split("/")[-1]}'))
temp_file = self.temp_files[index]
request.finished.connect(lambda *args, r=request, tf=temp_file: self.download_image(r, tf))
self.show()
@staticmethod
def download_image(request, temp_file):
image_data = request.readAll()
temp_file.open(QIODevice.WriteOnly)
temp_file.write(image_data)
temp_file.close()
app = QApplication(sys.argv)
window = MainWindow()
app.exec_()
您必须创建一个 class 来跟踪下载:
from dataclasses import dataclass
import sys
from PyQt5.QtCore import pyqtSignal, QObject, QUrl, QFile, QIODevice
from PyQt5.QtNetwork import QNetworkAccessManager, QNetworkRequest, QNetworkReply
from PyQt5.QtWidgets import QApplication, QWidget
@dataclass
class DownloadRequest:
url: QUrl
filename: str
class DownloadManager(QObject):
finished = pyqtSignal()
def __init__(self, parent=None):
super().__init__(parent)
self._manager = QNetworkAccessManager()
self._pending_downloads = 0
self.manager.finished.connect(self.handle_finished)
@property
def manager(self):
return self._manager
@property
def pending_downloads(self):
return self._pending_downloads
def download(self, requests):
for request in requests:
qrequest = QNetworkRequest(request.url)
qrequest.setAttribute(QNetworkRequest.User, request.filename)
self.manager.get(qrequest)
self._pending_downloads += 1
def handle_finished(self, reply):
self._pending_downloads -= 1
if reply.error() != QNetworkReply.NoError:
print(f"code: {reply.error()} message: {reply.errorString()}")
else:
print("successful")
filename = reply.attribute(QNetworkRequest.User)
file = QFile(filename)
if file.open(QIODevice.WriteOnly):
file.write(reply.readAll())
print(f"pending downloads {self.pending_downloads}")
if self.pending_downloads == 0:
self.finished.emit()
class MainWindow(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self._manager = DownloadManager()
self._manager.finished.connect(self.handle_finished)
img_url1 = "https://docs.python.org/3/_static/py.png"
img_url2 = "https://somesite.com/image2.jpg"
request1 = DownloadRequest(QUrl(img_url1), img_url1.split("/")[-1])
request2 = DownloadRequest(QUrl(img_url2), img_url2.split("/")[-1])
self._manager.download([request1, request2])
def handle_finished(self):
print("finished")
def main():
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()
if __name__ == "__main__":
main()