原文: http://zetcode.com/python/requests/

在本教程中,我们展示了如何使用 Python Requests 模块。 我们获取数据,发布数据,流数据并连接到安全的网页。 在示例中,我们使用在线服务,nginx 服务器,Python HTTP 服务器和 Flask 应用。

ZetCode 也有一个简洁的 Python 教程

超文本传输协议(HTTP)是用于分布式协作超媒体信息系统的应用协议。 HTTP 是万维网数据通信的基础。

Python Requests

Requests 是一个简单优雅的 Python HTTP 库。 它提供了通过 HTTP 访问 Web 资源的方法。 Requests 是内置的 Python 模块。

  1. $ sudo service nginx start

我们在本地主机上运行 nginx Web 服务器。 我们的一些示例使用nginx服务器。

Python Requests 版本

第一个程序打印请求库的版本。

version.py

  1. #!/usr/bin/env python3
  2. import requests
  3. print(requests.__version__)
  4. print(requests.__copyright__)

该程序将打印请求的版本和版权。

  1. $ ./version.py
  2. 2.21.0
  3. Copyright 2018 Kenneth Reitz

这是示例的示例输出。

Python Requests 读取网页

get()方法发出 GET 请求; 它获取由给定 URL 标识的文档。

read_webpage.py

  1. #!/usr/bin/env python3
  2. import requests as req
  3. resp = req.get("http://www.webcode.me")
  4. print(resp.text)

该脚本获取www.webcode.me网页的内容。

  1. resp = req.get("http://www.webcode.me")

get()方法返回一个响应对象。

  1. print(resp.text)

text属性包含响应的内容,以 Unicode 表示。

  1. $ ./read_webpage.py
  2. <!DOCTYPE html>
  3. <html lang="en">
  4. <head>
  5. <meta charset="UTF-8">
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  7. <title>My html page</title>
  8. </head>
  9. <body>
  10. <p>
  11. Today is a beautiful day. We go swimming and fishing.
  12. </p>
  13. <p>
  14. Hello there. How are you?
  15. </p>
  16. </body>
  17. </html>

这是read_webpage.py脚本的输出。

以下程序获取一个小型网页,并剥离其 HTML 标签。

strip_tags.py

  1. #!/usr/bin/env python3
  2. import requests as req
  3. import re
  4. resp = req.get("http://www.webcode.me")
  5. content = resp.text
  6. stripped = re.sub('<[^<]+?>', '', content)
  7. print(stripped)

该脚本会剥离www.webcode.me网页的 HTML 标签。

  1. stripped = re.sub('<[^<]+?>', '', content)

一个简单的正则表达式用于剥离 HTML 标记。

HTTP 请求

HTTP 请求是从客户端发送到浏览器的消息,以检索某些信息或采取某些措施。

Requestrequest方法创建一个新请求。 请注意,request模块具有一些更高级的方法,例如get()post()put(),为我们节省了一些输入。

create_request.py

  1. #!/usr/bin/env python3
  2. import requests as req
  3. resp = req.request(method='GET', url="http://www.webcode.me")
  4. print(resp.text)

该示例创建一个 GET 请求并将其发送到http://www.webcode.me

Python Requests 获取状态

Response对象包含服务器对 HTTP 请求的响应。 其status_code属性返回响应的 HTTP 状态代码,例如 200 或 404。

get_status.py

  1. #!/usr/bin/env python3
  2. import requests as req
  3. resp = req.get("http://www.webcode.me")
  4. print(resp.status_code)
  5. resp = req.get("http://www.webcode.me/news")
  6. print(resp.status_code)

我们使用get()方法执行两个 HTTP 请求,并检查返回的状态。

  1. $ ./get_status.py
  2. 200
  3. 404

200 是成功 HTTP 请求的标准响应,而 404 则表明找不到所请求的资源。

Python Requests HEAD 方法

head()方法检索文档标题。 标头由字段组成,包括日期,服务器,内容类型或上次修改时间。

head_request.py

  1. #!/usr/bin/env python3
  2. import requests as req
  3. resp = req.head("http://www.webcode.me")
  4. print("Server: " + resp.headers['server'])
  5. print("Last modified: " + resp.headers['last-modified'])
  6. print("Content type: " + resp.headers['content-type'])

