1. re模块简介

Python的re模块是一个用于正则表达式操作的标准库,它允许开发者对文本进行高效的模式匹配和搜索。

re模块提供了许多功能,包括:

  1. 匹配:使用re.match()或re.search()函数在字符串中查找模式匹配项。
  2. 替换:使用re.sub()函数替换字符串中的匹配项。
  3. 分割:使用re.split()函数按照匹配项分割字符串。
  4. 模式修正符:使用模式修正符可以更改模式匹配的行为,例如忽略大小写或多行匹配。
  5. 匹配对象:使用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("花千骨")