批量爬取小说章节并优化排版(附完整可运行脚本)
批量爬取小说章节并优化排版附完整可运行脚本在日常学习和生活中我们经常会遇到想要保存喜欢的网络小说以便离线阅读的需求。手动复制粘贴每一章内容不仅耗时费力还容易出现排版混乱、格式错乱等问题。今天就带大家实战一款Python小说爬虫脚本实现批量爬取指定小说章节、自动优化排版还原小说段落换行、空行格式、自动创建文件夹保存章节文件全程代码可直接复制运行新手也能快速上手。本文将从页面标签结构分析、核心知识点拆解、完整脚本实现、脚本运行说明四个方面展开手把手教你搭建属于自己的小说爬虫最后预告下一篇内容——多线程优化脚本解决单线程爬取速度慢的问题进一步提升爬取效率。一、实战前提与环境准备在开始实战之前我们需要准备好基础的Python环境和相关依赖库确保脚本能够正常运行。1.1 环境要求Python版本3.7及以上推荐3.9兼容性更好依赖库requests发送HTTP请求、lxml解析HTML页面1.2 依赖库安装打开CMD终端输入以下命令安装所需依赖库安装速度慢的话可以切换国内镜像源如阿里云、豆瓣源pipinstallrequests lxml-ihttps://pypi.doubanio.com/simple/安装完成后可通过以下命令验证是否安装成功pip list|findstrrequests lxml# Windows系统pip list|greprequests lxml# Linux/Mac系统若能看到requests和lxml的版本信息说明依赖库安装成功。二、目标页面标签结构分析核心关键爬虫的核心是“找到目标内容”而找到目标内容的前提是分析页面的HTML标签结构。本次实战的目标是爬取小说的章节列表和每一章的正文内容我们先通过浏览器的“开发者工具”分析页面结构这也是爬虫实战中最基础、最重要的一步。2.1 章节列表页面结构分析我们首先访问小说的章节列表页面本文隐藏具体链接实际使用时替换为目标小说章节列表页即可右键点击页面空白处选择“检查”或按F12快捷键打开开发者工具切换到“Elements”标签即可查看页面的HTML结构。通过分析发现所有章节的链接都存放在一个无序列表中每个章节对应一个列表项列表项内部包含一个标签标签的href属性就是章节详情页的链接相对路径。关键标签结构简化如下保留核心部分bodydivclassmaindivclasschapter-listulliahref/book/xxxx/1.html第1章 开篇/a/liliahref/book/xxxx/2.html第2章 相遇/a/liliahref/book/xxxx/3.html第3章 转折/alt;/ligt;!-- 更多章节... --/ul/div/div/body基于这个结构我们可以使用XPath表达式定位到所有的标签进而提取每个章节的链接。本次实战中我们使用的XPath表达式为//html/body/div[1]/div[4]/ul/li该表达式可以精准定位到章节列表的所有列表项。2.2 章节详情页结构分析点击任意一个章节链接进入章节详情页同样通过开发者工具分析正文和标题的标签结构。章节标题章节标题存放在id为“neirong”的标签内部的标签中XPath表达式可定位为//*[idneirong]/h1/text()通过text()方法提取标题文本。章节正文章节正文存放在id为“txt”的标签中该标签内部包含大量的标签用于换行和文本内容。由于标签会导致文本换行直接提取文本会丢失换行格式因此我们需要提取该标签下的所有文本节点再重新排版。章节详情页核心标签结构简化如下dividneirongh1第1章 开篇/h1dividtxtp清晨的阳光透过窗户洒在书桌的旧书上。br/主角揉了揉眼睛缓缓坐起身脑海中还残留着昨晚的梦境。br/窗外的鸟鸣声此起彼伏预示着新的一天开始了。lt;br/gt;!-- 更多正文内容... --/p/div/div这里需要注意的是标签是HTML中的换行标签在爬取时我们需要将这些换行转换为文本中的换行符\n同时清理多余的空格和空行让排版符合小说阅读习惯段落之间空一行标题上下空行。三、核心知识点拆解新手必看本次实战脚本虽然简短但包含了Python爬虫的核心知识点掌握这些知识点能够帮助你应对大部分基础的静态页面爬虫需求。3.1 requests库发送HTTP请求requests库是Python中最常用的HTTP请求库简洁易用能够快速发送GET、POST等请求获取网页内容。本次实战中我们使用requests.get()方法发送GET请求获取章节列表页和章节详情页的HTML内容。关键知识点headers参数模拟浏览器发送请求避免被网站反爬。其中User-Agent是最常用的参数用于告诉网站服务器“我是一个正常的浏览器访问不是爬虫”。response.encoding设置网页编码格式避免出现乱码。本次实战中我们设置为“utf-8”适配大多数中文网站。response.text获取网页的HTML文本内容用于后续解析。3.2 lxml库与XPath解析HTML页面lxml库是一款高效的HTML/XML解析库支持XPath表达式能够快速定位和提取页面中的目标内容。XPath是一种在XML文档中查找信息的语言也适用于HTML文档语法简洁、定位精准是爬虫解析页面的首选工具。本次实战中常用的XPath语法//*[idtxt]定位id为“txt”的任意标签*表示任意标签。//*[idneirong]/h1/text()定位id为“neirong”的标签下的h1标签并提取其文本内容。//*[idtxt]//text()定位id为“txt”的标签下的所有文本节点包括子标签中的文本//表示递归查找所有子节点。./a/href定位当前节点下的a标签并提取其href属性值相对路径链接。3.3 os模块文件与文件夹操作os模块是Python中用于操作文件和文件夹的内置模块本次实战中我们使用os.path.exists()方法判断文件夹是否存在使用os.mkdir()方法创建文件夹确保章节文件能够正常保存到指定目录。关键代码解析ifnotos.path.exists(novel):os.mkdir(novel)这段代码的作用是判断当前目录下是否存在“novel”文件夹如果不存在则创建该文件夹避免后续写入文件时出现“路径不存在”的报错。3.4 文本排版优化网络小说的正文通常包含大量的换行标签直接提取文本会导致所有内容连在一起阅读体验极差。本次实战中我们通过以下步骤优化排版提取id为“txt”的标签下所有文本节点存入列表。遍历列表清理每个文本节点的多余空格strip()方法过滤掉空文本。用“\n\n”拼接所有文本实现段落之间空一行的效果小说标准排版。给章节标题上下各添加空行让标题与正文区分明显提升阅读体验。四、完整可运行脚本实战核心以下是本次实战的完整脚本已修复所有报错如chapter_title定义顺序错误优化排版逻辑隐藏具体书号和链接大家只需替换url_part和url_html为目标小说的域名和章节列表页链接即可直接运行实现批量爬取10章小说内容。importrequestsfromlxmlimportetreeimportos# 确保novel文件夹存在不存在则创建用于保存章节文件ifnotos.path.exists(novel):os.mkdir(novel)# 小说网站域名前缀替换为目标小说网站的域名url_parthttps://www.biquge365.net# 小说章节列表页链接替换为目标小说的章节列表页链接url_htmlhttps://www.biquge365.net/newbook/xxxx/# 请求头模拟浏览器访问避免被反爬headers{User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36}# 发送请求获取章节列表页HTML内容responserequests.get(urlurl_html,headersheaders)# 设置编码格式避免乱码response.encodingutf-8# 解析HTML页面treeetree.HTML(response.text)# 定位所有章节的列表项li标签提取章节链接litree.xpath(/html/body/div[1]/div[4]/ul/li)# 章节计数控制爬取的章节数量chapter_count0# 最大爬取章节数可根据需求修改max_chapter10# 遍历所有章节列表项爬取每一章内容foriinli:# 爬够指定章节数后停止ifchapter_countmax_chapter:break# 提取章节详情页的相对路径链接ai.xpath(./a/href)[0]# 拼接完整的章节详情页链接绝对路径urlurl_parta# 发送请求获取章节详情页内容responserequests.get(urlurl,headersheaders)response.encodingutf-8# 解析章节详情页HTMLtreeetree.HTML(response.text)# 提取章节标题id为neirong的div下的h1标签titletree.xpath(//*[idneirong]/h1/text())# 定义章节标题避免未定义报错如果获取不到标题自动命名为“第X章”chapter_titletitle[0].strip()iftitleelsef第{chapter_count1}章# 提取章节正文id为txt的div下的所有文本节点text_listtree.xpath(//*[idtxt]//text())# 优化排版清理空格、空文本按小说格式换行段落之间空一行lines[]fortintext_list:linet.strip()# 过滤掉空文本避免多余空行ifline:lines.append(line)# 拼接正文内容实现段落之间空一行content\n\n.join(lines)# 拼接完整章节内容标题上下空行提升阅读体验full_contentf\n{chapter_title}\n\n{content}\n\n# 写入文件保存到novel文件夹每个章节一个单独的txt文件withopen(fnovel/{chapter_title}.txt,w,encodingutf-8)asf:f.write(full_content)# 打印爬取进度print(f已成功写入{chapter_title})# 章节计数加1chapter_count1# 爬取完成提示print(f\n爬取完成共爬取{max_chapter}章文件已保存至当前目录下的novel文件夹中。)五、脚本运行说明与注意事项5.1 运行步骤复制上述完整脚本粘贴到Python编辑器如PyCharm、VS Code、IDLE等中。替换脚本中的url_part和url_htmlurl_part目标小说网站的域名如https://www.xxx.com。url_html目标小说的章节列表页链接打开小说章节列表复制浏览器地址栏中的链接即可。修改max_chapter可选如果想爬取更多章节可修改max_chapter的值如改为20即爬取20章。运行脚本等待爬取完成脚本会自动创建novel文件夹并将每一章内容保存为单独的txt文件。5.2 注意事项反爬处理脚本中已添加User-Agent请求头模拟浏览器访问避免被网站反爬。如果爬取时出现403、503等报错可更换User-Agent百度搜索“User-Agent大全”复制任意一个浏览器的User-Agent替换即可。编码问题如果爬取的内容出现乱码可尝试将response.encoding改为“gbk”部分中文网站使用gbk编码。标签结构变化如果脚本运行时出现“列表索引超出范围”的报错大概率是目标网站的标签结构发生了变化需要重新通过开发者工具分析页面结构修改对应的XPath表达式。合规爬取本脚本仅用于学习和个人研究请勿用于商业用途爬取时请遵守网站的robots协议不要过度频繁爬取避免给网站服务器造成压力。六、下一篇预告多线程优化脚本本次实战的脚本采用单线程爬取方式虽然逻辑简单、易于理解但存在一个明显的问题爬取速度慢。因为单线程需要等待一个章节爬取完成后才能开始爬取下一个章节尤其是当需要爬取大量章节如几百章、几千章时耗时非常长。下一篇文章我们将针对这个问题使用Python的threading模块多线程或concurrent.futures模块线程池对本次的爬虫脚本进行优化实现多章节同时爬取大幅提升爬取效率。下一篇核心内容预告多线程原理讲解为什么多线程能提升爬取速度线程池的使用避免手动创建过多线程提升脚本稳定性。多线程脚本修改在本次脚本基础上添加多线程逻辑实现批量快速爬取。多线程爬取注意事项避免并发过高被反爬控制线程数量。总结本次Python爬虫实战我们实现了从页面标签分析、核心知识点拆解到完整脚本编写的全过程成功实现了批量爬取小说章节、自动优化排版、自动保存文件的功能。通过本次实战相信大家已经掌握了基础的静态页面爬虫技巧包括requests发送请求、lxml解析页面、XPath定位内容、os模块操作文件等核心知识点。脚本已优化至无报错、排版美观新手可直接复制运行只需替换对应的链接即可。下一篇我们将通过多线程优化脚本解决单线程爬取速度慢的问题让爬虫效率再上一个台阶感兴趣的小伙伴可以持续关注如果在运行脚本过程中遇到问题欢迎在评论区留言我会一一解答。记得点赞、收藏、关注后续会分享更多Python爬虫实战教程