该示例打印服务器,www.webcode.me网页的上次修改时间和内容类型。

  1. $ ./head_request.py
  2. Server: nginx/1.6.2
  3. Last modified: Sat, 20 Jul 2019 11:49:25 GMT
  4. Content type: text/html

这是head_request.py程序的输出。

Python Requests GET 方法

get()方法向服务器发出 GET 请求。 GET 方法请求指定资源的表示形式。

httpbin.org是免费提供的 HTTP 请求&响应服务。

mget.py

  1. #!/usr/bin/env python3
  2. import requests as req
  3. resp = req.get("https://httpbin.org/get?name=Peter")
  4. print(resp.text)

该脚本将具有值的变量发送到httpbin.org服务器。 该变量直接在 URL 中指定。

  1. $ ./mget.py
  2. {
  3. "args": {
  4. "name": "Peter"
  5. },
  6. "headers": {
  7. "Accept": "*/*",
  8. "Accept-Encoding": "gzip, deflate",
  9. "Host": "httpbin.org",
  10. "User-Agent": "python-requests/2.21.0"
  11. },
  12. ...
  13. }

这是示例的输出。

mget2.py

  1. #!/usr/bin/env python3
  2. import requests as req
  3. payload = {'name': 'Peter', 'age': 23}
  4. resp = req.get("https://httpbin.org/get", params=payload)
  5. print(resp.url)
  6. print(resp.text)

get()方法采用params参数,我们可以在其中指定查询参数。

  1. payload = {'name': 'Peter', 'age': 23}

数据在 Python 字典中发送。

  1. resp = req.get("https://httpbin.org/get", params=payload)

我们将 GET 请求发送到httpbin.org站点,并传递params参数中指定的数据。

  1. print(resp.url)
  2. print(resp.text)

我们将 URL 和响应内容打印到控制台。

  1. $ ./mget2.py
  2. http://httpbin.org/get?name=Peter&age=23
  3. {
  4. "args": {
  5. "age": "23",
  6. "name": "Peter"
  7. },
  8. "headers": {
  9. "Accept": "*/*",
  10. "Accept-Encoding": "gzip, deflate",
  11. "Host": "httpbin.org",
  12. "User-Agent": "python-requests/2.21.0"
  13. },
  14. ...
  15. }

这是示例的输出。

Python Requests 重定向

重定向是将一个 URL 转发到另一个 URL 的过程。 HTTP 响应状态代码 301“永久移动”用于永久 URL 重定向; 302 找到临时重定向。

redirect.py

  1. #!/usr/bin/env python3
  2. import requests as req
  3. resp = req.get("https://httpbin.org/redirect-to?url=/")
  4. print(resp.status_code)
  5. print(resp.history)
  6. print(resp.url)

在示例中,我们向https://httpbin.org/redirect-to页面发出 GET 请求。 该页面重定向到另一个页面; 重定向响应存储在响应的history属性中。

  1. $ ./redirect.py
  2. 200
  3. [<Response [302]>]
  4. https://httpbin.org/

https://httpbin.org/redirect-to的 GET 请求被重定向到https://httpbin.org 302。

在第二个示例中,我们不遵循重定向。

redirect2.py

  1. #!/usr/bin/env python3
  2. import requests as req
  3. resp = req.get("https://httpbin.org/redirect-to?url=/", allow_redirects=False)
  4. print(resp.status_code)
  5. print(resp.url)

allow_redirects参数指定是否遵循重定向。 默认情况下,重定向之后。

  1. $ ./redirect2.py
  2. 302
  3. https://httpbin.org/redirect-to?url=/

这是示例的输出。

用 nginx 重定向

在下一个示例中,我们显示如何在 nginx 服务器中设置页面重定向。

  1. location = /oldpage.html {
  2. return 301 /newpage.html;
  3. }

将这些行添加到位于 Debian 上/etc/nginx/sites-available/default的 Nginx 配置文件中。

  1. $ sudo service nginx restart

编辑完文件后,我们必须重新启动 nginx 才能应用更改。

oldpage.html

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <title>Old page</title>
  5. </head>
  6. <body>
  7. <p>
  8. This is old page
  9. </p>
  10. </body>
  11. </html>

这是位于 nginx 文档根目录中的oldpage.html文件。

newpage.html

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <title>New page</title>
  5. </head>
  6. <body>
  7. <p>
  8. This is a new page
  9. </p>
  10. </body>
  11. </html>

