1. re模块简介
Python的re模块是一个用于正则表达式操作的标准库,它允许开发者对文本进行高效的模式匹配和搜索。
re模块提供了许多功能,包括:
- 匹配:使用re.match()或re.search()函数在字符串中查找模式匹配项。
- 替换:使用re.sub()函数替换字符串中的匹配项。
- 分割:使用re.split()函数按照匹配项分割字符串。
- 模式修正符:使用模式修正符可以更改模式匹配的行为,例如忽略大小写或多行匹配。
- 匹配对象:使用re.compile()函数可以将模式编译为匹配对象,以提高性能并重复使用模式。
re模块中的一些常用函数包括:
- re.match(pattern, string):从字符串的开头匹配模式并返回匹配对象,如果匹配失败则返回None。
- re.search(pattern, string):在字符串中搜索模式并返回匹配对象,如果匹配失败则返回None。
- re.findall(pattern, string):查找字符串中所有匹配项并以列表形式返回它们。
- re.sub(pattern, repl, string):在字符串中查找模式并用替换字符串repl替换所有匹配项。
- re.split(pattern, string):按照匹配项分割字符串并返回分割后的列表。
此外,re模块还提供了其他一些函数和常量,以支持更高级的正则表达式操作,例如:
- re.compile(pattern, flags):将模式编译为一个匹配对象,并支持可选的标志参数来更改匹配行为。
- re.IGNORECASE:用于指定匹配时忽略大小写。
- re.MULTILINE:用于指定多行匹配。
- re.DOTALL:用于指定匹配任何字符,包括换行符。
- re.ASCII:用于指定只匹配ASCII字符集。
- re.VERBOSE:用于在模式中使用注释和空格,以提高可读性。
2. re规则
1.字符匹配规则
规则 | 描述 |
. | 匹配任意字符(除了换行符) |
\w | 匹配字母、数字或下划线 |
\W | 匹配除了字母、数字或下划线以外的字符 |
\d | 匹配数字 |
\D | 匹配非数字字符 |
\s | 匹配任意空白字符(包括空格、制表符、换行符等) |
\S | 匹配任意非空白字符 |
2.重复匹配规则
- | 匹配前一个字符1次或多次
- ? | 匹配前一个字符0次或1次
- {m} | 匹配前一个字符恰好m次
- {m,} | 匹配前一个字符至少m次
- {m,n} | 匹配前一个字符至少m次,但不超过n次
且m和n均为非负整数,且m <= n。其中:
- 匹配前一个字符出现0次或多次,等价于{0,}。
- 匹配前一个字符出现1次或多次,等价于{1,}。
- ? 匹配前一个字符出现0次或1次,等价于{0,1}。
可以使用这些规则来匹配不同数量的字符,例如:
- 匹配一个数字:\d
- 匹配至少一个数字:\d+
- 匹配零个或一个数字:\d?
- 匹配3个数字:\d{3}
- 匹配至少3个数字:\d{3,}
- 匹配3到5个数字:\d{3,5}
3.位置匹配规则
规则 | 描述 |
^ | 匹配字符串的开头 |
$ | 匹配字符串的结尾 |
\b | 匹配单词边界 |
\B | 匹配非单词边界 |
4.分组和引用规则
规则 | 描述 |
( ) | 创建一个匹配组 |
(?: ) | 创建一个非捕获匹配组 |
\1, \2, ... | 引用前面的匹配组 |
5.特殊字符匹配规则
规则 | 描述 |
\ | 转义特殊字符 |
[] | 匹配方括号中任意一个字符 |
[^ ] | 匹配不在方括号中的任意一个字符 |
| | 匹配 | 左边或右边的表达式 |
() | 创建一个子模式,并在后续操作中引用它 |
3. re爬虫实战
3.1 具体要求
1.使用re模块,匹配所有的中文+标点符号+\s 2.爬取花千骨小说目录页面所有标题以及链接 3.爬取得到hrefList以及titleList列表发送请求爬取章节正文 findall search ... 4.文件夹 《花千骨》 01-水鬼拦路.txt ......
3.2 实现思路
首先,通过设置搜索的主url和get请求参数,使用requests模块爬取响应文件。
然后,通过设置响应文件的解格式和正则表达式,从响应对象中的html中获取小说目录的url。
接着,根据目录的url,使用requests模块爬取目录页面的数据,并将html传入到目录清洗函数。
在目录清洗函数中,查找list列表的值,并将前面多余的数据切除。
之后,通过正则表达式匹配,获取所有的目录章节内容,并循环遍历每个章节。
对于每个章节,调用获取章节详情页函数,爬取章节详情页数据。
在获取章节详情页数据后,使用正则表达式匹配章节标题和正文内容,将章节标题添加到titleList中,将正文内容拼接成正文。
最终,可以将整个小说的标题和正文保存。
3.3 实现代码
import os
# 设置用户代理
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36"
}
# 设置标题
titleList = []
import requests, re
'''1.搜索小说'''
def searchNovel(novel):
# 1.1 设置搜索的主url
searchUrl = "https://www.duquanben.com/api/search"
# 1.2 设置get请求参数
par = {
"q": novel
}
# 1.3 使用requests模块爬取响应文件
searchResp = requests.get(url=searchUrl,
params=par,
headers=headers)
# 1.4 设置响应文件的解格式
searchResp.encoding = 'utf-8'
# 1.5 获取响应对象中的html
searchHtml = searchResp.text
# \/xiaoshuo\/17\/17715\/
# \/xiaoshuo\/6\/6193\/
# 1.6 将数据中的\/替换成/
searchHtml = searchHtml.replace("\/", "/")
# 1.7 设置新的正则表达式
# 第一种正则表达式
# pattern = re.compile(r'/[a-z]+/\d+/\d+/')
# 第二种正则表达式
# pattern = re.compile(r'/[a-z]+/\d/\d+/')
# 第三种正则表达式
pattern = re.compile(r'/[a-z]{8}/\d{1}/\d{4}/')
fd = pattern.findall(searchHtml)
# 1.8 调用目录页面
getML(fd[0])
'''2.查找小说目录的所有内容'''
def getML(novelUrl):
# 2.1 设置完整url
# https://www.duquanben.com/xiaoshuo/6/6193/
mainUrl = "https://www.duquanben.com"
url = mainUrl + novelUrl
# 2.2 爬取目录的页面数据
mlResp = requests.get(url=url, headers=headers)
# 2.3 设置解码格式
mlResp.encoding = 'utf-8'
# 2.4 将html传入到目录清洗函数
getMLData(mlResp.text, mainUrl)
'''3.目录页面的数据清洗与获取'''
def getMLData(html, mlUrl):
# 3.1 查找list列表的值
htmlIndex = html.find("mulu_list")
#3.2 将前面多余的数据切除
html = html[htmlIndex:]
# /xiaoshuo/6/6193/3029016.html
# 3.3 设置目录的正则表达式
pattern = re.compile(r'/[a-z]{8}/\d{1}/\d{4}/\d+\.html')
# 3.4 匹配结果
hrefList = pattern.findall(html)
# 3.5 循环遍历所有的目录章节内容
for href in hrefList:
# 3.6 将href传递到详情页处理
getSection(href, mlUrl)
'''4.获取章节详情页'''
def getSection(href, mlUrl):
# 4.1 拼接Url
url = mlUrl + href
# 4.2 爬取详情页数据
sectionResp = requests.get(url=url, headers=headers)
# 4.3 设置解码格式
sectionResp.encoding = 'utf-8'
# 4.4 获取网页数据
html =sectionResp.text
# 4.5 调用章节页面解析函数
getSectionData(html)
'''5.章节页面数据解析'''
def getSectionData(html):
# 5.1 设置h1匹配正则表达式
# <h1>1.水鬼拦路</h1>
pattern = re.compile(r'\d+\.[\u4e00-\u9fa5]+')
sea = pattern.search(html)
# 5.2 将标题添加titleList中
titleList.append(sea.group())
# 5.3 设置content的正则表达式
# pattern2 = re.compile(r'(<p>{1}<br>{0,1}\s*[\u4e00-\u9fa5]+)+')
pattern2 = re.compile(r'(<p>{1}<br>{0,1}\s*(.|\n)+</p>{1})+')
fd = pattern2.findall(html)
# 5.4 将数据拼接成正文
content = []
# 5.5 循环遍历fd获取正文内容
for line in fd:
# 5.6 替换
line = str(line).replace("<p>", "")\
.replace("</p>", "")\
.replace("<br>", '\n')
# 5.7 将替换后的数据
content.append(line)
# 5.8 将content中的列表数据拼接
content = "".join(content)
# 5.9 保存数据
saveData(content, sea.group())
'''6.保存数据到文件夹中'''
def saveData(content,title):
# 6.1 新建文件
file = open("%s.txt" % title, 'w', encoding='utf-8')
# 6.2 写入
file.write(content)
# 6.3 关闭
file.close()
# 6.4 输出
print("已经写入了", title)
if __name__ == '__main__':
# 1.判断是否有花千骨文件夹
if "花千骨" not in os.listdir():
os.mkdir("花千骨")
os.chdir("花千骨")
searchNovel("花千骨")