网页小说爬取与转换工具:从
HTML 到 Markdown 的自动化解决方案
一、项目概述
本项目是一个用于爬取并格式化网页小说的 Python
脚本,它能够自动抓取小说内容并将其转换为 Markdown
格式,方便用户离线阅读和整理。脚本采用了多线程技术来加速下载过程,同时处理了特殊字符编码和分页问题,确保生成的
Markdown 文件内容完整且格式规范。
主要功能包括:
自动获取小说目录和各章节链接
处理网页中的特殊字符和图标
支持多线程并行下载多个章节
自动检测并合并分页内容
生成格式良好的 Markdown 文件
二、核心功能模块
1. 网页内容获取与解析
1 2 3 4 5 6 7 8 9 10 11 def get_html_text (url ): headers = { 'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36 Edg/129.0.0.0' , 'cookie' : 'jq_Obj=1; ff54ff0fa0f557568e6e69d35b815894=fcad32351f41e0bacbc3c4dc74b2a721; zh_choose=n; _ga=GA1.1.234751423.1728474308; _ga_YN9485YEKE=GS1.1.1728535222.6.1.1728536491.0.0.0' } try : r = requests.get(url, headers=headers) r.encoding = r.apparent_encoding return r.text except : return ""
这个函数负责发送 HTTP
请求获取网页内容,并自动检测和设置正确的编码,确保中文内容能正常显示。
2. 目录处理与 URL 管理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 def fetch_and_save_urls (url ): html = get_html_text(url) soup = BeautifulSoup(html, 'html.parser' ) ul_tag = soup.find('ul' , class_='chaw_c' ) a_all = ul_tag.find_all('a' ) urls = [] for a in a_all: a_url = a.get('href' ) a_title = a.text urls.append({a_title: a_url}) with open ('urls.yaml' , 'w' , encoding='utf-8' ) as file: yaml.safe_dump(urls, file) return urlsdef read_urls (url ): try : with open ('urls.yaml' , 'r' ) as file: print ('读取本地:urls' ) return yaml.safe_load(file) except FileNotFoundError: return fetch_and_save_urls(url)
这部分代码处理小说目录页,提取所有章节的 URL 和标题,并将其保存到
YAML 文件中。下次运行时会优先读取本地文件,避免重复爬取。
3. 特殊字符处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 def read_css_dict (css_url ): try : with open ('css_dict.yml' , 'r' ) as file: css_dict = yaml.safe_load(file) print ('读取本地:css_dict' ) return css_dict except FileNotFoundError: css_content = get_html_text(css_url) icon_pattern = r'\.icon-(.*?):before\s*\{\s*content:\s*"(.*?)";\s*\}' css_dict = re.findall(icon_pattern, css_content) with open ('css_dict.yml' , 'w' ) as file: yaml.safe_dump(css_dict, file) return css_dictdef replace_content (css_dict, html_content ): icon_dict = {} for icon_class, content in css_dict: try : content_bytes = bytes ([int (content[1 :3 ], 16 ), int (content[3 :], 16 )]) decoded_str = content_bytes.decode('utf-16be' ) icon_dict[f'icon-{icon_class} ' ] = decoded_str except UnicodeDecodeError: print (f"无法正确解码 icon-{icon_class} 的内容。" ) soup = BeautifulSoup(html_content, 'html.parser' ) div = soup.find('div' , id ='mlfy_main_text' ) for icon_class, utf8_content in icon_dict.items(): for i_tag in div.find_all('i' , {'class' : lambda c: icon_class in c}): if not i_tag.string: i_tag.string = utf8_content else : i_tag.string = i_tag.string + utf8_content return str (soup)
这部分代码处理网页中的特殊图标和字符。通过解析 CSS
文件,提取图标对应的编码,并将其替换为实际字符,确保内容完整。
4. 分页处理
1 2 3 4 5 6 7 8 9 10 11 12 def if_has_next (url_next ): html = get_html_text(url_next) pattern = r'url_next:\s*"(.*?)"' match = re.search(pattern, html) if match : url_next_value = match .group(1 ) if '_' in url_next_value: return url_next_value else : return None else : return None
该函数检测章节是否有下一页,并返回下一页的
URL,用于后续内容合并。
5. Markdown 转换与保存
1 2 3 4 5 6 7 8 def save_page_content (html_content, chapter ): h = html2text.HTML2Text() markdown_content = ((h.handle(html_content) .replace('_' , '' ) .replace(' ' , '' )) .replace('铅笔小说网qianbiwenxue.com' , '' )) with open ('无敌剑域/' + chapter + '.md' , 'w' , encoding='utf-8' ) as file: file.write(markdown_content)
这个函数将 HTML 内容转换为 Markdown
格式,并保存到文件中。它会移除多余的空格和网站标识,使生成的文件更加简洁。
6. 多线程处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 def process_html_pages (chapter, url ): thread_id = threading.current_thread().ident html_content = '' while url: html = get_html_text(url) html_content += replace_content(css_dict, html) url = if_has_next(url) save_page_content(html_content, chapter) end_time = time.time() elapsed_time = end_time - start_time return f'线程:{thread_id} 下载章节《{chapter} 》完毕--当前用时:{elapsed_time:.5 f} 秒。' with concurrent.futures.ThreadPoolExecutor() as executor: future_to_task = {executor.submit(process_html_pages, list (item.keys())[0 ], list (item.values())[0 ]): item for item in url_s} for future in concurrent.futures.as_completed(future_to_task): task = future_to_task[future] try : result = future.result() print (result) except Exception as exc: print (f"{list (task.keys())[0 ]} 产生了一个异常:{exc} " ) failed_tasks.append(task)
这部分代码实现了多线程下载功能,通过线程池并行处理多个章节,大大提高了下载效率。同时还包含了失败重试机制,确保所有章节都能成功下载。
三、项目使用方法
安装必要的依赖库:
1 pip install requests beautifulsoup4 pyyaml html2text
修改代码中的 URL:
将url变量设置为目标小说的目录页 URL
将css_url变量设置为网站的 CSS 文件 URL
运行脚本:
等待下载完成,所有章节将以 Markdown 格式保存在 “无敌剑域”
文件夹中
四、项目优化建议
添加进度条显示,让用户更直观地了解下载进度
增加配置文件,将 URL、保存路径等参数外部化,提高灵活性
改进异常处理机制,对不同类型的异常进行分类处理
添加断点续传功能,支持从上次中断的位置继续下载
增加对不同网站结构的支持,提高通用性
这个项目展示了如何使用 Python
进行网页爬取和内容处理,通过多线程技术提高效率,并利用正则表达式和
BeautifulSoup
处理复杂的网页结构。代码结构清晰,功能完整,可以作为类似项目的基础框架进行扩展。