这是newpage.html

redirect3.py

  1. #!/usr/bin/env python3
  2. import requests as req
  3. resp = req.get("http://localhost/oldpage.html")
  4. print(resp.status_code)
  5. print(resp.history)
  6. print(resp.url)
  7. print(resp.text)

该脚本访问旧页面并遵循重定向。 如前所述,默认情况下,请求遵循重定向。

  1. $ ./redirect3.py
  2. 200
  3. (<Response [301]>,)
  4. http://localhost/files/newpage.html
  5. <!DOCTYPE html>
  6. <html>
  7. <head>
  8. <title>New page</title>
  9. </head>
  10. <body>
  11. <p>
  12. This is a new page
  13. </p>
  14. </body>
  15. </html>

这是示例的输出。

  1. $ sudo tail -2 /var/log/nginx/access.log
  2. 127.0.0.1 - - [21/Jul/2019:07:41:27 -0400] "GET /oldpage.html HTTP/1.1" 301 184
  3. "-" "python-requests/2.4.3 CPython/3.4.2 Linux/3.16.0-4-amd64"
  4. 127.0.0.1 - - [21/Jul/2019:07:41:27 -0400] "GET /newpage.html HTTP/1.1" 200 109
  5. "-" "python-requests/2.4.3 CPython/3.4.2 Linux/3.16.0-4-amd64"

access.log文件中可以看到,该请求已重定向到新的文件名。 通信包含两个 GET 请求。

用户代理

在本节中,我们指定用户代理的名称。 我们创建自己的 Python HTTP 服务器。

http_server.py

  1. #!/usr/bin/env python3
  2. from http.server import BaseHTTPRequestHandler, HTTPServer
  3. class MyHandler(BaseHTTPRequestHandler):
  4. def do_GET(self):
  5. message = "Hello there"
  6. self.send_response(200)
  7. if self.path == '/agent':
  8. message = self.headers['user-agent']
  9. self.send_header('Content-type', 'text/html')
  10. self.end_headers()
  11. self.wfile.write(bytes(message, "utf8"))
  12. return
  13. def main():
  14. print('starting server on port 8081...')
  15. server_address = ('127.0.0.1', 8081)
  16. httpd = HTTPServer(server_address, MyHandler)
  17. httpd.serve_forever()
  18. main()

我们有一个简单的 Python HTTP 服务器。

  1. if self.path == '/agent':
  2. message = self.headers['user-agent']

如果路径包含'/agent',则返回指定的用户代理。

user_agent.py

  1. #!/usr/bin/env python3
  2. import requests as req
  3. headers = {'user-agent': 'Python script'}
  4. resp = req.get("http://localhost:8081/agent", headers=headers)
  5. print(resp.text)

该脚本向我们的 Python HTTP 服务器创建一个简单的 GET 请求。 要向请求添加 HTTP 标头,我们将字典传递给headers参数。

  1. headers = {'user-agent': 'Python script'}

标头值放置在 Python 字典中。

  1. resp = req.get("http://localhost:8081/agent", headers=headers)

这些值将传递到headers参数。

  1. $ simple_server.py
  2. starting server on port 8081...

首先,我们启动服务器。

  1. $ ./user_agent.py
  2. Python script

然后我们运行脚本。 服务器使用我们随请求发送的代理名称进行了响应。

Python Requests POST 值

post方法在给定的 URL 上调度 POST 请求,为填写的表单内容提供键/值对。

post_value.py

  1. #!/usr/bin/env python3
  2. import requests as req
  3. data = {'name': 'Peter'}
  4. resp = req.post("https://httpbin.org/post", data)
  5. print(resp.text)

脚本使用具有Peter值的name键发送请求。 POST 请求通过post方法发出。

  1. $ ./post_value.py
  2. {
  3. "args": {},
  4. "data": "",
  5. "files": {},
  6. "form": {
  7. "name": "Peter"
  8. },
  9. "headers": {
  10. "Accept": "*/*",
  11. "Accept-Encoding": "gzip, deflate",
  12. "Content-Length": "10",
  13. "Content-Type": "application/x-www-form-urlencoded",
  14. "Host": "httpbin.org",
  15. "User-Agent": "python-requests/2.21.0"
  16. },
  17. "json": null,
  18. ...
  19. }

这是post_value.py脚本的输出。

Python Requests 上传图像

