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 请求方法
- GET
- GET 方法用于从服务器获取资源。请求的参数附加在 URL 后面,以
?
分隔 URL 和参数,参数之间用&
连接。例如:http://example.com/api?param1=value1¶m2=value2
。 - GET 方法的特点是参数会暴露在 URL 中,长度有限制(不同浏览器和服务器限制不同,一般在 2000 字符左右),并且 GET 请求一般会被浏览器缓存,适合获取数据且数据量较小的场景,比如获取文章详情页面。
- GET 方法用于从服务器获取资源。请求的参数附加在 URL 后面,以
- POST
- POST 方法用于向服务器提交数据,数据包含在请求体中。它不会像 GET 那样将参数暴露在 URL 中,适合提交敏感信息或大数据量的场景,如用户登录、文件上传等。
- 例如,在用户登录时,POST 请求体可能包含用户名和密码等信息,服务器接收并处理这些数据。
- PUT
- PUT 方法用于更新服务器上的资源。它和 POST 的区别在于,PUT 通常用于完整地替换资源,而 POST 可能用于部分更新或创建新资源。
- 比如,当更新用户的完整信息时,可以使用 PUT 方法将用户的所有信息发送到服务器进行替换更新。
- DELETE
- DELETE 方法用于删除服务器上的资源。通过发送 DELETE 请求到指定资源的 URL,服务器根据请求删除相应资源。例如,删除数据库中的一条记录,可以使用 DELETE 请求。
二、Python 实现 HTTP 请求的常用库
(一)urllib 库
- 简介
urllib
是 Python 内置的 HTTP 请求库,它提供了一系列处理 URL 的功能。urllib
库在 Python 3 中主要包含urllib.request
、urllib.error
、urllib.parse
等模块。urllib.request
用于发送请求和获取响应,urllib.error
用于处理请求过程中产生的错误,urllib.parse
用于解析和构造 URL。
- 发送 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
方法将字节数据解码为字符串并打印。
- 发送带参数的 GET 请求
- 如果要发送带参数的 GET 请求,需要使用
urllib.parse
模块来构造 URL。示例如下:
- 如果要发送带参数的 GET 请求,需要使用
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 上,最后发送请求并获取响应。
- 发送 POST 请求
- 发送 POST 请求时,需要将数据编码后作为
urlopen
方法的第二个参数传递。示例代码如下:
- 发送 POST 请求时,需要将数据编码后作为
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 库
- 简介
requests
库是 Python 中一个非常流行的第三方 HTTP 请求库,它以简洁易用的 API 而受到广泛欢迎。相比urllib
库,requests
库的代码更加简洁明了,处理各种请求和响应的功能更加强大。可以通过pip install requests
来安装该库。
- 发送 GET 请求
- 示例代码如下:
import requests
url = 'http://httpbin.org/get'
response = requests.get(url)
print(response.text)
- 导入
requests
库后,使用requests.get
方法发送 GET 请求,response
对象包含了服务器的响应信息,通过response.text
可以获取响应的文本内容。
- 发送带参数的 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 上。
- 发送 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
参数传递即可。
- 处理响应
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 库设置请求头
- 使用 Request 对象设置请求头
- 以发送 GET 请求并设置
User - Agent
请求头为例,代码如下:
- 以发送 GET 请求并设置
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 库设置请求头
- 直接在请求方法中设置请求头
- 同样以设置
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 请求
- 默认验证证书
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
方法会自动验证百度服务器的证书,如果证书合法则获取响应内容。
- 忽略证书验证(不推荐在生产环境使用)
- 在某些测试场景下,可能需要忽略证书验证。可以使用
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 请求
- 默认验证证书
requests
库默认也会验证服务器的证书。示例代码:
import requests
url = 'https://www.baidu.com'
response = requests.get(url)
print(response.text)
- 同样发送一个 HTTPS 请求到百度,
requests.get
方法会验证证书,如果证书合法则获取响应内容。
- 忽略证书验证(不推荐在生产环境使用)
- 可以通过设置
verify
参数为False
来忽略证书验证。代码如下:
- 可以通过设置
import requests
url = 'https://example.com'
response = requests.get(url, verify = False)
print(response.text)
- 但和
urllib
库一样,这种方式在生产环境中存在安全风险,因为它无法保证通信的安全性,可能会遭受中间人攻击。
五、处理 HTTP 响应中的数据
(一)解析文本响应
- HTML 响应解析
- 当服务器返回 HTML 格式的响应时,可以使用
BeautifulSoup
库来解析 HTML。首先需要安装BeautifulSoup
,可以通过pip install beautifulsoup4
安装。示例代码如下:
- 当服务器返回 HTML 格式的响应时,可以使用
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 页面的标题。
- JSON 响应解析
- 很多 API 会返回 JSON 格式的数据。
requests
库可以方便地解析 JSON 响应。示例代码如下:
- 很多 API 会返回 JSON 格式的数据。
import requests
url = 'http://httpbin.org/json'
response = requests.get(url)
data = response.json()
print(data)
- 使用
response.json()
方法将 JSON 格式的响应内容解析为 Python 的字典或列表对象,方便后续处理。
(二)处理二进制响应(如文件下载)
- 下载图片
- 以下是使用
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
方法以指定的块大小迭代响应内容,并写入文件。
- 下载其他二进制文件(如 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 库的错误处理
- 捕获 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
,并打印错误状态码。
- 捕获 URL 错误
- 当 URL 格式不正确或无法连接到服务器时,会抛出
urllib.error.URLError
。示例如下:
- 当 URL 格式不正确或无法连接到服务器时,会抛出
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 库的错误处理
- 检查响应状态码
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,则打印错误信息,否则打印响应内容。
- 使用 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 错误。