实战PyQt5: 130-使用HTTP请求下载文件( 三 )
测试试代码以pyqt5-examples样例代码为基础 ,演示了如何使用QNetworkAccessManager , QNetworkRequest , QNetworkReply 从网站中下载文件并保存在本地 。完整代码如下:
import sysfrom PyQt5.QtCore import Qt, QDir, QFile, QFileInfo, QIODevice, QUrlfrom PyQt5.QtWidgets import (QApplication, QDialog, QDialogButtonBox,QHBoxLayout, QVBoxLayout, QLabel, QLineEdit,QProgressDialog, QMessageBox, QPushButton)from PyQt5.QtNetwork import QNetworkAccessManager, QNetworkRequest,QNetworkReply class DemoDownloadFile(QDialog):def __init__(self, parent=None):super(DemoDownloadFile, self).__init__(parent)# 设置窗口标题self.setWindowTitle('实战 Qt for Python: 文件下载')# 设置窗口大小self.resize(400, 120)self.url = QUrl()self.nam = QNetworkAccessManager()self.reply = Noneself.outFile = Noneself.httpGetId = 0self.httpRequestAborted = Falseself.initUi()def initUi(self):#编辑下载地址self.urlLineEdit = QLineEdit('')urlLabel = QLabel('网址(&U):')urlLabel.setBuddy(self.urlLineEdit)#状态信息self.statusLabel = QLabel('在这里输入要下载的文件的网址 。 ')self.statusLabel.setWordWrap(True)#下载和退出按钮self.btnDownload = QPushButton('下载')self.btnDownload.setDefault(True)self.btnQuit = QPushButton('退出')self.btnQuit.setAutoDefault(False)buttonBox = QDialogButtonBox()buttonBox.addButton(self.btnDownload, QDialogButtonBox.ActionRole)buttonBox.addButton(self.btnQuit, QDialogButtonBox.RejectRole)#进度显示对话框self.progressDialog = None#连接slot函数self.urlLineEdit.textChanged.connect(self.enableDownloadButton)self.nam.authenticationRequired.connect(self.slotAuthenticationRequired)self.nam.sslErrors.connect(self.sslErrors)self.btnDownload.clicked.connect(self.downloadFile)self.btnQuit.clicked.connect(self.close)topLayout = QHBoxLayout()topLayout.addWidget(urlLabel)topLayout.addWidget(self.urlLineEdit)mainLayout = QVBoxLayout()mainLayout.setSpacing(16)mainLayout.addLayout(topLayout)mainLayout.addWidget(self.statusLabel)mainLayout.addWidget(buttonBox)mainLayout.addStretch(1)self.setLayout(mainLayout)self.urlLineEdit.setFocus()#发出下载请求def startRequest(self, url):self.reply = self.nam.get(QNetworkRequest(url))self.reply.finished.connect(self.httpFinished)self.reply.readyRead.connect(self.httpReadyRead)self.reply.downloadProgress.connect(self.updateDataReadProgress)#下载文件def downloadFile(self):self.url = QUrl(self.urlLineEdit.text())fileInfo = QFileInfo(self.url.path())filename = fileInfo.fileName()#如果没有文件名 , 就假定一个缺省文件if not filename:filename = 'index.html'#如果存储目录有相同文件名称 , 则询问是否覆盖if QFile.exists(filename):ret = QMessageBox.question(self, '下载文件','在当前目录下已经存着文件 %s 。 覆盖它吗?' % filename,QMessageBox.Yes | QMessageBox.No, QMessageBox.No)if ret == QMessageBox.No:return#删除原来的文件QFile.remove(filename)self.outFile = QFile(filename)if not self.outFile.open(QIODevice.WriteOnly):QMessageBox.information(self, '下载文件','不能保存文件 %s: %s.' % (filename, self.outFile.errorString()))self.outFile = Nonereturnself.progressDialog = QProgressDialog(self)self.progressDialog.canceled.connect(self.cancelDownload)self.progressDialog.setWindowTitle('下载文件')self.progressDialog.setLabelText('正在下载 %s.' % filename)self.btnDownload.setEnabled(False)self.httpRequestAborted = Falseself.startRequest(self.url)#终止下载def cancelDownload(self):self.statusLabel.setText('下载被取消了.')self.httpRequestAborted = Trueif self.reply is not None:self.reply.abort()self.btnDownload.setEnabled(True)#下载完成后def httpFinished(self):#释放进度对话框if self.progressDialog is not None:self.progressDialog.hide()self.progressDialog.deleteLater()self.progressDialog = None#如果被终止下载了 , 做相应的善后处理if self.httpRequestAborted:if self.outFile is not None:self.outFile.close()self.outFile.remove()self.outFile = Noneself.reply.deleteLater()self.reply = Nonereturnself.outFile.flush()self.outFile.close()redirectionTarget = self.reply.attribute(QNetworkRequest.RedirectionTargetAttribute)if self.reply.error():self.outFile.remove()QMessageBox.information(self, '文件下载','下载失败: %s.' % self.reply.errorString())self.btnDownload.setEnabled(True)elif redirectionTarget is not None:newUrl = self.url.resolved(redirectionTarget)ret = QMessageBox.question(self, '下载文件', '重定向到文件 %s?' % newUrl.toString(),QMessageBox.Yes | QMessageBox.No)if ret == QMessageBox.Yes:self.url = newUrlself.reply.deleteLater()self.reply = Noneself.outFile.open(QIODevice.WriteOnly)self.outFile.resize(0)self.startRequest(self.url)returnelse:filename = QFileInfo(QUrl(self.urlLineEdit.text()).path()).fileName()self.statusLabel.setText('文件 %s 下载到 %s.' % (filename, QDir.currentPath()))self.btnDownload.setEnabled(True)self.reply.deleteLater()self.reply = Noneself.outFile = None#保存下载的数据def httpReadyRead(self):if self.outFile is not None:self.outFile.write(self.reply.readAll())#更新进度对话框的进度显示信息def updateDataReadProgress(self, bytesRead, totalBytes):if self.httpRequestAborted:returnif self.progressDialog is not None:self.progressDialog.setMaximum(totalBytes)self.progressDialog.setValue(bytesRead)#下载地址发生了改变 , 如果地址为空 , 则禁用下载按钮 , 否则启用def enableDownloadButton(self):self.btnDownload.setEnabled(self.urlLineEdit.text() != '')#处理许可下载信息def slotAuthenticationRequired(self, authenticator):import osfrom PyQt5 import uicui = os.path.join(os.path.dirname(__file__), 'authenticationdialog.ui')dlg = uic.loadUi(ui)dlg.adjustSize()dlg.siteDescription.setText('%s at %s' % (authenticator.realm(), self.url.host()))dlg.userEdit.setText(self.url.userName())dlg.passwordEdit.setText(self.url.password())if dlg.exec() == QDialog.Accepted:authenticator.setUser(dlg.userEdit.text())authenticator.setPassword(dlg.passwordEdit.text())#SSL 错误处理def sslErrors(self, reply, errors):errorString = ", ".join([str(error.errorString()) for error in errors])ret = QMessageBox.warning(self, 'HTTP 文件下载示例','发生了SSL错误: %s' % errorString,QMessageBox.Ignore | QMessageBox.Abort)if ret == QMessageBox.Ignore:self.reply.ignoreSslErrors()if __name__ == '__main__':app = QApplication(sys.argv)window = DemoDownloadFile()window.show()sys.exit(app.exec())
- Wireshark数据包分析实战:TCP报文段重组
- Python爬虫采集网易云音乐热评实战
- Django实战016:django中使用redis详解
- HTTP实战之Wireshark抓包分析
- Wireshark数据包分析实战:网卡卸载
- Python数据分析:数据可视化实战教程
- 实战经验:电商平台遭遇CC攻击,我们是如何应对的?
- Tencent IN对话 | 八位互联网实战家,实战智慧营销商学院
- HLS实战之Wireshark抓包分析
- Vue实战091:Vue项目部署到nginx服务器