在以下示例中,我们将上传图片。 我们使用 Flask 创建一个 Web 应用。

app.py

  1. #!/usr/bin/env python3
  2. import os
  3. from flask import Flask, request
  4. app = Flask(__name__)
  5. @app.route("/")
  6. def home():
  7. return 'This is home page'
  8. @app.route("/upload", methods=['POST'])
  9. def handleFileUpload():
  10. msg = 'failed to upload image'
  11. if 'image' in request.files:
  12. photo = request.files['image']
  13. if photo.filename != '':
  14. photo.save(os.path.join('.', photo.filename))
  15. msg = 'image uploaded successfully'
  16. return msg
  17. if __name__ == '__main__':
  18. app.run()

这是具有两个端点的简单应用。 /upload端点检查是否有某些图像并将其保存到当前目录。

upload_file.py

  1. #!/usr/bin/env python3
  2. import requests as req
  3. url = 'http://localhost:5000/upload'
  4. with open('sid.jpg', 'rb') as f:
  5. files = {'image': f}
  6. r = req.post(url, files=files)
  7. print(r.text)

我们将图像发送到 Flask 应用。 该文件在post()方法的files属性中指定。

JSON 格式

JSON (JavaScript 对象表示法)是一种轻量级的数据交换格式。 人类很容易读写,机器也很容易解析和生成。

JSON 数据是键/值对的集合; 在 Python 中,它是通过字典实现的。

读取 JSON

在第一个示例中,我们从 PHP 脚本读取 JSON 数据。

send_json.php

  1. <?php
  2. $data = [ 'name' => 'Jane', 'age' => 17 ];
  3. header('Content-Type: application/json');
  4. echo json_encode($data);

PHP 脚本发送 JSON 数据。 它使用json_encode()函数完成该工作。

read_json.py

  1. #!/usr/bin/env python3
  2. import requests as req
  3. resp = req.get("http://localhost/send_json.php")
  4. print(resp.json())

read_json.py读取 PHP 脚本发送的 JSON 数据。

  1. print(resp.json())

json()方法返回响应的 json 编码内容(如果有)。

  1. $ ./read_json.py
  2. {'age': 17, 'name': 'Jane'}

这是示例的输出。

发送 JSON

接下来,我们将 JSON 数据从 Python 脚本发送到 PHP 脚本。

parse_json.php

  1. <?php
  2. $data = file_get_contents("php://input");
  3. $json = json_decode($data , true);
  4. foreach ($json as $key => $value) {
  5. if (!is_array($value)) {
  6. echo "The $key is $value\n";
  7. } else {
  8. foreach ($value as $key => $val) {
  9. echo "The $key is $value\n";
  10. }
  11. }
  12. }

该 PHP 脚本读取 JSON 数据,并发送带有已解析值的消息。

send_json.py

  1. #!/usr/bin/env python3
  2. import requests as req
  3. data = {'name': 'Jane', 'age': 17}
  4. resp = req.post("http://localhost/parse_json.php", json=data)
  5. print(resp.text)

该脚本将 JSON 数据发送到 PHP 应用并读取其响应。

  1. data = {'name': 'Jane', 'age': 17}

这是要发送的数据。

  1. resp = req.post("http://localhost/parse_json.php", json=data)

包含 JSON 数据的字典将传递给json参数。

  1. $ ./send_json.py
  2. The name is Jane
  3. The age is 17

这是示例输出。

从字典中检索定义

在以下示例中,我们在 www.dictionary.com 上找到术语的定义。 要解析 HTML,我们使用lxml模块。

  1. $ pip install lxml

我们使用pip工具安装lxml模块。

get_term.py

  1. #!/usr/bin/env python3
  2. import requests as req
  3. from lxml import html
  4. import textwrap
  5. term = "dog"
  6. resp = req.get("http://www.dictionary.com/browse/" + term)
  7. root = html.fromstring(resp.content)
  8. for sel in root.xpath("//span[contains(@class, 'one-click-content')]"):
  9. if sel.text:
  10. s = sel.text.strip()
  11. if (len(s) > 3):
  12. print(textwrap.fill(s, width=50))

在此脚本中,我们在www.dictionary.com上找到了术语狗的定义。 lxml模块用于解析 HTML 代码。

注意:包含定义的标签可能会在一夜之间发生变化。 在这种情况下,我们需要调整脚本。

  1. from lxml import html

