MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

Python实现HTTP请求的基础

2024-08-093.7k 阅读

一、HTTP 请求基础概述

(一)HTTP 协议简介

HTTP(Hyper - Text Transfer Protocol)即超文本传输协议,它是用于在万维网上进行数据传输的应用层协议。HTTP 基于客户端 - 服务器模型,客户端发起请求,服务器响应请求。它以明文形式传输数据,工作在 TCP/IP 协议栈之上,默认端口为 80(HTTPS 为 443)。

HTTP 协议的请求和响应都有特定的格式。请求由请求行、请求头、空行和请求体组成。例如,一个简单的 GET 请求:

GET /index.html HTTP/1.1
Host: example.com

这里 GET 是请求方法,/index.html 是请求的资源路径,HTTP/1.1 是协议版本,Host 是请求头字段。

响应则由状态行、响应头、空行和响应体组成。例如:

HTTP/1.1 200 OK
Content - Type: text/html
Content - Length: 1234

<!DOCTYPE html>
<html>
...
</html>

HTTP/1.1 是协议版本,200 OK 是状态码和原因短语,后面的 Content - Type 等是响应头字段,后面的 HTML 内容就是响应体。

(二)常见 HTTP 请求方法

  1. GET
    • GET 方法用于从服务器获取资源。请求的参数附加在 URL 后面,以 ? 分隔 URL 和参数,参数之间用 & 连接。例如:http://example.com/api?param1=value1&param2=value2
    • GET 方法的特点是参数会暴露在 URL 中,长度有限制(不同浏览器和服务器限制不同,一般在 2000 字符左右),并且 GET 请求一般会被浏览器缓存,适合获取数据且数据量较小的场景,比如获取文章详情页面。
  2. POST
    • POST 方法用于向服务器提交数据,数据包含在请求体中。它不会像 GET 那样将参数暴露在 URL 中,适合提交敏感信息或大数据量的场景,如用户登录、文件上传等。
    • 例如,在用户登录时,POST 请求体可能包含用户名和密码等信息,服务器接收并处理这些数据。
  3. PUT
    • PUT 方法用于更新服务器上的资源。它和 POST 的区别在于,PUT 通常用于完整地替换资源,而 POST 可能用于部分更新或创建新资源。
    • 比如,当更新用户的完整信息时,可以使用 PUT 方法将用户的所有信息发送到服务器进行替换更新。
  4. DELETE
    • DELETE 方法用于删除服务器上的资源。通过发送 DELETE 请求到指定资源的 URL,服务器根据请求删除相应资源。例如,删除数据库中的一条记录,可以使用 DELETE 请求。

二、Python 实现 HTTP 请求的常用库

(一)urllib 库

  1. 简介
    • urllib 是 Python 内置的 HTTP 请求库,它提供了一系列处理 URL 的功能。urllib 库在 Python 3 中主要包含 urllib.requesturllib.errorurllib.parse 等模块。urllib.request 用于发送请求和获取响应,urllib.error 用于处理请求过程中产生的错误,urllib.parse 用于解析和构造 URL。
  2. 发送 GET 请求
    • 示例代码如下:
import urllib.request

url = 'http://httpbin.org/get'
response = urllib.request.urlopen(url)
data = response.read()
print(data.decode('utf - 8'))
  • 在上述代码中,首先导入 urllib.request 模块。然后定义了要请求的 URL,使用 urllib.request.urlopen 方法发送 GET 请求,该方法返回一个类似文件对象的响应对象。通过调用 read 方法读取响应内容,最后使用 decode 方法将字节数据解码为字符串并打印。
  1. 发送带参数的 GET 请求
    • 如果要发送带参数的 GET 请求,需要使用 urllib.parse 模块来构造 URL。示例如下:
import urllib.request
import urllib.parse

base_url = 'http://httpbin.org/get'
params = {'param1': 'value1', 'param2': 'value2'}
encoded_params = urllib.parse.urlencode(params)
full_url = base_url + '?' + encoded_params
response = urllib.request.urlopen(full_url)
data = response.read()
print(data.decode('utf - 8'))
  • 这里先定义了参数 params,使用 urllib.parse.urlencode 方法将参数编码为 URL 可识别的格式,然后将编码后的参数附加到基础 URL 上,最后发送请求并获取响应。
  1. 发送 POST 请求
    • 发送 POST 请求时,需要将数据编码后作为 urlopen 方法的第二个参数传递。示例代码如下:
import urllib.request
import urllib.parse

url = 'http://httpbin.org/post'
data = {'param1': 'value1', 'param2': 'value2'}
encoded_data = urllib.parse.urlencode(data).encode('utf - 8')
req = urllib.request.Request(url, data = encoded_data)
response = urllib.request.urlopen(req)
data = response.read()
print(data.decode('utf - 8'))
  • 首先定义了 POST 请求的数据 data,编码后使用 urllib.request.Request 创建请求对象,将编码后的数据作为 data 参数传入。然后通过 urlopen 发送请求并获取响应。

