re
re 模块是 Python 中用来处理正则表达式的模块,提供了一系列函数,用于匹配、搜索、替换字符串中的模式
import re
r0 = re.match(r'\d?[A-Z]{3}', '1ASD')
print(r0)
r0 = re.match(r'\d?[A-Z]{3}', 'AD')
print(r0)
"""执行结果:
<re.Match object; span=(0, 4), match='1ASD'>
None
"""
print('王林 王麻子 小林子'.split(' '))
r0 = re.split(r'\s+', '王林 王麻子 小林子,WangLin')
print(r0)
r0 = re.split(r'[\s,]+', '王林 王麻子 小林子,WangLin')
print(r0)
"""执行结果:
['王林', '', '', '王麻子', '小林子']
['王林', '王麻子', '小林子,WangLin']
['王林', '王麻子', '小林子', 'WangLin']
"""
r0 = re.match(r'^(\w{1,10})-(\d{11})$', 'dawn-19999999999')
print(r0)
print(r0.groups())
# group(0) 和整个表达式想匹配
print(r0.group(0), r0.group(1), r0.group(2))
"""执行结果:
<re.Match object; span=(0, 16), match='dawn-19999999999'>
('dawn', '19999999999')
dawn-19999999999 dawn 19999999999
"""
# \d+默认是贪婪匹配;将后面的9全部匹配了
r0 = re.match(r'^(dawn-\d+)(9*)$', 'dawn-19999999999')
print(r0)
print(r0.groups())
"""执行结果:
<re.Match object; span=(0, 16), match='dawn-19999999999'>
('dawn-19999999999', '')
"""
# \d+?变成了非贪婪匹配
r0 = re.match(r'^(dawn-\d+?)(9*)$', 'dawn-19999999999')
print(r0)
print(r0.groups())
"""执行结果:
<re.Match object; span=(0, 16), match='dawn-19999999999'>
('dawn-1', '9999999999')
"""
# re 模块首先编译正则表达式,再用编译后的模式匹配字符串。
# 如果正则表达式重复使用很多次,可以预编译它,避免每次都编译,提高效率。
c0 = re.compile(r'^(\d{3})-(\d{3,8})$')
r0 = c0.match("100-222")
print(r0)
print(r0.groups())
"""执行结果
<re.Match object; span=(0, 7), match='100-222'>
('100', '222')
"""
datetime
datetime 日期时间工具,常用于获取当前时间、格式化时间、进行日期和时间计算、解析和格式化日期字符串等。通过 timedelta,你可以轻松进行日期的加减操作,而 strftime 和 strptime 则帮助你处理不同格式的时间字符串。
# datetime模块 => 包含一个datetime类
from datetime import datetime, timezone, timedelta
# 获取当前时间
print(datetime.now())
# 获取指定类型的时间
print(datetime(2025, 2, 7, 11, 11, 11))
# 将时间转为时间戳
dt = datetime(2025, 2, 7, 11, 11, 11)
print(dt.timestamp()) # 整数位表示秒
# timestamp转换为datetime
tp = dt.timestamp()
print(datetime.fromtimestamp(tp)) # 本地时间:操作系统设定的时区
print(datetime.fromtimestamp(tp, timezone.utc)) # UTC时间
# datetime转为string《string format time》
print(datetime.strftime(dt, "%Y年%m月%d %H:%M:%S"))
print(datetime.strftime(datetime.now(), '%a, %b %d %H:%M'))
# string转为datetime《string parse time》
dt_obj = datetime.strptime("2025-02-17 12:45:30", "%Y-%m-%d %H:%M:%S")
print(type(dt_obj), dt_obj)
# datetime加减
"""
对日期和时间进行加减实际上就是把datetime往后或往前计算,得到新的datetime。
加减可以直接用+和-运算符,不过需要导入timedelta这个类
"""
now = datetime.now()
print(now + timedelta(hours=1))
print(now - timedelta(days=10, hours=1))
# 创建时区UTC+8:00
tz_utc_8 = timezone(timedelta(hours=8))
print(datetime.now())
# 强行设置为UTC+8:00时区
print(now.replace(tzinfo=tz_utc_8))
# 强制设置时区为UTC+0:00
now = datetime.now().replace(tzinfo=timezone.utc)
print(now)
# 强制转为UTC+8:00
now = now.astimezone(timezone(timedelta(hours=8)))
print(now)
collections
collections 提供了许多有用的集合类
namedtuple
namedtuple() 函数用于创建一个具名元组。它创建一个类似元组的对象,但每个字段都可以通过名称访问。
from collections import namedtuple
Point = namedtuple('Point', ['x', 'y'])
point = Point(1, 2)
print(point)
"""
namedtuple可以用属性而不是索引来引用tuple的某个元素。
这样一来,namedtuple可以很方便地定义一种数据类型,它具备tuple的不变性,
又可以根据属性来引用。
可以验证创建的Point对象是tuple的一种子类:
"""
print(isinstance(point, Point)) # True
print(isinstance(point, tuple)) # True
deque
deque 是一个双端队列,支持从两端高效地添加和删除元素。它比列表更适合用作队列或栈。
list是线性存储,数据量大的时候,插入和删除效率很低,按索引访问元素很快deque是为了高效实现插入和删除操作的双向列表,适合用于队列和栈
from collections import deque
# 创建一个空的 deque
dq = deque()
# 从右边添加元素
dq.append(1)
dq.append(2)
# 从左边添加元素
dq.appendleft(0)
# 从右边删除元素
dq.pop()
# 从左边删除元素
dq.popleft()
print(dq) # 输出:deque([1])
defaultdict
defaultdict 是一个字典子类,它提供一个默认值,当键不存在时,返回指定的默认值。这对于避免 KeyError 非常有用。
defaultdict的其他行为跟dict是完全一样的。
from collections import defaultdict
# 创建一个 defaultdict,指定默认值为 int(默认值是 0)
dict0 = defaultdict(int)
# 向字典中添加元素
dict0['a'] += 1
dict0['b'] += 2
print(dict0) # 输出:defaultdict(<class 'int'>, {'a': 1, 'b': 2})
# 如果访问一个不存在的键,返回默认值
print(dict0['c']) # 输出:0
OrderedDict
OrderedDict 是一个有序字典,保持字典元素的插入顺序。通常标准字典是无序的,但 OrderedDict 会记住元素的插入顺序 而非 key 的顺序。
from collections import OrderedDict
# 创建一个有序字典
od = OrderedDict()
# 向字典中添加元素
od['apple'] = 3
od['banana'] = 2
od['orange'] = 1
# 打印字典
print(od) # 输出:OrderedDict([('apple', 3), ('banana', 2), ('orange', 1)])
# 迭代时保持插入顺序
for key, value in od.items():
print(key, value)
# 创建一个有序字典
od = OrderedDict()
# 向字典中添加元素
od['apple'] = 3
od['banana'] = 2
od['orange'] = 1
# 打印字典
print(od) # 输出:OrderedDict([('apple', 3), ('banana', 2), ('orange', 1)])
# 迭代时保持插入顺序
for key, value in od.items():
print(key, value)
ChainMap
ChainMap 用于将多个字典合并为一个视图,可以像访问普通字典一样访问多个字典的数据。
from collections import ChainMap
# 创建两个字典
dict1 = {'a': 1, 'b': 2}
dict2 = {'b': 3, 'c': 4}
# 将两个字典合并
cm = ChainMap(dict1, dict2)
print(cm) # ChainMap({'a': 1, 'b': 2}, {'b': 3, 'c': 4})
print(cm['a']) # 1
print(cm['b']) # 2(来自 dict1,因为 ChainMap 是从左到右查找)
print(cm['c']) # 4(来自 dict2)
解析并获取命令行参数,如果没有获取到,使用默认参数
from collections import ChainMap
import os, argparse
"""
argparse 库用于处理命令行参数
argparse.ArgumentParser:创建一个 ArgumentParser 对象,用于处理命令行参数的解析
"""
parser = argparse.ArgumentParser()
"""
-s 或 --server: 接受一个值,指定服务。
-v 或 --version: 接受一个值,指定版本。
"""
parser.add_argument('-s', '--server')
parser.add_argument('-v', '--version')
"""
parse_args():解析命令行参数,返回一个命名空间对象,
其包含了命令行传入的参数的值。如果用户没有提供某个参数,则对应的值为 None。
"""
namespace = parser.parse_args()
command_line_args = { k: v for k, v in vars(namespace).items() if v }
# 构造缺省参数:
defaults = {
'server': 'user-api',
'version': '1.0.0'
}
# 组合成ChainMap:
combined = ChainMap(command_line_args, os.environ, defaults)
# 打印参数:
print('server=%s' % combined['server'])
print('version=%s' % combined['version'])
Counter
Counter 是一个字典的子类,用于统计可哈希对象的频率。它非常适合用来计数和统计元素的出现次数。
from collections import Counter
# 创建一个 Counter
c0 = Counter(['a', 'b', 'c', 'a', 'b', 'a'])
print(c0) # Counter({'a': 3, 'b': 2, 'c': 1})
# 获取某个元素的数量
print(c0['a']) # 3
# 获取出现最常见的元素
print(c0.most_common(1)) # [('a', 3)]
c1 = Counter('hello')
print(c1) # Counter({'l': 2, 'h': 1, 'e': 1, 'o': 1})
# 更新一次计数
c1.update('haha')
print(c1) # Counter({'h': 3, 'l': 2, 'a': 2, 'e': 1, 'o': 1})
argparse
sys.argv
sys.argv 是获取命令行参数的基础方法,适合用于简单的命令行参数传递和处理,但如果参数较复杂(比如需要处理可选参数、类型转换、帮助信息等),argparse 会更加方便和强大。
sys.argv是一个列表,包含了从命令行传递给 Python 脚本的所有参数。sys.argv[0]是脚本本身的文件名(即执行的 Python 文件)。- 后续的元素(从
sys.argv[1]开始)是传递给脚本的命令行参数。
bash
python test.py arg1 arg2 arg3
在脚本中,sys.argv 的内容会是:
python
import sys
print(sys.argv)
输出将会是:
['test.py', 'arg1', 'arg2', 'arg3']
sys.argv[0]='example.py'(脚本文件名)sys.argv[1]='arg1'(第一个传递的参数)sys.argv[2]='arg2'(第二个传递的参数)sys.argv[3]='arg3'(第三个传递的参数)
argparse
argparse 是 Python 标准库中的一个模块,用于解析命令行参数。它提供了一个灵活且易用的方式来处理命令行输入,允许你定义期望的参数、自动生成帮助信息,并执行类型转换、验证等操作。
- 创建解析器:使用
ArgumentParser()创建一个解析器对象。 - 添加参数:通过
add_argument()方法来定义你期望的命令行参数。 - 解析参数:使用
parse_args()方法解析传递给脚本的命令行参数。
import argparse
def main():
# 定义一个ArgumentParser实例:
parser = argparse.ArgumentParser(
prog='backup', # 程序名
description='Backup MySQL database.', # 描述
epilog='Copyright(r), 2025' # 说明信息
)
# 定义位置参数:
parser.add_argument('outfile')
# 定义关键字参数:
parser.add_argument('--host', default='localhost')
# 此参数必须为int类型:
parser.add_argument('--port', default='3306', type=int)
# 允许用户输入简写的-u:
parser.add_argument('-u', '--user', required=True)
parser.add_argument('-p', '--password', required=True)
parser.add_argument('--database', required=True)
# gz参数不跟参数值,因此指定action='store_true',意思是出现-gz表示True:
parser.add_argument('-gz', '--gzcompress', action='store_true', required=False, help='Compress backup files by gz.')
# 解析参数:
args = parser.parse_args()
# 打印参数:
print('parsed args:')
print(f'outfile = {args.outfile}')
print(f'host = {args.host}')
print(f'port = {args.port}')
print(f'user = {args.user}')
print(f'password = {args.password}')
print(f'database = {args.database}')
print(f'gzcompress = {args.gzcompress}')
if __name__ == '__main__':
main()
base64
Base64 实际上就是一种查表的编码方法,使用 64 个字符的字符集进行编码,该字符集如下:
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
每个字符使用六位(2^6 = 64)表示,因此它能够表示 64 个不同的值。
Base64编码会把3字节的二进制数据编码为4字节的文本数据,长度增加33%,好处是编码后的文本数据可以在邮件正文、网页等直接显示。
编码过程
-
原始字符串:Cat
-
转换为字节:每个字符转为 ASCII 码:
- 'C' → 67 (二进制 01000011)
- 'a' → 97 (二进制 01100001)
- 't' → 116 (二进制 01110100) 所以原始数据是:01000011 01100001 01110100
-
将原始的二进制分成 4 组: 010000 110110 000101 110100
-
查表映射:
- 010000 → 16(对应字符 Q)
- 110110 → 54(对应字符 2)
- 000101 → 5(对应字符 F)
- 110100 → 52(对应字符 0) 所以编码后的字符串为:Q2F0。
-
没有填充
- 这里没有出现不足三字节的情况,所以没有填充字符 =
-
填充字符
- 如果原始数据不是 3 的倍数字节,编码后会填充 = 字符:
- 如果有 1 个字节剩余,则添加两个 =
- 如果有 2 个字节剩余,则添加一个 =
解码过程
解码是编码的逆过程。解码时会将 Base64 字符转换回原来的 6 位二进制数据,然后将这些数据重新合并成 8 位字节流,最终恢复出原始数据。
示例
import base64
def print_b64decode(s):
s1 = base64.b64decode(s)
print(s1.decode("utf-8"))
s0 = base64.b64encode("从今日起,王某便是元婴之下第一人.".encode("utf-8"))
print(s0)
print_b64decode(s0)
"""执行结果
b'5LuO5LuK5pel6LW377yM546L5p+Q5L6/5piv5YWD5am05LmL5LiL56ys5LiA5Lq6Lg=='
从今日起,王某便是元婴之下第一人.
"""
struct
用于打包和解包二进制数据,常用函数:
struct.pack(fmt, v1, v2, ...): 将 Python 的值打包为二进制数据。struct.unpack(fmt, buffer): 从二进制数据中解包,返回一个元组。struct.calcsize(fmt): 返回打包格式字符串所需的字节数。
将浮点数转换为字节
import struct
s0 = b'123456'
print(s0)
int0 = 123
print(int0.to_bytes(2, byteorder='little'))
print(int0.to_bytes(2, byteorder='big'))
# 将浮点数转换为字节
f0 = 12.34
fb0 = struct.pack('f', f0) # 'f' 表示 32 位浮点数
打包数据:将整数、浮点数和字符打包成二进制格式
"""
'if3s' 表示:
i:一个整数(4 字节)
f:一个浮点数(4 字节)
3s:一个长度为 3 的字节字符串
"""
data = struct.pack('if3s', 42, 3.14, b'abc')
print(data) # 输出的是二进制数据
解包数据:按照相同的格式字符串解码
binary_data = struct.pack('if3s', 42, 3.14, b'abc')
unpacked_data = struct.unpack('if3s', binary_data)
print(unpacked_data) # 输出: (42, 3.140000104904175, b'abc')
计算格式字符串所占的字节数
size = struct.calcsize('if3s')
print(size) # 输出: 11 (4 字节整数 + 4 字节浮点数 + 3 字节字符串)
hashlib
hashlib 模块提供了许多常见的加密哈希算法,以使用如 MD5、SHA-1、SHA-256 等算法来计算字符串或二进制数据的哈希值
import hashlib
md5 = hashlib.md5()
md5.update("天让你死,我也要把你抢回来!".encode("utf-8"))
print(md5.hexdigest()) # daabec1fa6fdd9f2557de17317cb5931
md5 = hashlib.md5()
md5.update("天让你死,".encode("utf-8"))
md5.update("我也要把你抢回来!".encode("utf-8"))
print(md5.hexdigest()) # daabec1fa6fdd9f2557de17317cb5931
sha1 = hashlib.sha1()
sha1.update("顺为凡,逆则仙,只在心中一念间".encode("utf-8"))
print(sha1.hexdigest()) # acadf87861e261fc5107774c9642b6fcdfeea52b
sha1 = hashlib.sha1()
sha1.update("顺为凡,逆则仙,".encode("utf-8"))
sha1.update("只在心中一念间".encode("utf-8"))
print(sha1.hexdigest()) # acadf87861e261fc5107774c9642b6fcdfeea52b
hmac
为了防止黑客通过彩虹表反推原始口令,我们需要在计算哈希时加入盐值(salt),使得相同的输入产生不同的哈希。通常做法是计算 md5(message + salt)。然而,HMAC(Keyed-Hashing for Message Authentication)算法将盐值视为“口令”,并在计算过程中将其与消息一起哈希。HMAC算法通用,适用于任何哈希算法(如MD5、SHA-1),并提供更标准和安全的方式。Python的 hmac 模块实现了这一标准算法。
import hashlib
import hmac
key = b'secret000'
message = '我一生逆天,不甘心命运摆弄,欲成为天地之主,欲踏碎这天,轰灭这地!'.encode('utf-8')
h = hmac.new(key, message, digestmod=hashlib.sha256)
print(h.hexdigest())
itertools
itertools 模块为处理迭代器提供了丰富的工具,尤其适用于需要高效地生成组合、排列、笛卡尔积等场景。它的懒加载特性使得处理大型数据集时特别高效,避免了不必要的内存消耗。
import itertools
# count(start=0, step=1)
# 返回一个无限迭代器,从 start 开始,每次递增 step,默认是从 0 开始,步长为 1。
counter = itertools.count(1)
print(next(counter))
print(next(counter))
counter = itertools.count(10, 20)
print(next(counter))
print(next(counter))
# 创建一个无限的迭代器,重复遍历输入的可迭代对象。
cs = itertools.cycle([1, 2])
print(next(cs)) # 1
print(next(cs)) # 2
print(next(cs)) # 1
cs = itertools.cycle("这雨,出生于天,死于大地。中间的过程,便是人生。")
print(next(cs))
print(next(cs))
# repeat(object, times=None)
# 返回一个迭代器,重复返回同一个对象 times 次。如果 times 不指定,则默认无限次重复。
r0 = itertools.repeat("王林", 2)
print(next(r0))
print(next(r0))
items = ['王林', '李慕婉', '红蝶']
# permutations(iterable, r=None)
# 返回输入元素的所有排列(按顺序的排列)。如果给定参数 r,则返回所有 r 长度的排列。
perms = itertools.permutations(items, 2)
for perm in perms:
print(perm)
# combinations(iterable, r)
# 返回输入元素的所有 r 长度的组合,组合中的元素是无序的。
import itertools
combs = itertools.combinations(items, 2)
for c in combs:
print(c)
# combinations_with_replacement(iterable, r)
# 返回所有 r 长度的组合,并允许元素重复。
combs = itertools.combinations_with_replacement(items, 2)
for c in combs:
print(c)
# product(*iterables, repeat=1)
# 返回多个可迭代对象的笛卡尔积。可以通过 repeat 参数指定重复次数。
items = ['王林', '李慕婉']
prod = itertools.product(items, repeat=2)
for p in prod:
print(p)
# chain(*iterables)
# 将多个可迭代对象连接成一个大的迭代器,按顺序返回每个元素。
chain_obj = itertools.chain('ABC', '123')
print(list(chain_obj))
# zip_longest(*iterables, fillvalue=None)
# 类似 zip(),但会填充较短的可迭代对象,使它们的长度一致,直到最长的迭代器耗尽。
a = [1, 2, 3]
b = ['a', 'b']
zipped = itertools.zip_longest(a, b, fillvalue='x')
print(list(zipped))
# islice(iterable, start, stop, step)
# 返回一个迭代器,表示输入可迭代对象的一个切片,类似于切片操作,但是它是懒加载的(按需计算)。
items = range(10)
sliced = itertools.islice(items, 2, 8, 2)
print(list(sliced))
# groupby()把迭代器中相邻的重复元素挑出来放在一起:
for key,group in itertools.groupby("王王麻麻子小林子"):
print(key, list(group))
"""执行结果
王 ['王', '王']
麻 ['麻', '麻']
子 ['子']
小 ['小']
林 ['林']
子 ['子']
""
contextlib
with 语句
在读写文件完毕后可以使用try...finally需要正确关闭,但是写try...finally的过程比较繁琐,而Python提供的 with 语句可以更方便地使用资源,而不必担心资源没有关闭。
with open('/path/to/file', 'r') as f:
f.read()
但并不是只有open()函数返回的fp对象才能使用with语句。实际上,任何对象,只要正确实现了上下文管理,就可以用于with语句。
而实现上下文管理是通过__enter__和__exit__这两个方法实现的
class Work(object):
def __init__(self, name):
self.name = name
def __enter__(self):
print('Begin do work')
return self
def __exit__(self, exc_type, exc_value, traceback):
if exc_type:
print('Error do work')
else:
print('End do work')
def do_work(self):
print('%s do work ...' % self.name)
with Work('Bob') as q:
q.do_work()
"""执行结果
Begin do work
Bob do work ...
End do work
"""
@contextmanager
编写__enter__和__exit__仍然很繁琐,而contextlib提供了更简单的写法
class Work(object):
def __init__(self, name):
self.name = name
def do_work(self):
print('%s do work ...' % self.name)
"""
@contextmanager这个decorator接受一个generator,
用yield语句把with ... as var把变量输出出去,
然后,with语句就可以正常地工作了
"""
@contextmanager
def cwork(name):
print('Begin do work')
work = Work(name)
yield work
print('End do work')
with cwork('Bob') as worker:
worker.do_work()
如果希望在某段代码执行前后自动执行特定代码,也可以用@contextmanager实现。
@contextmanager
def tag(name):
print("<%s>" % name)
yield
print("</%s>" % name)
with tag("h1"):
print("hello")
print("world")
"""执行结果:
<h1>
hello
world
</h1>
"""
"""执行顺序:
with语句首先执行yield之前的语句,因此打印出<h1>;
yield调用会执行with语句内部的所有语句,因此打印出hello和world;
最后执行yield之后的语句,打印出</h1>。
"""
@closing
如果对象没有实现上下文,就不能用with语句。此时可以用closing()来把该对象变为上下文对象。
from contextlib import closing, contextmanager
from urllib.request import urlopen
with closing(urlopen('https://www.python.org')) as page:
for line in page:
print(line)
closing也是一个经过@contextmanager装饰的generator,这个generator的实现其实非常简单;可将任意对象变为上下文对象,并支持with语句
@contextmanager
def closing(thing):
try:
yield thing
finally:
thing.close()
urllib
urllib 提供了用于操作 URL(Uniform Resource Locator)以及网络请求的功能。urllib 模块的主要作用是处理 HTTP 请求、解析和构建 URL,以及进行编码和解码操作。
urllib 模块的子模块:
urllib.request: 用于打开和读取 URLs(HTTP、FTP 等)。urllib.parse: 用于解析 URL,并进行 URL 编码和解码。urllib.error: 包含处理 HTTP 错误的异常类。urllib.robotparser: 用于解析robots.txt文件。urllib.response: 用于处理响应(通常不需要直接使用,已集成在urllib.request中)。
get
req = request.urlopen('http://www.python.org')
req.add_header = ('User-agent', 'Mozilla/5.0')
with req as response:
print(f"Status: {response.status} {response.reason}")
for k, v in response.getheaders():
print(f"{k}:{v}")
# print(response.read().decode('utf-8'))
ProxyHandler
如果需要通过Proxy去访问网站,可使用ProxyHandler来处理
proxy = "127.0.0.1:7890"
# proxy = "http://username:password@your_proxy_address:port"
proxy_handler = request.ProxyHandler({
'http': proxy,
'https': proxy
})
# 创建 opener
opener = request.build_opener(proxy_handler)
# 发送请求
response = opener.open("http://www.python.org")
# 读取响应内容
print(response.read())
XML
操作XML有两种方法:DOM和SAX。DOM将整个XML加载到内存,解析为树,优点是可以任意遍历,但占用内存大且解析慢;SAX是流式解析,占用内存小且解析快,但需要手动处理事件。通常优先考虑SAX。
在Python中,使用SAX解析XML很简单,只需实现 start_element、end_element 和 char_data 三个事件处理函数即可。
from xml.parsers.expat import ParserCreate
class DefaultSaxHandler(object):
def start_element(self, name, attrs):
print('start_element: %s, attrs: %s' % (name, str(attrs)))
def end_element(self, name):
print('end_element: %s' % name)
def char_data(self, text):
print('char_data: %s' % text)
xml = r'''<?xml version="1.0"?>
<ol>
<li><a href="/python">Python</a></li>
<li><a href="/ruby">Ruby</a></li>
</ol>
'''
handler = DefaultSaxHandler()
parser = ParserCreate()
parser.StartElementHandler = handler.start_element
parser.EndElementHandler = handler.end_element
parser.CharacterDataHandler = handler.char_data
parser.Parse(xml)
HTMLParser
HTML本质上是XML的子集,但是HTML的语法没有XML那么严格,所以不能用标准的DOM或SAX来解析HTML。而Python提供了HTMLParser可非常方便地解析HTML
from html.parser import HTMLParser
class MyHTMLParser(HTMLParser):
def handle_starttag(self, tag, attrs):
print('<%s>' % tag)
def handle_endtag(self, tag):
print('</%s>' % tag)
def handle_startendtag(self, tag, attrs):
print('<%s/>' % tag)
def handle_data(self, data):
print(data)
def handle_comment(self, data):
print('<!--', data, '-->')
def handle_entityref(self, name):
print('&%s;' % name)
def handle_charref(self, name):
print('&#%s;' % name)
parser = MyHTMLParser()
parser.feed('''<html>
<head></head>
<body>
<!-- test html parser -->
<p>Some <a href="#">html</a> HTML tutorial...<br>END</p>
</body></html>''')