1. 准备工作与环境搭建想要用Python爬取飞卢小说网的小说内容首先得准备好趁手的工具。就像木匠干活前要检查斧头是否锋利一样我们需要确保开发环境配置正确。这里我推荐使用Python 3.6及以上版本因为新版本对字符串编码处理更加友好能减少很多莫名其妙的乱码问题。安装核心库只需要一行命令pip install requests这个库比Python自带的urllib好用太多了——自动处理连接池、支持文件上传、能轻松添加HTTP头部最关键的是用起来特别符合人类直觉。我刚开始学爬虫时被urllib的复杂API折磨得不轻直到发现requests才体会到爬虫的乐趣。2. 分析目标网站结构飞卢小说网的页面结构有个明显特征小说章节页面的URL都是在基础URL后追加章节编号。比如基础URL是https://b.faloo.com/123456.html那么第5章就是https://b.faloo.com/123456_5.html。这种规律性让爬取工作变得简单很多。通过浏览器开发者工具F12查看网页源码会发现小说正文都包裹在p标签里。这里有个坑要注意有些p标签里可能是广告内容需要根据实际内容进行过滤。我上次爬取时就遇到过章节里突然出现点击下载APP看更多精彩内容的干扰文本。3. 核心爬取代码实现先来看完整的爬虫函数我会逐段解释关键部分import requests import re import os def crawl_novel(novel_id): base_url fhttps://b.faloo.com/{novel_id}.html response requests.get(base_url) # 获取小说总章节数 chapter_pattern ra href.? target_self title.? total_chapters len(re.findall(chapter_pattern, response.text)) # 提取小说标题 title_pattern rtitle(.?)/title novel_title re.search(title_pattern, response.text).group(1) print(f开始爬取《{novel_title}》共{total_chapters}章) # 创建保存目录 save_dir os.path.join(os.getcwd(), novel_title) os.makedirs(save_dir, exist_okTrue) # 逐章爬取 for chapter in range(1, total_chapters 1): chapter_url fhttps://b.faloo.com/{novel_id}_{chapter}.html chapter_response requests.get(chapter_url) # 提取章节标题 chapter_title re.search(title_pattern, chapter_response.text).group(1) print(f正在爬取第{chapter}章{chapter_title}) # 提取正文内容 content_pattern rp(.?)/p paragraphs re.findall(content_pattern, chapter_response.text) # 保存到文件 file_path os.path.join(save_dir, f{chapter_title}.txt) with open(file_path, w, encodingutf-8) as f: for para in paragraphs: f.write(para \n) print(f第{chapter}章保存成功) return novel_title这段代码有几个关键点值得注意正则表达式优化原始代码中的正则匹配模式lt;pgt;其实是HTML实体编码直接用p更直观。我测试发现飞卢的页面源码中确实是原始标签。异常处理增强增加了exist_okTrue参数避免目录已存在时报错。实际运行中网络请求可能会超时生产环境还应该添加重试机制。编码处理明确指定文件写入编码为UTF-8这是处理中文内容的必备操作。有次我忘了设置编码结果打开文件全是乱码排查了半天才发现问题。4. 反爬应对策略现在的网站基本都有反爬机制飞卢小说网虽然不算严格但也需要做些基本防护请求头设置最好添加User-Agent模拟浏览器访问headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 } response requests.get(url, headersheaders)请求频率控制在循环中添加time.sleep(1)避免请求过于密集。我有次没加延迟爬了200章后IP就被临时封禁了。代理设置如果需要大规模爬取建议使用代理IP池proxies { http: http://10.10.1.10:3128, https: http://10.10.1.10:1080 } requests.get(url, proxiesproxies)5. 内容清洗与优化原始爬取的内容可能包含一些不需要的元素比如广告文本过滤可以通过关键词黑名单过滤blacklist [飞卢小说网, 最帅更新] paragraphs [p for p in paragraphs if not any(word in p for word in blacklist)]空白段落处理有些p标签里只有空格或换行符paragraphs [p.strip() for p in paragraphs if p.strip()]章节标题规范化有些标题会带网站后缀可以去掉chapter_title chapter_title.replace( - 飞卢小说网, )6. 文件存储优化原始代码为每个章节创建单独文件当章节数很多时会显得零散。可以考虑以下优化方案合并存储所有章节存到一个文件用分隔符隔开with open(full_novel.txt, a, encodingutf-8) as f: f.write(f\n\n 第{chapter}章 {chapter_title} \n\n) f.write(\n.join(paragraphs))EPUB格式使用python-epub库生成电子书格式方便在阅读器上查看from epub import create_epub book create_epub.Book() book.add_chapter(titlechapter_title, content\n.join(paragraphs)) book.save(f{novel_title}.epub)数据库存储如果要做全文搜索可以存入SQLite或MongoDBimport sqlite3 conn sqlite3.connect(novels.db) cursor conn.cursor() cursor.execute(INSERT INTO chapters VALUES (?,?,?), (novel_title, chapter, \n.join(paragraphs))) conn.commit()7. 完整代码示例下面是一个增强版的完整实现包含了上述提到的各种优化import requests import re import os import time from typing import Optional class NovelCrawler: def __init__(self): self.headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36, Accept-Language: zh-CN,zh;q0.9 } self.blacklist [飞卢小说网, 最帅更新, APP] def get_total_chapters(self, novel_id: str) - Optional[int]: url fhttps://b.faloo.com/{novel_id}.html try: response requests.get(url, headersself.headers, timeout10) response.raise_for_status() pattern ra href.? target_self title.? return len(re.findall(pattern, response.text)) except Exception as e: print(f获取章节数失败: {e}) return None def crawl_chapter(self, novel_id: str, chapter: int) - Optional[dict]: url fhttps://b.faloo.com/{novel_id}_{chapter}.html try: response requests.get(url, headersself.headers, timeout10) response.encoding utf-8 # 提取标题 title_match re.search(rtitle(.?)/title, response.text) if not title_match: return None title title_match.group(1).replace( - 飞卢小说网, ) # 提取正文并过滤 paragraphs re.findall(rp(.?)/p, response.text) paragraphs [p.strip() for p in paragraphs if p.strip() and not any(w in p for w in self.blacklist)] return { title: title, content: paragraphs, chapter: chapter } except Exception as e: print(f爬取第{chapter}章失败: {e}) return None def save_to_file(self, novel_title: str, data: dict, save_dir: str): os.makedirs(save_dir, exist_okTrue) file_path os.path.join(save_dir, f{data[chapter]}_{data[title]}.txt) with open(file_path, w, encodingutf-8) as f: f.write(f{data[title]}\n\n) f.write(\n.join(data[content])) def crawl(self, novel_id: str, start_chapter1, delay1): total self.get_total_chapters(novel_id) if not total: return False first_chapter self.crawl_chapter(novel_id, 1) if not first_chapter: return False novel_title first_chapter[title].split(_)[0] save_dir os.path.join(os.getcwd(), novel_title) print(f开始爬取《{novel_title}》共{total}章) for chapter in range(start_chapter, total 1): data self.crawl_chapter(novel_id, chapter) if data: self.save_to_file(novel_title, data, save_dir) print(f第{chapter}/{total}章保存成功: {data[title]}) time.sleep(delay) return True if __name__ __main__: crawler NovelCrawler() novel_id input(请输入小说ID: ) crawler.crawl(novel_id)这个版本的主要改进包括使用面向对象封装方便复用和扩展添加了类型提示(Type hints)代码更清晰完善的错误处理和日志输出可配置的爬取延迟和起始章节更健壮的内容过滤机制8. 常见问题与解决方案在实际使用中你可能会遇到这些问题Q1: 爬取速度很慢怎么办A: 可以尝试使用Session保持连接session requests.Session()启用HTTP持久连接在headers中添加Connection: keep-alive适当减少延迟时间但不要小于0.5秒Q2: 总是获取到验证页面怎么办A: 飞卢可能会对频繁请求弹出验证解决方法随机化User-Agent可以从列表轮换添加Referer头Referer: https://b.faloo.com/模拟完整浏览器行为添加CookieQ3: 正则表达式匹配不到内容A: 可能页面结构有变应该先打印出response.text查看实际获取的页面使用更宽松的正则比如rp.*?(.?)/p考虑改用BeautifulSoup等HTML解析库Q4: 文件内容出现乱码A: 编码问题可以这样处理确保response.encoding utf-8文件写入时明确指定encodingutf-8遇到特殊字符可以尝试errorsignore参数9. 扩展思路掌握了基础爬取方法后你还可以尝试这些进阶功能增量爬取记录已爬章节只获取新内容import pickle if os.path.exists(progress.pkl): with open(progress.pkl, rb) as f: progress pickle.load(f) else: progress {last_chapter: 0}内容分析使用jieba库进行中文分词和关键词提取import jieba.analyse keywords jieba.analyse.extract_tags(\n.join(paragraphs), topK10)自动发布将爬取内容自动发布到WordPress等平台import wordpress_xmlrpc client wordpress_xmlrpc.Client(https://example.com/xmlrpc.php, user, pass) post wordpress_xmlrpc.WordPressPost() post.title chapter_title post.content \n.join(paragraphs) client.call(posts.NewPost(post))监控更新使用定时任务定期检查小说更新import schedule def job(): current_chapters crawler.get_total_chapters(novel_id) if current_chapters last_chapters: print(f发现{current_chapters - last_chapters}章更新) schedule.every(6).hours.do(job) while True: schedule.run_pending() time.sleep(1)10. 法律与道德提醒虽然技术本身是中立的但在实际应用中需要注意尊重网站的robots.txt协议不要对服务器造成过大负担爬取的内容仅限个人学习使用不要绕过付费章节获取内容考虑使用官方API替代爬虫(如果有的话)我刚开始做爬虫时曾因为请求太频繁被封过IP后来学会了控制节奏既完成了数据收集又不影响网站正常运行。技术人应该有这样的自觉——我们解决问题而不是制造问题。