lxml模块可用于解析 HTML。

  1. import textwrap

textwrap模块用于将文本包装到特定宽度。

  1. resp = req.get("http://www.dictionary.com/browse/" + term)

为了执行搜索,我们在 URL 的末尾附加了该词。

  1. root = html.fromstring(resp.content)

我们需要使用resp.content而不是resp.text,因为html.fromstring()隐式地希望字节作为输入。 (resp.content以字节为单位返回内容,而resp.text以 Unicode 文本形式返回。

  1. for sel in root.xpath("//span[contains(@class, 'one-click-content')]"):
  2. if sel.text:
  3. s = sel.text.strip()
  4. if (len(s) > 3):
  5. print(textwrap.fill(s, width=50))

我们解析内容。 主要定义位于span标签内部,该标签具有one-click-content属性。 我们通过消除多余的空白和杂散字符来改善格式。 文字宽度最大为 50 个字符。 请注意,此类解析可能会更改。

  1. $ ./get_term.py
  2. a domesticated canid,
  3. any carnivore of the dog family Canidae, having
  4. prominent canine teeth and, in the wild state, a
  5. long and slender muzzle, a deep-chested muscular
  6. body, a bushy tail, and large, erect ears.
  7. ...

这是定义的部分列表。

Python Requests 流请求

流正在传输音频和/或视频数据的连续流,同时正在使用较早的部分。 Requests.iter_lines()遍历响应数据,一次一行。 在请求上设置stream=True可以避免立即将内容读取到内存中以获得较大响应。

streaming.py

  1. #!/usr/bin/env python3
  2. import requests as req
  3. url = "https://docs.oracle.com/javase/specs/jls/se8/jls8.pdf"
  4. local_filename = url.split('/')[-1]
  5. r = req.get(url, stream=True)
  6. with open(local_filename, 'wb') as f:
  7. for chunk in r.iter_content(chunk_size=1024):
  8. f.write(chunk)

该示例流式传输 PDF 文件并将其写入磁盘。

  1. r = req.get(url, stream=True)

在发出请求时将stream设置为True,除非我们消耗掉所有数据或调用Response.close(),否则请求无法释放回池的连接。

  1. with open(local_filename, 'wb') as f:
  2. for chunk in r.iter_content(chunk_size=1024):
  3. f.write(chunk)

我们按 1 KB 的块读取资源,并将其写入本地文件。

Python Requests 凭证

auth参数提供基本的 HTTP 认证; 它使用一个元组的名称和密码来用于领域。 安全领域是一种用于保护 Web 应用资源的机制。

  1. $ sudo apt-get install apache2-utils
  2. $ sudo htpasswd -c /etc/nginx/.htpasswd user7
  3. New password:
  4. Re-type new password:
  5. Adding password for user user7

我们使用htpasswd工具创建用于基本 HTTP 认证的用户名和密码。

  1. location /secure {
  2. auth_basic "Restricted Area";
  3. auth_basic_user_file /etc/nginx/.htpasswd;
  4. }

在 nginx /etc/nginx/sites-available/default配置文件中,我们创建一个安全页面。 领域的名称是"Restricted Area"

index.html

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <title>Secure page</title>
  5. </head>
  6. <body>
  7. <p>
  8. This is a secure page.
  9. </p>
  10. </body>
  11. </html>

/usr/share/nginx/html/secure目录中,我们有这个 HTML 文件。

credentials.py

  1. #!/usr/bin/env python3
  2. import requests as req
  3. user = 'user7'
  4. passwd = '7user'
  5. resp = req.get("http://localhost/secure/", auth=(user, passwd))
  6. print(resp.text)

该脚本连接到安全网页; 它提供访问该页面所需的用户名和密码。

  1. $ ./credentials.py
  2. <!DOCTYPE html>
  3. <html lang="en">
  4. <head>
  5. <title>Secure page</title>
  6. </head>
  7. <body>
  8. <p>
  9. This is a secure page.
  10. </p>
  11. </body>
  12. </html>

使用正确的凭据,credentials.py脚本返回受保护的页面。

在本教程中,我们使用了 Python Requests 模块。 您可能对以下相关教程感兴趣: Python 列表推导式Python SimpleJson 教程Python FTP 教程OpenPyXL 教程,[ Python CSV 教程Python 教程

列出所有 Python 教程