首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Python爬取小说网站全本下载:从入门到反爬实战

Python爬取小说网站全本下载:从入门到反爬实战

原创
作者头像
富贵软件
发布2025-10-14 15:19:28
发布2025-10-14 15:19:28
3400
代码可运行
举报
文章被收录于专栏:编程教程编程教程
运行总次数:0
代码可运行

​免费编程软件「python+pycharm」

链接:https://pan.quark.cn/s/48a86be2fdc0

一、为什么需要自己爬小说?

每天都有数百万读者在小说网站追更,但免费章节看一半突然收费、网站广告弹窗满天飞、手机浏览器卡成PPT……这些痛点让许多读者选择自己动手爬取全本小说。用Python写个爬虫,不仅能实现自动下载,还能把小说转换成mobi/epub格式,在Kindle或微信读书上舒服阅读。

核心价值点:

  • 摆脱广告干扰:纯文本阅读体验
  • 永久保存:避免网站下架导致书荒
  • 格式自由:转换成任何电子书格式
  • 批量处理:一次性下载整本小说

二、基础爬虫实现(30分钟上手)

1. 环境准备

代码语言:javascript
代码运行次数:0
运行
复制
# 安装必要库
pip install requests beautifulsoup4 fake_useragent

2. 简单爬取示例

以笔趣阁为例(示例域名,实际使用时请替换):

代码语言:javascript
代码运行次数:0
运行
复制
import requests
from bs4 import BeautifulSoup

def get_chapter(url):
    headers = {'User-Agent': 'Mozilla/5.0'}
    try:
        response = requests.get(url, headers=headers, timeout=10)
        soup = BeautifulSoup(response.text, 'html.parser')
        # 笔趣阁内容通常在id="content"的div中
        content = soup.find('div', id='content').text.strip()
        return content
    except Exception as e:
        print(f"获取章节失败: {e}")
        return None

# 测试获取第一章
print(get_chapter("https://www.example.com/book/1.html"))

3. 获取全本目录

代码语言:javascript
代码运行次数:0
运行
复制
def get_chapter_list(book_url):
    headers = {'User-Agent': 'Mozilla/5.0'}
    response = requests.get(book_url, headers=headers)
    soup = BeautifulSoup(response.text, 'html.parser')
    
    # 笔趣阁目录通常在class="listmain"的ul中
    chapters = []
    for li in soup.select('.listmain ul li a'):
        chapters.append({
            'title': li.text.strip(),
            'url': li['href']
        })
    return chapters

# 获取某本书所有章节链接
chapters = get_chapter_list("https://www.example.com/book/")
for i, chap in enumerate(chapters[:5], 1):  # 打印前5章
    print(f"{i}. {chap['title']}: {chap['url']}")

三、进阶功能实现

1. 多线程下载(提速5-10倍)

代码语言:javascript
代码运行次数:0
运行
复制
import concurrent.futures

def download_book(chapters, output_file):
    all_content = []
    
    def fetch_chapter(chapter):
        content = get_chapter(chapter['url'])
        if content:
            return f"\n\n{chapter['title']}\n\n{content}"
        return ""
    
    with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
        results = executor.map(fetch_chapter, chapters)
        all_content = [content for content in results if content]
    
    with open(output_file, 'w', encoding='utf-8') as f:
        f.write("\n".join(all_content))
    print(f"小说已保存至 {output_file}")

# 使用示例
chapters = get_chapter_list("https://www.example.com/book/")
download_book(chapters, "小说全本.txt")

2. 转换为电子书格式

使用ebooklib库生成epub:

代码语言:javascript
代码运行次数:0
运行
复制
from ebooklib import epub

def create_epub(chapters, book_name):
    book = epub.EpubBook()
    book.set_title(book_name)
    book.set_language('zh')
    
    # 添加章节
    for chapter in chapters:
        content = get_chapter(chapter['url'])
        if content:
            c1 = epub.EpubHtml(
                title=chapter['title'],
                file_name=f"{chapter['title'].replace('/', '_')}.xhtml",
                lang='zh',
                content=f"<h1>{chapter['title']}</h1><p>{content}</p>"
            )
            book.add_item(c1)
            book.toc.append((chapter['title'], [c1], False))
    
    # 添加元数据
    book.add_author('匿名')
    
    # 生成epub
    epub.write_epub(f"{book_name}.epub", book, {})
    print(f"EPUB文件已生成: {book_name}.epub")

# 使用示例
chapters = get_chapter_list("https://www.example.com/book/")
create_epub(chapters, "我的小说")

四、反爬策略实战

1. 基础反爬应对

代码语言:javascript
代码运行次数:0
运行
复制
# 随机User-Agent
from fake_useragent import UserAgent

def get_random_ua():
    ua = UserAgent()
    return ua.random

headers = {'User-Agent': get_random_ua()}

2. 代理IP池实现

代码语言:javascript
代码运行次数:0
运行
复制
import random

class ProxyPool:
    def __init__(self):
        # 购买站大爷代理IP
        self.proxies = [
            {'http': 'http://1.1.1.1:8080'},
            {'http': 'http://2.2.2.2:8080'},
            # 更多代理...
        ]
    
    def get_proxy(self):
        return random.choice(self.proxies)

