PyQt QNetworkAccessManager
最后修改于 2023 年 8 月 24 日
在本文中,我们将展示如何使用 QNetworkAccessManager 来发送请求和接收响应。
访问 ,阅读 PyQt6 教程,或列出所有 PyQt 教程。
QNetworkAccessManager
QNetworkAccessManager 允许应用程序发送网络请求并接收回复。QNetworkRequest 持有要通过网络管理器发送的请求,而 QNetworkReply 包含响应返回的数据和标头。
QNetworkAccessManager 有一个异步 API,这意味着它的方法总是立即返回,而不会等待它们完成。相反,当请求完成时,会发出一个信号。我们在附加到 finished 信号的方法中处理响应。
HTTP GET 请求
HTTP GET 方法请求指定资源的表示形式。
#!/usr/bin/python
from PyQt6 import QtNetwork
from PyQt6.QtCore import QCoreApplication, QUrl
import sys
class Example:
def __init__(self):
self.doRequest()
def doRequest(self):
url = 'http://webcode.me'
req = QtNetwork.QNetworkRequest(QUrl(url))
self.nam = QtNetwork.QNetworkAccessManager()
self.nam.finished.connect(self.handleResponse)
self.nam.get(req)
def handleResponse(self, reply):
er = reply.error()
if er == QtNetwork.QNetworkReply.NetworkError.NoError:
bytes_string = reply.readAll()
print(str(bytes_string, 'utf-8'))
else:
print("Error occured: ", er)
print(reply.errorString())
QCoreApplication.quit()
def main():
app = QCoreApplication([])
ex = Example()
sys.exit(app.exec())
if __name__ == '__main__':
main()
该示例检索指定网页的 HTML 代码。
url = 'http://webcode.me' req = QtNetwork.QNetworkRequest(QUrl(url))
我们使用 QNetworkRequest 向指定的 URL 发送请求。
self.nam = QtNetwork.QNetworkAccessManager() self.nam.finished.connect(self.handleResponse) self.nam.get(req)
创建一个 QNetworkAccessManager 对象。当请求完成时,调用 handleResponse 方法。请求通过 get 方法发出。
def handleResponse(self, reply):
er = reply.error()
if er == QtNetwork.QNetworkReply.NetworkError.NoError:
bytes_string = reply.readAll()
print(str(bytes_string, 'utf-8'))
else:
print("Error occured: ", er)
print(reply.errorString())
QCoreApplication.quit()
handleResponse 接收一个 QNetworkReply 对象。它包含已发送请求的数据和标头。如果网络回复中没有错误,我们使用 readAll 方法读取所有数据;否则我们打印一条错误消息。errorString 返回对最后发生的错误的人类可读描述。readAll 返回 QByteArray 格式的数据,需要进行解码。
$ ./get_request.py
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My html page</title>
</head>
<body>
<p>
Today is a beautiful day. We go swimming and fishing.
</p>
<p>
Hello there. How are you?
</p>
</body>
</html>
HTTP POST 请求
HTTP POST 方法向服务器发送数据。请求正文的类型由 Content-Type 标头指示。POST 请求通常通过 HTML 表单发送。请求中发送的数据可以用不同的方式编码;在 application/x-www-form-urlencoded 中,值被编码为由 '&' 分隔的键值元组,键和值之间用 '=' 连接。非字母数字字符会进行百分比编码。multipart/form-data 用于二进制数据和文件上传。
#!/usr/bin/python
from PyQt6 import QtNetwork
from PyQt6 import QtCore
import sys, json
class Example:
def __init__(self):
self.doRequest()
def doRequest(self):
data = QtCore.QByteArray()
data.append(b'name=Peter&')
data.append(b'age=34')
url = 'https://httpbin.org/post'
req = QtNetwork.QNetworkRequest(QtCore.QUrl(url))
req.setHeader(QtNetwork.QNetworkRequest.KnownHeaders.ContentTypeHeader,
'application/x-www-form-urlencoded')
self.nam = QtNetwork.QNetworkAccessManager()
self.nam.finished.connect(self.handleResponse)
self.nam.post(req, data)
def handleResponse(self, reply):
er = reply.error()
if er == QtNetwork.QNetworkReply.NetworkError.NoError:
bytes_string = reply.readAll()
json_ar = json.loads(str(bytes_string, 'utf-8'))
data = json_ar['form']
print(f"Name: {data['name']}")
print(f"Age: {data['age']}")
print()
else:
print('Error occurred: ', er)
print(reply.errorString())
QtCore.QCoreApplication.quit()
def main():
app = QtCore.QCoreApplication([])
ex = Example()
sys.exit(app.exec())
if __name__ == '__main__':
main()
该示例向测试网站 https://httpbin.org/post 发送一个 post 请求,该网站会以 JSON 格式将数据返回。
data = QtCore.QByteArray() data.append(b'name=Peter&') data.append(b'age=34')
根据规范,我们对发送的数据在 QByteArray 中进行编码。
url = 'https://httpbin.org/post'
req = QtNetwork.QNetworkRequest(QtCore.QUrl(url))
req.setHeader(QtNetwork.QNetworkRequest.KnownHeaders.ContentTypeHeader,
'application/x-www-form-urlencoded')
我们指定 application/x-www-form-urlencoded 编码类型。
bytes_string = reply.readAll()
json_ar = json.loads(str(bytes_string, 'utf-8'))
data = json_ar['form']
print(f"Name: {data['name']}")
print(f"Age: {data['age']}")
print()
在处理方法中,我们读取响应数据并对其进行解码。我们使用内置的 json 模块来提取已提交的数据。
$ ./post_request.py Name: Peter Age: 34
QNetworkAccessManager 身份验证
每当最终服务器在传递所请求的内容之前请求身份验证时,就会发出 authenticationRequired 信号。
#!/usr/bin/python
from PyQt6 import QtCore, QtNetwork
import sys, json
class Example:
def __init__(self):
self.doRequest()
def doRequest(self):
self.auth = 0
url = 'https://httpbin.org/basic-auth/user7/passwd7'
req = QtNetwork.QNetworkRequest(QtCore.QUrl(url))
self.nam = QtNetwork.QNetworkAccessManager()
self.nam.authenticationRequired.connect(self.authenticate)
self.nam.finished.connect(self.handleResponse)
self.nam.get(req)
def authenticate(self, reply, auth):
print('Authenticating')
self.auth += 1
if self.auth >= 3:
reply.abort()
auth.setUser('user7')
auth.setPassword('passwd7')
def handleResponse(self, reply):
er = reply.error()
if er == QtNetwork.QNetworkReply.NetworkError.NoError:
bytes_string = reply.readAll()
data = json.loads(str(bytes_string, 'utf-8'))
print(f"Authenticated: {data['authenticated']}")
print(f"User: {data['user']}")
print()
else:
print('Error occurred: ', er)
print(reply.errorString())
QtCore.QCoreApplication.quit()
def main():
app = QtCore.QCoreApplication([])
ex = Example()
sys.exit(app.exec())
if __name__ == '__main__':
main()
在该示例中,我们使用 https://httpbin.org 网站来展示如何使用 QNetworkAccessManager 进行身份验证。
self.nam.authenticationRequired.connect(self.authenticate)
我们将 authenticationRequired 信号连接到 authenticate 方法。
def authenticate(self, reply, auth):
print('Authenticating')
...
authenticate 方法的第三个参数是 QAuthenticator,它用于传递所需的身份验证信息。
self.auth += 1
if self.auth >= 3:
reply.abort()
如果身份验证失败,QNetworkAccessManager 会持续发出 authenticationRequired 信号。我们在三次失败尝试后中止该过程。
auth.setUser('user7')
auth.setPassword('passwd7')
我们将用户和密码设置到 QAuthenticator 中。
bytes_string = reply.readAll()
data = json.loads(str(bytes_string, 'utf-8'))
print(f"Authenticated: {data['authenticated']}")
print(f"User: {data['user']}")
print()
https://httpbin.org 以 JSON 数据响应,其中包含用户名和一个指示身份验证是否成功的布尔值。
$ ./authentication.py Authenticating Authenticated: True User: user7
使用 QNetworkAccessManager 获取网站图标 (favicon)
网站图标 (favicon) 是与特定网站相关联的小图标。在下面的示例中,我们将从一个网站下载一个网站图标。
#!/usr/bin/python
from PyQt6 import QtCore, QtNetwork
import sys
class Example:
def __init__(self):
self.doRequest()
def doRequest(self):
url = 'http://webcode.me/favicon.ico'
req = QtNetwork.QNetworkRequest(QtCore.QUrl(url))
self.nam = QtNetwork.QNetworkAccessManager()
self.nam.finished.connect(self.handleResponse)
self.nam.get(req)
def handleResponse(self, reply):
er = reply.error()
if er == QtNetwork.QNetworkReply.NetworkError.NoError:
data = reply.readAll()
self.saveFile(data)
else:
print('Error occured: ', er)
print(reply.errorString())
QtCore.QCoreApplication.quit()
def saveFile(self, data):
f = open('favicon.ico', 'wb')
with f:
f.write(data)
def main():
app = QtCore.QCoreApplication([])
ex = Example()
sys.exit(app.exec())
if __name__ == '__main__':
main()
该代码示例下载了谷歌的网站图标。
self.nam.get(req)
我们使用 get 方法下载图标。
data = reply.readAll() self.saveFile(data)
在 handleResponse 方法中,我们读取数据并将其保存到文件中。
def saveFile(self, data):
f = open('favicon.ico', 'wb')
with f:
f.write(data)
图像数据在 saveFile 方法中被保存在磁盘上。
在本文中,我们学习了如何使用 QNetworkAccessManager。
作者
列出所有 PyQt 教程。