(二)requests 库

  1. 简介
    • requests 库是 Python 中一个非常流行的第三方 HTTP 请求库,它以简洁易用的 API 而受到广泛欢迎。相比 urllib 库,requests 库的代码更加简洁明了,处理各种请求和响应的功能更加强大。可以通过 pip install requests 来安装该库。
  2. 发送 GET 请求
    • 示例代码如下:
import requests

url = 'http://httpbin.org/get'
response = requests.get(url)
print(response.text)
  • 导入 requests 库后,使用 requests.get 方法发送 GET 请求,response 对象包含了服务器的响应信息,通过 response.text 可以获取响应的文本内容。
  1. 发送带参数的 GET 请求
    • 代码如下:
import requests

base_url = 'http://httpbin.org/get'
params = {'param1': 'value1', 'param2': 'value2'}
response = requests.get(base_url, params = params)
print(response.text)
  • 这里直接将参数以字典形式作为 params 参数传递给 requests.get 方法,requests 库会自动将参数编码并附加到 URL 上。
  1. 发送 POST 请求
    • 示例代码:
import requests

url = 'http://httpbin.org/post'
data = {'param1': 'value1', 'param2': 'value2'}
response = requests.post(url, data = data)
print(response.text)
  • 使用 requests.post 方法发送 POST 请求,将数据以字典形式作为 data 参数传递即可。
  1. 处理响应
    • requests 库的响应对象有很多有用的属性。例如,response.status_code 可以获取响应的状态码,response.headers 可以获取响应头信息。示例如下:
import requests

url = 'http://httpbin.org/get'
response = requests.get(url)
print('Status Code:', response.status_code)
print('Headers:', response.headers)
  • 这段代码获取了响应的状态码和响应头并打印出来。

三、设置 HTTP 请求头

(一)为什么要设置请求头

HTTP 请求头包含了关于请求的元数据,如客户端信息、请求的内容类型、期望的响应类型等。设置合适的请求头可以让服务器更好地理解客户端的需求,同时也可以模拟不同的客户端行为。例如,设置 User - Agent 请求头可以模拟不同的浏览器,有些网站会根据 User - Agent 来返回不同格式的内容。

(二)urllib 库设置请求头

  1. 使用 Request 对象设置请求头
    • 以发送 GET 请求并设置 User - Agent 请求头为例,代码如下:
import urllib.request

url = 'http://httpbin.org/get'
headers = {'User - Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'}
req = urllib.request.Request(url, headers = headers)
response = urllib.request.urlopen(req)
data = response.read()
print(data.decode('utf - 8'))
  • 首先定义了 headers 字典,包含了 User - Agent 信息。然后使用 urllib.request.Request 创建请求对象,将 headers 作为参数传入,最后发送请求并获取响应。

(三)requests 库设置请求头

  1. 直接在请求方法中设置请求头
    • 同样以设置 User - Agent 请求头为例,代码如下:
import requests

url = 'http://httpbin.org/get'
headers = {'User - Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'}
response = requests.get(url, headers = headers)
print(response.text)
  • requests.get 方法中直接将 headers 字典作为参数传入,就可以设置请求头。这种方式比 urllib 库更加简洁。

四、处理 HTTPS 请求

(一)HTTPS 协议基础

HTTPS(Hyper - Text Transfer Protocol Secure)是 HTTP 的安全版本,它通过 SSL/TLS 协议对传输的数据进行加密,保证数据传输的安全性。当客户端发起 HTTPS 请求时,服务器会返回数字证书,客户端验证证书的合法性后,双方协商加密算法并建立安全连接。

(二)urllib 库处理 HTTPS 请求

  1. 默认验证证书
    • urllib 库在处理 HTTPS 请求时,默认会验证服务器的证书。示例如下:
import urllib.request

url = 'https://www.baidu.com'
response = urllib.request.urlopen(url)
data = response.read()
print(data.decode('utf - 8'))
  • 这段代码发送了一个 HTTPS 请求到百度,urllib.request.urlopen 方法会自动验证百度服务器的证书,如果证书合法则获取响应内容。
  1. 忽略证书验证(不推荐在生产环境使用)
    • 在某些测试场景下,可能需要忽略证书验证。可以使用 ssl 模块来实现。代码如下:
import urllib.request
import ssl

context = ssl._create_unverified_context()
url = 'https://example.com'
response = urllib.request.urlopen(url, context = context)
data = response.read()
print(data.decode('utf - 8'))
  • 这里使用 ssl._create_unverified_context() 创建了一个不验证证书的上下文对象,然后将其作为 context 参数传递给 urlopen 方法。但这种方式会带来安全风险,不建议在生产环境使用。

(三)requests 库处理 HTTPS 请求

  1. 默认验证证书
    • requests 库默认也会验证服务器的证书。示例代码:
import requests

url = 'https://www.baidu.com'
response = requests.get(url)
print(response.text)
  • 同样发送一个 HTTPS 请求到百度,requests.get 方法会验证证书,如果证书合法则获取响应内容。
  1. 忽略证书验证(不推荐在生产环境使用)
    • 可以通过设置 verify 参数为 False 来忽略证书验证。代码如下:
import requests

url = 'https://example.com'
response = requests.get(url, verify = False)
print(response.text)
  • 但和 urllib 库一样,这种方式在生产环境中存在安全风险,因为它无法保证通信的安全性,可能会遭受中间人攻击。

五、处理 HTTP 响应中的数据

(一)解析文本响应

  1. HTML 响应解析
    • 当服务器返回 HTML 格式的响应时,可以使用 BeautifulSoup 库来解析 HTML。首先需要安装 BeautifulSoup,可以通过 pip install beautifulsoup4 安装。示例代码如下:
import requests
from bs4 import BeautifulSoup

url = 'http://example.com'
response = requests.get(url)
soup = BeautifulSoup(response.text, 'html.parser')
title = soup.title.string
print('Title:', title)
  • 这里发送 GET 请求获取响应,然后使用 BeautifulSoup 将响应文本解析为可操作的对象。通过 soup.title.string 获取 HTML 页面的标题。
  1. JSON 响应解析
    • 很多 API 会返回 JSON 格式的数据。requests 库可以方便地解析 JSON 响应。示例代码如下:
import requests

url = 'http://httpbin.org/json'
response = requests.get(url)
data = response.json()
print(data)
  • 使用 response.json() 方法将 JSON 格式的响应内容解析为 Python 的字典或列表对象,方便后续处理。

(二)处理二进制响应(如文件下载)

  1. 下载图片
    • 以下是使用 requests 库下载图片的示例代码:
import requests

url = 'http://example.com/image.jpg'
response = requests.get(url, stream = True)
with open('image.jpg', 'wb') as f:
    for chunk in response.iter_content(chunk_size = 8192):
        if chunk:
            f.write(chunk)
  • 设置 stream = True 可以避免一次性将整个响应内容加载到内存中。通过 response.iter_content 方法以指定的块大小迭代响应内容,并写入文件。
  1. 下载其他二进制文件(如 PDF)
    • 下载 PDF 文件的代码和下载图片类似,只需要修改 URL 和保存的文件名。示例如下:
import requests

url = 'http://example.com/document.pdf'
response = requests.get(url, stream = True)
with open('document.pdf', 'wb') as f:
    for chunk in response.iter_content(chunk_size = 8192):
        if chunk:
            f.write(chunk)
  • 同样以流的方式下载 PDF 文件,提高内存使用效率。

六、处理 HTTP 请求错误

(一)urllib 库的错误处理

  1. 捕获 HTTP 错误
    • urllib 库通过 urllib.error.HTTPError 来捕获 HTTP 错误。示例代码如下:
import urllib.request
import urllib.error

url = 'http://httpbin.org/status/404'
try:
    response = urllib.request.urlopen(url)
    data = response.read()
    print(data.decode('utf - 8'))
except urllib.error.HTTPError as e:
    print('HTTP Error:', e.code)
  • 这里尝试访问一个返回 404 状态码的 URL,使用 try - except 块捕获 HTTPError,并打印错误状态码。
  1. 捕获 URL 错误
    • 当 URL 格式不正确或无法连接到服务器时,会抛出 urllib.error.URLError。示例如下:
import urllib.request
import urllib.error

url = 'http://invalid - url'
try:
    response = urllib.request.urlopen(url)
    data = response.read()
    print(data.decode('utf - 8'))
except urllib.error.URLError as e:
    print('URL Error:', e.reason)
  • 这里尝试访问一个无效的 URL,捕获 URLError 并打印错误原因。

(二)requests 库的错误处理

  1. 检查响应状态码
    • requests 库可以通过 response.status_code 检查响应状态码,并进行相应处理。示例如下:
import requests

url = 'http://httpbin.org/status/404'
response = requests.get(url)
if response.status_code!= 200:
    print('Request failed with status code:', response.status_code)
else:
    print('Response content:', response.text)
  • 这里检查响应状态码,如果不是 200,则打印错误信息,否则打印响应内容。
  1. 使用 raise_for_status 方法
    • requests 库的 response.raise_for_status() 方法会在状态码不是 200 时抛出异常。示例代码如下:
import requests

url = 'http://httpbin.org/status/404'
response = requests.get(url)
try:
    response.raise_for_status()
    print('Response content:', response.text)
except requests.exceptions.HTTPError as e:
    print('HTTP Error:', e)
  • 使用 try - except 块捕获 HTTPError,如果状态码不是 200,会抛出异常并打印错误信息。这种方式可以更简洁地处理 HTTP 错误。