# 使用代理
proxy = ProxyPool().get_proxy()
response = requests.get(url, headers=headers, proxies=proxy, timeout=10)

3. 处理验证码

对于简单的图形验证码,可以使用pytesseract

代码语言:javascript
代码运行次数:0
运行
复制
from PIL import Image
import pytesseract
import io

def solve_captcha(img_bytes):
    img = Image.open(io.BytesIO(img_bytes))
    # 转换为灰度图提高识别率
    img = img.convert('L')
    # 二值化处理
    threshold = 140
    table = []
    for i in range(256):
        if i < threshold:
            table.append(0)
        else:
            table.append(1)
    img = img.point(table, '1')
    return pytesseract.image_to_string(img)

# 使用示例(需要先获取验证码图片)
# captcha_text = solve_captcha(captcha_img_bytes)

4. 模拟浏览器行为

使用selenium模拟真实用户操作:

代码语言:javascript
代码运行次数:0
运行
复制
from selenium import webdriver
from selenium.webdriver.chrome.options import Options

def selenium_get(url):
    chrome_options = Options()
    chrome_options.add_argument("--headless")  # 无头模式
    chrome_options.add_argument(f"user-agent={get_random_ua()}")
    
    driver = webdriver.Chrome(options=chrome_options)
    driver.get(url)
    
    # 等待页面加载(可根据实际情况调整)
    driver.implicitly_wait(10)
    
    # 获取内容(示例获取body文本)
    content = driver.find_element_by_tag_name('body').text
    driver.quit()
    return content

五、完整项目结构

novel_crawler/

├── config.py # 配置文件

├── proxies.py # 代理池管理

├── parser.py # 页面解析器

├── downloader.py # 下载器

├── converter.py # 格式转换

└── main.py # 主程序

主程序示例

代码语言:javascript
代码运行次数:0
运行
复制
# main.py
from parser import NovelParser
from downloader import Downloader
from converter import EpubConverter

def main():
    book_url = input("请输入小说目录页URL: ")
    parser = NovelParser()
    chapters = parser.get_chapters(book_url)
    
    downloader = Downloader()
    downloader.download_all(chapters, "小说.txt")
    
    converter = EpubConverter()
    converter.to_epub(chapters, "我的小说")

if __name__ == "__main__":
    main()

六、常见问题Q&A

Q1:被网站封IP怎么办? A:立即启用备用代理池,建议使用住宅代理(如站大爷IP代理),配合每请求更换IP策略。可以设置重试机制,当连续3次请求失败时自动切换代理。

Q2:遇到403 Forbidden错误如何解决? A:首先检查User-Agent是否有效,尝试添加更多请求头如RefererCookie。如果问题依旧,可能是IP被封,需要更换代理。

Q3:如何处理动态加载的内容? A:对于JavaScript渲染的页面,使用selenium或playwright模拟浏览器行为。也可以分析XHR请求,直接抓取API接口数据。

Q4:下载的小说内容混乱怎么办? A:检查CSS选择器是否准确,不同网站结构可能不同。建议在解析前打印HTML片段确认选择器正确性。可以添加异常处理,跳过解析失败的章节。

Q5:如何提高下载速度? A:使用多线程/异步请求(推荐aiohttp),合理设置并发数(通常5-10个线程)。对于大文件,可以分块下载后合并。

Q6:爬取的小说有乱码怎么办? A:确保响应编码正确,可以尝试response.encoding = response.apparent_encoding。保存文件时指定编码utf-8gbk(根据网站实际编码)。

Q7:如何避免法律风险? A:仅爬取允许公开获取的内容,遵守网站的robots.txt协议。不要将爬取的内容用于商业用途,建议仅供个人学习研究使用。

七、总结与建议

  1. 从简单网站开始:先尝试爬取结构清晰的站点,再挑战反爬严格的网站
  2. 控制爬取频率:设置合理的time.sleep(),避免给服务器造成过大压力
  3. 数据持久化:将爬取结果及时保存到数据库或文件,防止程序中断丢失数据
  4. 关注网站更新:小说网站可能改版,需要定期维护解析逻辑
  5. 学习进阶技术:掌握Scrapy框架、分布式爬虫等高级技术应对大规模需求

通过这个项目,你不仅学会了Python爬虫技术,更掌握了应对反爬的策略。记住技术本身没有对错,关键在于如何使用。希望这些代码能帮助你享受纯净的阅读体验!

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、为什么需要自己爬小说?
    • 核心价值点:
  • 二、基础爬虫实现(30分钟上手)
    • 1. 环境准备
    • 2. 简单爬取示例
    • 3. 获取全本目录
  • 三、进阶功能实现
    • 1. 多线程下载(提速5-10倍)
    • 2. 转换为电子书格式
  • 四、反爬策略实战
    • 1. 基础反爬应对
    • 2. 代理IP池实现
    • 3. 处理验证码
    • 4. 模拟浏览器行为
  • 五、完整项目结构
    • 主程序示例
  • 六、常见问题Q&A
  • 七、总结与建议
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档