1. 项目背景与核心思路
作为一个常年混迹各大小说网站的资深书虫,我最近被两件事折磨得够呛:一是满屏飞舞的弹窗广告,二是那些敷衍到极致的章节标题。你能想象连续看到"第101章 出手"、"第102章 再次出手"这种标题时的心情吗?作为一个有追求的Python开发者,我决定用技术手段解决这个问题。
这个项目的核心思路其实很简单:先用爬虫把小说内容完整抓取下来,然后用AI模型对每章内容进行分析,生成更吸引人的标题。听起来容易,但实际操作中涉及到不少技术细节和坑点。下面我就把整个实现过程拆解开来,包括爬虫构建、反爬应对、AI接口调用等关键环节,以及那些只有实操过才会知道的注意事项。
特别声明:本项目仅用于技术学习交流,请勿用于商业用途或侵犯版权。建议大家在本地运行代码,仅爬取自己已购买或有权限阅读的内容。
2. 技术选型与架构设计
2.1 整体架构
整个系统采用模块化设计,主要分为三个部分:
- 爬取模块:负责从目标网站获取小说目录和正文内容
- 存储模块:将爬取的内容结构化保存到本地
- 标题生成模块:调用AI模型生成新标题
这种分层设计的好处是各模块职责明确,后续维护和扩展都很方便。比如想换AI模型时,只需要修改标题生成模块,其他部分完全不用动。
2.2 技术栈选择
经过多方比较,我最终确定了以下技术方案:
-
爬虫部分:
requests+BeautifulSoup4:轻量级组合,适合中小型爬虫项目fake-useragent:用于随机生成User-Agentlxml:作为BeautifulSoup的解析器,性能更好
-
AI部分:
- OpenAI API(GPT-3.5-turbo):标题生成效果稳定
tiktoken:用于计算token数量控制成本
-
其他工具:
logging:记录运行日志json:配置文件存储time+random:控制请求频率
没有选择Scrapy这样的重型框架,是因为我们的需求相对简单,没必要引入复杂的架构。同样,AI部分也没有使用本地模型,主要是考虑到部署成本和开发效率。
3. 爬虫实现细节
3.1 网站分析
首先需要分析目标网站的结构。以典型的小说网站为例,一般会有以下几种页面:
- 目录页:包含所有章节链接
- 正文页:单章小说内容
- 搜索页:通过书名搜索(可选)
通过Chrome开发者工具分析,我发现这个网站的结构还算规整:
- 目录页:
/book/{book_id}/ - 章节页:
/chapter/{chapter_id}/ - 章节链接都在
<div class="chapter-list">下的<a>标签中 - 正文内容在
<div id="content">内
3.2 基础爬虫实现
先实现最基础的爬取功能:
python复制import requests
from bs4 import BeautifulSoup
from fake_useragent import UserAgent
def get_html(url):
headers = {'User-Agent': UserAgent().random}
response = requests.get(url, headers=headers)
response.encoding = 'utf-8' # 很多小说网站使用utf-8编码
return response.text
def parse_chapter_list(html):
soup = BeautifulSoup(html, 'lxml')
chapter_list = []
for a in soup.select('.chapter-list a'):
chapter_list.append({
'title': a.text.strip(),
'url': a['href']
})
return chapter_list
def parse_chapter_content(html):
soup = BeautifulSoup(html, 'lxml')
content = soup.select_one('#content').text
return content.strip()
这个基础版本已经能完成最简单的爬取功能,但还远远不够健壮。
3.3 反爬应对策略
在实际运行中,我遇到了几个常见的反爬问题:
- IP封禁:连续请求太快会被封IP
- User-Agent检测:使用固定UA会被识别
- 请求频率限制:网站对高频请求有限制
针对这些问题,我加入了以下防护措施:
python复制import time
import random
def safe_get(url, max_retries=3):
headers = {'User-Agent': UserAgent().random}
for _ in range(max_retries):
try:
response = requests.get(url, headers=headers, timeout=10)
response.raise_for_status()
response.encoding = 'utf-8'
time.sleep(random.uniform(1, 3)) # 随机延迟1-3秒
return response.text
except Exception as e:
print(f"请求失败: {e}, 重试中...")
time.sleep(random.uniform(5, 10))
return None
此外,还可以考虑使用代理IP池,但对于个人项目来说成本较高,我暂时没有采用。
3.4 数据存储设计
爬取的数据需要合理存储,我设计了这样的结构:
code复制novels/
├── {book_name}/
│ ├── meta.json # 书籍元信息
│ ├── chapters/ # 章节内容
│ │ ├── 1.json # 每章原始数据
│ │ ├── 2.json
│ │ └── ...
│ └── processed/ # 处理后的数据
│ ├── 1.txt # 格式化后的正文
│ └── ...
对应的存储代码如下:
python复制import os
import json
def save_chapter(book_name, chapter):
# 创建目录
os.makedirs(f'novels/{book_name}/chapters', exist_ok=True)
os.makedirs(f'novels/{book_name}/processed', exist_ok=True)
# 保存原始数据
with open(f'novels/{book_name}/chapters/{chapter["id"]}.json', 'w') as f:
json.dump(chapter, f, ensure_ascii=False, indent=2)
# 保存处理后的正文
with open(f'novels/{book_name}/processed/{chapter["id"]}.txt', 'w') as f:
f.write(f"{chapter['title']}\n\n")
f.write(chapter['content'])
4. AI标题生成实现
4.1 标题生成策略
好的小说标题应该具备以下特点:
- 概括章节核心情节
- 留有悬念吸引读者
- 符合小说整体风格
- 长度适中(通常6-12字)
基于这些要求,我设计了这样的提示词(prompt):
code复制你是一个专业的小说编辑,请根据以下章节内容生成一个吸引人的章节标题。要求:
1. 标题长度6-12个汉字
2. 准确概括章节核心事件
3. 使用玄幻小说风格的词汇
4. 避免剧透关键情节
5. 保持悬念和吸引力
章节内容:
{content}
请直接输出标题,不要包含其他说明。
4.2 OpenAI API调用
使用OpenAI API的Python SDK实现标题生成:
python复制import openai
from tiktoken import encoding_for_model
def count_tokens(text, model="gpt-3.5-turbo"):
enc = encoding_for_model(model)
return len(enc.encode(text))
def generate_title(content, model="gpt-3.5-turbo"):
prompt = f"""你是一个专业的小说编辑...""" # 上面定义的prompt
messages = [
{"role": "system", "content": "你是一个专业的小说编辑"},
{"role": "user", "content": prompt.format(content=content)}
]
try:
response = openai.ChatCompletion.create(
model=model,
messages=messages,
temperature=0.7,
max_tokens=20
)
return response.choices[0].message.content.strip('"\'')
except Exception as e:
print(f"生成标题失败: {e}")
return None
4.3 成本控制技巧
使用AI API最大的问题是成本,特别是处理长篇小说时。我采用了以下几种优化策略:
- 内容截断:只发送前2000字给AI,通常足够生成标题
- 批量处理:攒够一定数量章节后一次性生成,减少API调用次数
- 本地缓存:已经生成的标题保存到本地,避免重复生成
- Token计数:使用tiktoken精确计算token使用量
实现代码示例:
python复制def smart_content_truncate(content, max_tokens=2000):
if count_tokens(content) <= max_tokens:
return content
# 中文按字符粗略估算(1个汉字≈1.5 token)
max_chars = int(max_tokens * 0.67)
return content[:max_chars] + "...[内容已截断]"
5. 系统集成与优化
5.1 主流程实现
将各个模块组合起来形成完整流程:
python复制def process_novel(book_url):
# 1. 获取目录
html = safe_get(book_url)
chapters = parse_chapter_list(html)
# 2. 获取各章内容
for i, chapter in enumerate(chapters[:5]): # 测试时只爬5章
print(f"正在处理第{i+1}章: {chapter['title']}")
content_html = safe_get(chapter['url'])
content = parse_chapter_content(content_html)
# 3. 生成新标题
short_content = smart_content_truncate(content)
new_title = generate_title(short_content)
# 4. 保存结果
save_chapter("test_book", {
"id": i+1,
"original_title": chapter['title'],
"new_title": new_title,
"content": content
})
print(f"原标题: {chapter['title']}")
print(f"新标题: {new_title}")
print("-" * 50)
5.2 效果展示
运行程序后,可以看到标题优化效果非常明显:
| 原标题 | AI生成标题 |
|---|---|
| 第1章 觉醒 | 第1章 神秘血脉初觉醒 |
| 第2章 测试 | 第2章 天赋测试惊众人 |
| 第3章 冲突 | 第3章 擂台比武结仇怨 |
| 第4章 突破 | 第4章 九死一生破瓶颈 |
| 第5章 奇遇 | 第5章 古洞偶得神秘传承 |
可以看到,AI生成的标题不仅更有吸引力,还能准确反映章节的核心内容。
6. 踩坑经验与优化建议
6.1 常见问题与解决方案
-
请求被封禁
- 现象:突然获取不到任何数据
- 解决:增加随机延迟,更换User-Agent,使用代理IP
-
HTML结构变化
- 现象:解析不到内容
- 解决:定期检查解析规则,增加多种选择器备选
-
AI生成标题质量不稳定
- 现象:偶尔生成无关标题
- 解决:优化prompt,增加生成温度(temperature)调节
-
API调用超限
- 现象:收到429错误
- 解决:实现指数退避重试机制
6.2 性能优化建议
- 异步爬取:使用
aiohttp替代requests,提升爬取效率 - 本地缓存:对已爬取章节建立缓存,避免重复爬取
- 分布式爬取:对于大型项目,可以考虑使用Scrapy-Redis
- 本地模型部署:使用Ollama部署Qwen等开源模型,减少API依赖
6.3 扩展功能思路
- 多网站适配:通过配置文件支持不同网站结构
- 电子书生成:将处理后的内容转为EPUB格式
- 风格定制:针对不同小说类型(玄幻、都市等)定制标题风格
- 内容摘要:除了标题,还可以生成章节摘要
7. 完整代码结构
以下是项目的完整目录结构和核心代码文件:
code复制novel-ai-title/
├── config.py # 配置文件
├── crawler.py # 爬虫核心逻辑
├── title_generator.py # 标题生成模块
├── utils.py # 工具函数
└── main.py # 主入口
核心代码已经分享在文中关键部分,完整代码可以参考我的GitHub仓库(地址见文末)。
8. 法律与道德考量
在结束之前,我必须再次强调这个项目的注意事项:
- 尊重版权:仅爬取你有权访问的内容
- 控制频率:不要对目标网站造成负担
- 遵守robots.txt:尊重网站的爬虫规则
- 个人使用:不要将爬取内容用于商业用途
技术本身没有对错,关键在于如何使用。希望大家能用这个项目学习技术,而不是侵犯他人权益。
这个项目最让我惊喜的不是技术实现,而是AI生成标题的质量。那些原本平淡的章节,在有了好标题后,阅读体验真的提升了不少。如果你也是个小说爱好者,不妨试试这个方案,给你的阅读清单加点料。