在本教程中,我们展示了如何使用Python请求模块。我们获取数据、发布数据、流式传输数据,并连接到安全网页。在示例中,我们使用在线服务、Nginx服务器、PythonHTTP服务器和Flask应用程序。
ZetCode还有一个简明的Python教程。
超文本传输协议(HTTP)是分布式协作超媒体信息系统的应用协议。HTTP是万维网数据通信的基础。
Python请求
Requests
是一个简单而优雅的PythonHTTP库。它提供了通过HTTP访问Web资源的方法。
$ sudo service nginx start
我们在本地主机上运行Nginx网络服务器。我们的一些示例使用nginx
服务器。
Python请求版本
第一个程序打印请求库的版本。
#!/usr/bin/python import requests print(requests.__version__) print(requests.__copyright__)
程序打印请求的版本和版权。
$ ./version.py 2.21.0 Copyright 2018 Kenneth Reitz
这是示例的示例输出。
Python请求读取网页
get
方法发出GET请求;它获取由给定URL标识的文档。
#!/usr/bin/python import requests as req resp = req.get("http://www.webcode.me") print(resp.text)
脚本抓取www.webcode.me
网页的内容。
resp = req.get("http://www.webcode.me")
get
方法返回一个响应对象。
print(resp.text)
text属性包含响应的内容,采用Unicode。
$ ./read_webpage.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>
这是read_webpage.py
脚本的输出。
以下程序获取一个小网页并去除其HTML标签。
#!/usr/bin/python import requests as req import re resp = req.get("http://www.webcode.me") content = resp.text stripped = re.sub('<[^<]+?>', '', content) print(stripped)
该脚本去除了www.webcode.me
网页的HTML标签。
stripped = re.sub('<[^<]+?>', '', content)
一个简单的正则表达式用于去除HTML标签。
HTTP请求
HTTP请求是从客户端发送到浏览器以检索某些信息或执行某些操作的消息。
Request的
request
方法创建一个新的请求。注意request
模块有一些更高级的方法,比如get
、post
或put
,这为我们节省了一些输入。
#!/usr/bin/python import requests as req resp = req.request(method='GET', url="http://www.webcode.me") print(resp.text)
该示例创建一个GET请求并将其发送到http://www.webcode.me
。
Python请求获取状态
Response
对象包含服务器对HTTP请求的响应。它的status_code
属性返回响应的HTTP状态代码,例如200或404。
#!/usr/bin/python import requests as req resp = req.get("http://www.webcode.me") print(resp.status_code) resp = req.get("http://www.webcode.me/news") print(resp.status_code)
我们使用get
方法执行两个HTTP请求并检查返回的状态。
$ ./get_status.py 200 404
200是成功HTTP请求的标准响应,而404表示无法找到所请求的资源。
Python请求head方法
head
方法检索文档标头。标头由字段组成,包括日期、服务器、内容类型或最后修改时间。
#!/usr/bin/python import requests as req resp = req.head("http://www.webcode.me") print("Server: " + resp.headers['server']) print("Last modified: " + resp.headers['last-modified']) print("Content type: " + resp.headers['content-type'])
该示例打印www.webcode.me
网页的服务器、最后修改时间和内容类型。
$ ./head_request.py Server: nginx/1.6.2 Last modified: Sat, 20 Jul 2019 11:49:25 GMT Content type: text/html
这是head_request.py
程序的输出。
Python请求get方法
get
方法向服务器发出GET请求。GET方法请求指定资源的表示形式。
httpbin.org
是免费提供的HTTP请求和响应服务。
#!/usr/bin/python import requests as req resp = req.get("https://httpbin.org/get?name=Peter") print(resp.text)
脚本将一个带有值的变量发送到httpbin.org
服务器。该变量直接在URL中指定。
$ ./mget.py { "args": { "name": "Peter" }, "headers": { "Accept": "*/*", "Accept-Encoding": "gzip, deflate", "Host": "httpbin.org", "User-Agent": "python-requests/2.21.0" }, ... }
#!/usr/bin/python import requests as req payload = {'name': 'Peter', 'age': 23} resp = req.get("https://httpbin.org/get", params=payload) print(resp.url) print(resp.text)
get
方法接受一个params
参数,我们可以在其中指定查询参数。
payload = {'name': 'Peter', 'age': 23}
数据在Python字典中发送。
resp = req.get("https://httpbin.org/get", params=payload)
我们向httpbin.org
站点发送GET请求并传递在params
参数中指定的数据。
print(resp.url) print(resp.text)
我们将URL和响应内容打印到控制台。
$ ./mget2.py http://httpbin.org/get?name=Peter&age=23 { "args": { "age": "23", "name": "Peter" }, "headers": { "Accept": "*/*", "Accept-Encoding": "gzip, deflate", "Host": "httpbin.org", "User-Agent": "python-requests/2.21.0" }, ... }
Python请求重定向
重定向是将一个URL转发到另一个URL的过程。HTTP响应状态码301MovedPermanently用于永久URL重定向;302Found用于临时重定向。
#!/usr/bin/python import requests as req resp = req.get("https://httpbin.org/redirect-to?url=/") print(resp.status_code) print(resp.history) print(resp.url)
在示例中,我们向https://httpbin.org/redirect-to
页面发出GET请求。该页面重定向到另一个页面;重定向响应存储在响应的history
属性中。
$ ./redirect.py 200 [<Response [302]>] https://httpbin.org/
对https://httpbin.org/redirect-to
的GET请求被302重定向到https://httpbin.org
。
在第二个示例中,我们不遵循重定向。
#!/usr/bin/python import requests as req resp = req.get("https://httpbin.org/redirect-to?url=/", allow_redirects=False) print(resp.status_code) print(resp.url)
allow_redirects
参数指定是否遵循重定向;默认遵循重定向。
$ ./redirect2.py 302 https://httpbin.org/redirect-to?url=/
使用nginx重定向
在下一个示例中,我们将展示如何在nginx服务器中设置页面重定向。
location = /oldpage.html { return 301 /newpage.html; }
将这些行添加到nginx配置文件中,该文件位于Debian上的/etc/nginx/sites-available/default
。
$ sudo service nginx restart
文件编辑完成后,我们必须重启nginx以应用更改。
<!DOCTYPE html> <html> <head> <title>Old page</title> </head> <body> <p> This is old page </p> </body> </html>
这是位于nginx文档根目录中的oldpage.html
文件。
<!DOCTYPE html> <html> <head> <title>New page</title> </head> <body> <p> This is a new page </p> </body> </html>
这是newpage.html
#!/usr/bin/python import requests as req resp = req.get("http://localhost/oldpage.html") print(resp.status_code) print(resp.history) print(resp.url) print(resp.text)
此脚本访问旧页面并遵循重定向。正如我们已经提到的,请求默认遵循重定向。
$ ./redirect3.py 200 (<Response [301]>,) http://localhost/files/newpage.html <!DOCTYPE html> <html> <head> <title>New page</title> </head> <body> <p> This is a new page </p> </body> </html>
$ sudo tail -2 /var/log/nginx/access.log 127.0.0.1 - - [21/Jul/2019:07:41:27 -0400] "GET /oldpage.html HTTP/1.1" 301 184 "-" "python-requests/2.4.3 CPython/3.4.2 Linux/3.16.0-4-amd64" 127.0.0.1 - - [21/Jul/2019:07:41:27 -0400] "GET /newpage.html HTTP/1.1" 200 109 "-" "python-requests/2.4.3 CPython/3.4.2 Linux/3.16.0-4-amd64"
正如我们从access.log
文件中看到的,请求被重定向到一个新的文件名。通信由两个GET请求组成。
用户代理
在本节中,我们指定用户代理的名称。我们创建自己的PythonHTTP服务器。
#!/usr/bin/python from http.server import BaseHTTPRequestHandler, HTTPServer class MyHandler(BaseHTTPRequestHandler): def do_GET(self): message = "Hello there" self.send_response(200) if self.path == '/agent': message = self.headers['user-agent'] self.send_header('Content-type', 'text/html') self.end_headers() self.wfile.write(bytes(message, "utf8")) return def main(): print('starting server on port 8081...') server_address = ('127.0.0.1', 8081) httpd = HTTPServer(server_address, MyHandler) httpd.serve_forever() main()
我们有一个简单的PythonHTTP服务器。
if self.path == '/agent': message = self.headers['user-agent']
如果路径包含'/agent'
,我们返回指定的用户代理。
#!/usr/bin/python import requests as req headers = {'user-agent': 'Python script'} resp = req.get("http://localhost:8081/agent", headers=headers) print(resp.text)
此脚本创建一个简单的GET请求到我们的PythonHTTP服务器。为了向请求添加HTTP标头,我们将字典传递给headers
参数。
headers = {'user-agent': 'Python script'}
标头值放在Python字典中。
resp = req.get("http://localhost:8081/agent", headers=headers)
值被传递给headers
参数。
$ simple_server.py starting server on port 8081...
首先,我们启动服务器。
$ ./user_agent.py Python script
然后我们运行脚本。服务器以我们随请求发送的代理的名称进行响应。
Python请求post值
post
方法在给定的URL上发送POST请求,为填写的表单内容提供键/值对。
#!/usr/bin/python import requests as req data = {'name': 'Peter'} resp = req.post("https://httpbin.org/post", data) print(resp.text)
脚本发送一个带有name
键和Peter
值的请求。POST请求是用post
方法发出的。
$ ./post_value.py { "args": {}, "data": "", "files": {}, "form": { "name": "Peter" }, "headers": { "Accept": "*/*", "Accept-Encoding": "gzip, deflate", "Content-Length": "10", "Content-Type": "application/x-www-form-urlencoded", "Host": "httpbin.org", "User-Agent": "python-requests/2.21.0" }, "json": null, ... }
这是post_value.py
脚本的输出。
Python请求上传图片
在下面的例子中,我们将上传一张图片。我们使用Flask创建一个Web应用程序。
#!/usr/bin/python import os from flask import Flask, request app = Flask(__name__) @app.route("/") def home(): return 'This is home page' @app.route("/upload", methods=['POST']) def handleFileUpload(): msg = 'failed to upload image' if 'image' in request.files: photo = request.files['image'] if photo.filename != '': photo.save(os.path.join('.', photo.filename)) msg = 'image uploaded successfully' return msg if __name__ == '__main__': app.run()
这是一个具有两个端点的简单应用程序。/upload
端点检查是否有一些图像并将其保存到当前目录。
#!/usr/bin/python import requests as req url = 'http://localhost:5000/upload' with open('sid.jpg', 'rb') as f: files = {'image': f} r = req.post(url, files=files) print(r.text)
我们将图像发送到Flask应用程序。该文件在post
方法的files
属性中指定。
JSON
JSON(JavaScript对象表示法)是一种轻量级数据交换格式。易于人类读写,便于机器解析生成。
JSON数据是键/值对的集合;在Python中,它是通过字典来实现的。
读取JSON
在第一个示例中,我们从PHP脚本中读取JSON数据。
<?php $data = [ 'name' => 'Jane', 'age' => 17 ]; header('Content-Type: application/json'); echo json_encode($data);
PHP脚本发送JSON数据。它使用json_encode
函数来完成这项工作。
#!/usr/bin/python import requests as req resp = req.get("http://localhost/send_json.php") print(resp.json())
read_json.py
读取PHP脚本发送的JSON数据。
print(resp.json())
json
方法返回响应的json编码内容(如果有)。
$ ./read_json.py {'age': 17, 'name': 'Jane'}
发送JSON
接下来,我们将JSON数据从Python脚本发送到PHP脚本。
<?php $data = file_get_contents("php://input"); $json = json_decode($data , true); foreach ($json as $key => $value) { if (!is_array($value)) { echo "The $key is $value\n"; } else { foreach ($value as $key => $val) { echo "The $key is $value\n"; } } }
此PHP脚本读取JSON数据并发回包含已解析值的消息。
#!/usr/bin/python import requests as req data = {'name': 'Jane', 'age': 17} resp = req.post("http://localhost/parse_json.php", json=data) print(resp.text)
此脚本将JSON数据发送到PHP应用程序并读取其响应。
data = {'name': 'Jane', 'age': 17}
这是要发送的数据。
resp = req.post("http://localhost/parse_json.php", json=data)
包含JSON数据的字典被传递给json
参数。
$ ./send_json.py The name is Jane The age is 17
这是示例输出。
从字典中检索定义
在下面的示例中,我们在www.dictionary.com中找到了术语的定义。为了解析HTML,我们使用了lxml
模块。
$ pip install lxml
我们使用pip
工具安装lxml
模块。
#!/usr/bin/python import requests as req from lxml import html import textwrap term = "dog" resp = req.get("http://www.dictionary.com/browse/" + term) root = html.fromstring(resp.content) for sel in root.xpath("//span[contains(@class, 'one-click-content')]"): if sel.text: s = sel.text.strip() if (len(s) > 3): print(textwrap.fill(s, width=50))
在此脚本中,我们在www.dictionary.com
上找到术语狗的定义。lxml
模块用于解析HTML代码。
from lxml import html
lxml
模块可用于解析HTML。
import textwrap
textwrap
模块用于将文本按一定宽度换行。
resp = req.get("http://www.dictionary.com/browse/" + term)
要执行搜索,我们会在URL的末尾附加该词。
root = html.fromstring(resp.content)
我们需要使用resp.content
而不是resp.text
因为html.fromstring
隐式期望字节作为输入。(resp.content
以字节为单位返回内容,而resp.text
为Unicode文本。
for sel in root.xpath("//span[contains(@class, 'one-click-content')]"): if sel.text: s = sel.text.strip() if (len(s) > 3): print(textwrap.fill(s, width=50))
我们解析内容。主要定义位于span
标记内,该标记具有one-click-content
属性。我们通过删除过多的空格和杂散字符来改进格式。文本宽度最多为50个字符。请注意,此类解析可能会发生变化。
$ ./get_term.py a domesticated canid, any carnivore of the dog family Canidae, having prominent canine teeth and, in the wild state, a long and slender muzzle, a deep-chested muscular body, a bushy tail, and large, erect ears. ...
这是定义的部分列表。
Python请求流式请求
Streaming正在传输连续的音频和/或视频数据流,同时使用较早的部分。Requests.iter_lines
迭代响应数据,一次一行。在请求上设置stream=True
可避免将内容一次读入内存以获取大量响应。
#!/usr/bin/python import requests as req url = "https://docs.oracle.com/javase/specs/jls/se8/jls8.pdf" local_filename = url.split('/')[-1] r = req.get(url, stream=True) with open(local_filename, 'wb') as f: for chunk in r.iter_content(chunk_size=1024): f.write(chunk)
该示例流式传输PDF文件并将其写入磁盘。
r = req.get(url, stream=True)
在发出请求时将stream
设置为True
,除非我们消耗所有数据或调用Response.close.
with open(local_filename, 'wb') as f: for chunk in r.iter_content(chunk_size=1024): f.write(chunk)
我们以1KB的块读取资源并将它们写入本地文件。
Python请求凭据
auth
参数提供基本的HTTP身份验证;它需要一个名称和密码的元组用于领域。安全域是一种用于保护Web应用程序资源的机制。
$ sudo apt-get install apache2-utils $ sudo htpasswd -c /etc/nginx/.htpasswd user7 New password: Re-type new password: Adding password for user user7
我们使用htpasswd
工具来创建用于基本HTTP身份验证的用户名和密码。
location /secure { auth_basic "Restricted Area"; auth_basic_user_file /etc/nginx/.htpasswd; }
在nginx/etc/nginx/sites-available/default
配置文件中,我们创建了一个安全页面。领域的名称是“限制区域”。
<!DOCTYPE html> <html lang="en"> <head> <title>Secure page</title> </head> <body> <p> This is a secure page. </p> </body> </html>
在/usr/share/nginx/html/secure
目录中,我们有这个HTML文件。
#!/usr/bin/python import requests as req user = 'user7' passwd = '7user' resp = req.get("http://localhost/secure/", auth=(user, passwd)) print(resp.text)
脚本连接到安全网页;它提供访问页面所需的用户名和密码。
$ ./credentials.py <!DOCTYPE html> <html lang="en"> <head> <title>Secure page</title> </head> <body> <p> This is a secure page. </p> </body> </html>
使用正确的凭据,credentials.py
脚本返回安全页面。
在本教程中,我们使用了Python请求模块。
列出所有Python教程。