本文链接: https://blog.csdn.net/xietansheng/article/details/115557974
0. http 相关模块
Python 官网相关文档:
- http 模块: http — HTTP modules
- http.client: http.client — HTTP protocol client
- http.server: http.server — HTTP servers
- http.cookies: http.cookies — HTTP state management
- http.cookiejar: http.cookiejar — Cookie handling for HTTP clients
- urllib.request: urllib.request — Extensible library for opening URLs
http
是一个包,有多个用于处理 http 协议的模块,如:http.client
,http.server
,http.cookies
,http.cookiejar
。http
模块中通过http.HTTPStatus
枚举定义了一些 HTTP 的状态码,如:HTTPStatus.OK
,HTTPStatus.NOT_FOUND
等。http.client
模块是一个低层级的 HTTP 协议客户端,定义了实现 HTTP 和 HTTPS 协议的客户端类。通常不直接使用该模块,一般使用urllib.request
(用于打开 URL 的可扩展库) 模块来实现 HTTP 和 HTTPS 请求。
1. HTTP 协议客户端: http.client
Python 官网: http.client — HTTP protocol client
1.1 HTTPConnection 对象
Python 官网:
HTTPConnection
/HTTPSConnection
实例表示一个与 HTTP/HTTPS 建立连接的事务,需要传递连接的主机名和端口号,不需要传入具体的 URL 资源路径。
HTTPConnection/HTTPSConnection 的构造方法:
# 创建 HTTP 连接实例
# host: HTTP URL 的 主机名(可以是 "host:port" 的形式, port 会自动读取)
# port: HTTP URL 的 端口, 默认为 80
# timeout: 连接超时时间, 浮点类型的 秒数
# blocksize: 用于发送文件类消息Body的缓冲区大小
class http.client.HTTPConnection(host, port=None, [timeout, ]
source_address=None, blocksize=8192)
# 创建 HTTP 连接实例
# host: HTTPS URL 的 主机名(可以是 "host:port" 的形式, port 会自动读取)
# port: HTTPS URL 的 端口, 默认为 443
# timeout: 连接超时时间, 浮点类型的 秒数
# blocksize: 用于发送文件类消息Body的缓冲区大小
class http.client.HTTPSConnection(host, port=None,
key_file=None, cert_file=None,
[timeout, ]
source_address=None, *, context=None,
check_hostname=None, blocksize=8192)
HTTPConnection 对象中的方法:
# 主动连接 HTTP 服务器, 可以不调用。
# 如果客户端没有建立连接, 该方法将在 request() 时自动被调用。
HTTPConnection.connect()
# 发送 HTTP 请求
#
# method: 请求方法, "GET", "POST" 等
# url: 请求的资源链接(可以只填写资源路径, 如: "/index.html"
# body: 请求的 body, 可以是 str, bytes/bytearray 或 file object;
# str 将使用 iso-8859-1编码, file object 必须已打开并支持 read() 方法
# headers: 额外增加的 HTTP 请求头, 字典类型
HTTPConnection.request(method, url, body=None, headers={},
*, encode_chunked=False)
# 发出 request() 之后, 调用该方法返回一个 HTTPResponse 对象
HTTPConnection.getresponse()
# 设置调试等级, 默认为 0 表示不输出调试信息, 大于0表示输出调试信息到 stdout,
# 该值将传递给 HTTPResponse 对象
HTTPConnection.set_debuglevel(level)
# 为 HTTP 连接隧道设置主机和端口, 这将允许通过代理服务器进行连接
HTTPConnection.set_tunnel(host, port=None, headers=None)
# 关闭到服务器的连接
HTTPConnection.close()
# 用于发送文件类消息Body的缓冲区大小
HTTPConnection.blocksize
HTTPSConnection 继承自 HTTPConnection
1.2 HTTPResponse 对象
Python 官网:http.client.HTTPResponse Objects
HTTPResponse
实例表示客户端发出请求之后,服务端的 HTTP 响应,包含 http code、响应头、响应内容的。HTTPResponse
继承自io.BufferedIOBase
,拥有 IO 字节流的相关操作方法。HTTPResponse
对象支持with
上下文管理器,在with
语句退出时会自动调用其close()
方法。调用HTTPConnection.close()
方法关闭套接字连接时也会自动调用HTTPResponse.close()
。
# 读取 响应Body, amt 表示最多读取的字节数, 默认读取所有
HTTPResponse.read([amt])
# 读取 响应Body 到 buf 缓冲区, 最大的读取字节数为 buf 的长度,
# 返回读取的字节数
HTTPResponse.readinto(buf)
# 获取指定名称 响应头 的值, 如果有多个同名的 响应头name,
# 则多个名称用 ", " 拼接返回, 没有对应的响应头, 返回 default
HTTPResponse.getheader(name, default=None)
# 获取所有的响应头, 返回一个列表, 列表元素为 (header, value)
HTTPResponse.getheaders()
# 返回基础套接字的 fileno
HTTPResponse.fileno()
# 关闭响应流, 一并不需要关闭, HTTPConnection.close() 时会自动关闭响应流。
HTTPResponse.close()
# 包含了所有响应头的 http.client.HTTPMessage 实例
HTTPResponse.msg
# HTTP 协议的版本: HTTP/1.0 为 10, HTTP/1.1 为 11
HTTPResponse.version
# HTTP 状态码, 200、404 等
HTTPResponse.status
# HTTP 原因短语, OK、NOT FOUND 等
HTTPResponse.reason
# 调试狗子, 如果大于0, 则读取和解析响应时, 消息将被输出到 stdout
HTTPResponse.debuglevel
# 流是否被关闭
HTTPResponse.closed
1.3 http.client 代码示例
httpbin.org 网站可以测试 HTTP/HTTPS 请求和响应的各种信息,如 Cookies、IP、Headers、参数、User-Agent 等,支持 GET、POST 等多种请求方式。
相关地址:http://httpbin.org、https://github.com/postmanlabs/httpbin
GET 方式请求:
"""
请求连接: http://httpbin.org/get?name=Tom&age=25
"""
import http.client
# 创建于服务器的链接
conn = http.client.HTTPConnection("httpbin.org")
# 发出 get 请求, 请求url为: http://httpbin.org/get?name=Tom&age=25
conn.request("GET", "/get?name=Tom&age=25")
# 获取响应
resp = conn.getresponse()
# 打印响应状态等信息
print(resp.status, resp.reason, resp.version)
# 打印响应头
print(resp.msg)
# 打印响应Body的内容
print(resp.read().decode("utf-8"))
# 关闭连接
conn.close()
POST 方式请求:
"""
请求连接: http://httpbin.org/post
"""
import http.client
# 创建于服务器的链接
conn = http.client.HTTPConnection("httpbin.org")
# 发出 post 请求, 请求url为: http://httpbin.org/post
conn.request("POST", "/post", body="name=Tom&age=25")
# 获取响应
resp = conn.getresponse()
# 打印响应状态等信息
print(resp.status, resp.reason, resp.version)
# 打印响应头
print(resp.msg)
# 打印响应Body的内容
print(resp.read().decode("utf-8"))
# 关闭连接
conn.close()
请求 HTTPS 连接时如果报SSL: CERTIFICATE_VERIFY_FAILED
的异常,可以在请求前加入下面代码,使用不校验的 HTTPS 上下文:
import ssl
# 默认的 HTTPS上下文 使用 不校验的上下文
ssl._create_default_https_context = ssl._create_unverified_context
# 或者
# 在创建 HTTPS连接对象 时指定HTTPS上下文为 不校验的上下文
http.client.HTTPSConnection("httpbin.org", context=ssl._create_unverified_context())
2. urlopen() 与 Request 对象
Python 官网: urllib.request — 用于打开 URL 的可扩展库
2.1 urllib.request 中的函数
urllib.request.urlopen()
函数:
# 打开一个链接或请求
#
# url: 链接 或 Request对象
#
# data: 请求Body中的字节数据, 可以是 bytes、bytearray、字节流打开的file对象。
# 有传该参数, 则使用 POST 方法请求, None 表示使用 GET 方法请求。
#
# timeout: 连接超时时间, 浮点类型的秒数
#
# cafile, capath: 为 HTTPS 请求指定一组授信的 CA 证书。
# cafile 为指向包含一堆 CA 证书的单个文件,
# capath 为指向 hash 证书文件的目录。
# 如果不指定证书, HTTPS 请求时可以选择不校验证书。
# context: 描述 SSL 各种选项的 ssl.SSLContext 示例。
# HTTPS 请求时如果不校验证书, 可以传 ssl._create_unverified_context()
#
# 返回 http.client.HTTPResponse 对象(使用完后需要关闭响应, 可以使用 with 语句)
#
urllib.request.urlopen(url, data=None, [timeout, ]
*, cafile=None, capath=None,
cadefault=False, context=None)
- 其他函数:
# 本地语法路径名 编码为 百分比表示的URL路径名(用于在 url 中的参数值的编码)
# 例如: "https://httpbin.org" -> "https%3A//httpbin.org"
urllib.request.pathname2url(path)
# 百分比表示的URL路径名 解码为 本地语法路径名(用于在 url 中的参数值的解码)
# 例如: "https%3A//httpbin.org" -> "https://httpbin.org"
urllib.request.url2pathname(url)
# 返回 scheme 到 代理服务器 的 URL 映射(一个字典)
urllib.request.getproxies()
# 构建打开器
urllib.request.build_opener([handler, ...])
# 设置 urlopen 中默认的打开器
urllib.request.install_opener(opener)
2.2 请求对象: Request
Python 官网:
urllib.request.Request
对象的方法和属性:
# 创建一个请求对象
#
# url: 请求链接
#
# data: 请求Body中的字节数据, 可以是 bytes、bytearray、字节流打开的file对象。
# 有传该参数, 则默认使用 POST 方法请求。
#
# headers: 请求头, 字典类型: {"key1": "value1", "key2": "value2"}
#
# method: 请求方法, "GET"、"POST" 等。默认为 "GET"; 如果有 data, 则默认为 "POST"。
#
class urllib.request.Request(url, data=None, headers={},
origin_req_host=None, unverifiable=False,
method=None)
Request.full_url # 设置 或 获取 请求连接
Request.get_full_url() # 获取 请求连接
Request.selector # 获取 URI 资源路径(url 中 host 后面的部分)
Request.method # 设置 或 获取 请求方法, "GET"、"POST" 等
Request.get_method() # 获取 请求方法
Request.type # 获取类型, "http"、"https" 等
Request.host # 获取主机
Request.origin_req_host # 获取请求的原始主机
Request.headers # 设置 或 获取 所有请求头
Request.add_header(key, val) # 添加请求头
Request.get_header(header_name, default=None) # 获取指定请求头的值
Request.has_header(header_name) # 是否有指定请求头
Request.remove_header(header_name) # 移除请求头
Request.header_items() # 包含所有请求头的列表: [(key, value), ...]
Request.add_unredirected_header(key, header) # 添加请求头, 如果发生重定向, 不会添加到重定向请求
Request.unverifiable # 请求是否不可校验
Request.set_proxy(host, type) # 设置代理服务器
创建 Request 对象,再发出GET
请求:
import urllib.request
# 创建请求对象
req = urllib.request.Request("http://httpbin.org/get?name=Tom&age=25")
# 设置请求方法
req.method = "GET"
# 添加/覆盖请求头
req.add_header("User-Agent", "Mozilla/5.0")
# 发出请求, 返回响应对象 http.client.HTTPResponse
resp = urllib.request.urlopen(req)
# 打印响应状态等信息
print(resp.status, resp.reason, resp.version)
# 打印响应头
print(resp.getheaders())
# 打印响应Body的内容
print(resp.read().decode("utf-8"))
# 关闭响应流
resp.close()
创建 Request 对象,再发出POST
请求:
import urllib.request
# 创建请求对象, 有 data 默认为 POST 请求, data 可以是 bytes、bytearray、字节流打开的file对象
req = urllib.request.Request("http://httpbin.org/post", data=b"name=Tom&age=25")
# 发出请求, 返回响应对象 http.client.HTTPResponse
resp = urllib.request.urlopen(req)
# 打印响应状态等信息
print(resp.status, resp.reason, resp.version)
# 打印响应头
print(resp.getheaders())
# 打印响应Body的内容
print(resp.read().decode("utf-8"))
# 关闭响应流
resp.close()
3. Cookie 处理: http.cookies 和 http.cookiejar
3.1 Cookies对象: SimpleCookie
Python 官网: http.cookies — HTTP state management
http.cookies.SimpleCookie
表示一个简单的 Cookies 对象,继承自dict
。
SimpleCookie 创建简单示例:
>>> from http import cookies
>>>
>>> C = cookies.SimpleCookie() # 创建 Cookies 对象
>>> C["aa"] = "abc"
>>> C["bb"] = "123"
>>>
>>> print(C) # 打印出 HTTP 响应头
Set-Cookie: aa=abc
Set-Cookie: bb=123
>>>
>>> C["aa"].output() # 生成 HTTP 响应头字符串
'Set-Cookie: aa=abc'
>>>
>>> C["aa"]["Path"] = "/cookie" # 添加其他属性
>>> C["aa"]["HttpOnly"] = True
>>> print(C["aa"])
Set-Cookie: aa=abc; HttpOnly; Path=/cookie
>>>
>>> print(C["aa"].key) # cookie 的 key
aa
>>> print(C["aa"].value) # cookie 的 value
abc
>>>
>>> for key in C: # 遍历 Cookie
... print(C[key])
...
Set-Cookie: aa=abc; HttpOnly; Path=/cookie
Set-Cookie: bb=123
官网 SimpleCookie 创建示例: http.cookies example
3.2 保存/添加 Cookies: http.cookiejar
Python 官网: http.cookiejar — Cookie handling for HTTP clients
http.cookiejar.Cookie
表示一个 Cookie 对象:
http.cookiejar.Cookie(
version, # 版本, >= 0
name, # Cookie 的名字, str
value, # Cookie 的值, str
port, # 端口
port_specified, # 是否指定端口, 如果True, 则 port 必须指定
domain, # 域名
domain_specified, # 是否指定域名
domain_initial_dot, # 是否域名点开头
path, # 路径
path_specified, # 是否指定路径
secure, # 是否是安全的
expires, # 过期时间, 单位为秒的时间戳
discard, # 是否丢弃(不保存)
comment, # 描述
comment_url, # 描述链接
rest, # 其他非标准的属性, 字典类型
rfc2109=False # 是否是 RFC 2109 标准
)
创建一个Cookie
对象:
import http.cookiejar
# 创建一个 Cookie
cookie = http.cookiejar.Cookie(
version=0,
name="hello",
value="world",
port=None,
port_specified=False,
domain=".httpbin.org",
domain_specified=True,
domain_initial_dot=False,
path="/",
path_specified=True,
secure=False,
expires=3742443533,
discard=False,
comment=None,
comment_url=None,
rest={},
)
# 判断 Cookie 是否过期(默认与当前时间对比)
print(cookie.is_expired(now=None))
# 设置 指定名称的非标准属性值
cookie.set_nonstandard_attr("attr_name", "attr_value")
# 获取 指定名称的非标准属性值
cookie.get_nonstandard_attr("attr_name", default=None)
# 判断 是否有指定名称的非标准属性
cookie.has_nonstandard_attr("attr_name")
http.cookiejar.CookieJar
用于管理 Cookie,手动设置 Cookie,给请求设置匹配的 Cookie,从响应中提取 Cookie 等。CookieJar
的创建和常用方法:
# CookieJar 构造方法
class http.cookiejar.CookieJar(policy=None)
# 添加符合条件的 Cookie 到请求头中
CookieJar.add_cookie_header(request)
# 提取响应中的 Cookie
CookieJar.extract_cookies(response, request)
# 手动设置一个 Cookie
CookieJar.set_cookie(cookie)
# 清理一些 Cookie
CookieJar.clear(domain=None, path=None, name=None)
# 清理会话 Cookie
CookieJar.clear_session_cookies()
# 遍历 Cookie
for cookie in cookieJar:
# 这里 cookie 的类型为 http.cookiejar.Cookie
print(cookie.name + "=" + cookie.value)
CookieJar
只支持在内存中保存,不能持久化,要想把 Cookie 保存为本地文件,可是使用FileCookieJar
。FileCookieJar
没有实现保存方法,通常使用它的子类MozillaCookieJar
或 LWPCookieJar
:
# FileCookieJar 构造方法, filename 为加载和保存 Cookie 的默认文件路径
class http.cookiejar.FileCookieJar(filename, delayload=None, policy=None)
# 加载 Cookie
FileCookieJar.load(filename=None, ignore_discard=False, ignore_expires=False)
# 保存 Cookie
FileCookieJar.save(filename=None, ignore_discard=False, ignore_expires=False)
Cookie 添加、提取、保存 代码示例:
import ssl
import urllib.request
import http.cookiejar
# 默认的 HTTPS上下文 使用 不校验的上下文
ssl._create_default_https_context = ssl._create_unverified_context
# 创建 MozillaCookieJar 对象, 指定 Cookie 文件路径
cookieJar = http.cookiejar.MozillaCookieJar("cookies.txt")
# 从文件中加载 Cookie
cookieJar.load()
# 创建请求
req = urllib.request.Request("https://www.baidu.com")
# 从 CookieJar 中查找符合 req 请求的 Cookie 并添加到请求头中
cookieJar.add_cookie_header(req)
# 可以打印查看被添加的 Cookie
print(req.header_items())
# 打开请求, 获取响应
resp = urllib.request.urlopen(req)
# 输出响应内容
# print(resp.read().decode("utf-8"))
# 从响应中提取 Cookie 并保存到 CookieJar 中
cookieJar.extract_cookies(resp, req)
# 把内存中的 Cookie 保存到文件中
cookieJar.save()
# 关闭响应
resp.close()
手动设置 Cookie 代码示例:
import urllib.request
import http.cookiejar
# 创建 MozillaCookieJar 对象, 指定 Cookie 文件路径
cookieJar = http.cookiejar.MozillaCookieJar("cookies.txt")
# 从文件中加载 Cookie
cookieJar.load()
# 创建一个 Cookie: hello=world
cookie = http.cookiejar.Cookie(
version=0,
name="hello",
value="world",
port=None,
port_specified=False,
domain=".httpbin.org",
domain_specified=True,
domain_initial_dot=False,
path="/",
path_specified=True,
secure=False,
expires=3742443533,
discard=False,
comment=None,
comment_url=None,
rest={},
)
# 手动设置 Cookie 到 CookieJar 中
cookieJar.set_cookie(cookie)
# 创建请求
req = urllib.request.Request("http://httpbin.org/cookies")
# 从 CookieJar 中查找符合 req 请求的 Cookie 并添加到请求头中
cookieJar.add_cookie_header(req)
# 可以打印查看添加的 Cookie
print(req.header_items())
# 打开请求, 获取响应
resp = urllib.request.urlopen(req)
# 输出响应内容
print(resp.read().decode("utf-8"))
# 从响应中提取 Cookie 并保存到 CookieJar 中
cookieJar.extract_cookies(resp, req)
# 把内存中的 Cookie 保存到文件中
cookieJar.save()
# 关闭响应
resp.close()
4. Handler 与 Opener
处理器Handler 与 打开器Opener:
- Python 官网: BaseHandler Objects
- Python 官网: OpenerDirector Objects
构建 Handler,自定义 Opener:
import urllib.request
import ssl
# 创建一个 HTTPHandler 处理器, 支持处理 HTTP 请求
handler = urllib.request.HTTPHandler()
# 创建一个 HTTPSHandler 处理器, 支持处理 HTTP/HTTPS 请求
# handler = urllib.request.HTTPSHandler(context=ssl._create_unverified_context())
# 通过 处理器handler 创建打开器 opener,
# 可以传递多个 Handler: build_opener(handler1, handler2, ...), 也可以不传递 handler 创建默认的 Opener
opener = urllib.request.build_opener(handler)
# 把自定义的 opener 设置为 urllib.request.urlopen() 打开时默认用的 Opener
# urllib.request.install_opener(opener)
# 创建请求对象
req = urllib.request.Request("http://httpbin.org/")
# 用打开器打开请求, 返回响应
resp = opener.open(req) # 打开 req 或者 url
# 输出响应内容
print(resp.read().decode("utf-8"))
5. Cookies 自动处理器: HTTPCookieProcessor
Python 官网: HTTPCookieProcessor Objects
import urllib.request
import http.cookiejar
import ssl
# 创建 CookieJar 管理 Cookie
cookiejar = http.cookiejar.CookieJar()
# 创建支持自动处理(提取/添加)Cookie 的 Handler
cookieHandler = urllib.request.HTTPCookieProcessor(cookiejar)
# 创建支持处理 HTTPS 请求的 Handler
httpsHandler = urllib.request.HTTPSHandler(context=ssl._create_unverified_context())
# 通过 多个handler 创建打开器 opener
opener = urllib.request.build_opener(cookieHandler, httpsHandler)
# 把自定义的 opener 设置为 urllib.request.urlopen() 打开时用的默认 Opener
# urllib.request.install_opener(opener)
# 创建请求对象, 返回将有 Cookie: id=123
req = urllib.request.Request("https://httpbin.org/cookies/set/id/123")
# 用打开器打开请求, 返回响应
resp = opener.open(req) # 打开 req 或者 url
# 输出 cookiejar 中的 cookie
for cookie in cookiejar:
print(cookie.name + "=" + cookie.value)
# 发出请求, 会自动添加 Cookie
resp = opener.open("https://httpbin.org/cookies")
print(resp.read().decode("utf-8"))
6. URL 解析: urllib.parse
Python 官网: urllib.parse — Parse URLs into components
urllib.parse
主要用于将 URL 字符串分拆解析为其组件(scheme、host、query等),或将 URL 组件组合成 URL 字符串。
解析 URL:
>>> from urllib.parse import urlparse
>>> o = urlparse("http://www.cwi.nl:80/%7Eguido/Python.html?name=tom&age=25")
>>> o
ParseResult(scheme='http', netloc='www.cwi.nl:80', path='/%7Eguido/Python.html',
params='', query='name=tom&age=25', fragment='')
>>> o.scheme
'http'
>>> o.port
80
>>> o.query
'name=tom&age=25'
非标准 URL 的解析结果:
>>> from urllib.parse import urlparse
>>>
>>> urlparse("//www.cwi.nl:80/%7Eguido/Python.html")
ParseResult(scheme='', netloc='www.cwi.nl:80', path='/%7Eguido/Python.html',
params='', query='', fragment='')
>>>
>>> urlparse("www.cwi.nl/%7Eguido/Python.html")
ParseResult(scheme='', netloc='', path='www.cwi.nl/%7Eguido/Python.html',
params='', query='', fragment='')
>>>
>>> urlparse("help/Python.html")
ParseResult(scheme='', netloc='', path='help/Python.html',
params='', query='', fragment='')
URL 组件组合:
>>> from urllib.parse import urljoin
>>>
>>> urljoin("http://www.cwi.nl/%7Eguido/Python.html", "FAQ.html")
'http://www.cwi.nl/%7Eguido/FAQ.html'
>>>
>>> urljoin("http://www.cwi.nl/%7Eguido/Python.html",
... "//www.python.org/%7Eguido")
'http://www.python.org/%7Eguido'