Python网络爬虫实战:两种方式抓取《凡人修仙传》完整内容

目录

方案一:单文件完整版(一体化存储)

核心特点:

技术亮点:

流量模拟技术:

精准内容提取:

健壮性增强:

适用场景:需要整本连续阅读、进行文本分析或训练NLP模型的情况

方案二:分章节存储版(模块化管理)

核心特点:

关键技术突破:

智能命名系统:

三重内容防护:

高级请求策略:

适用场景:需要分章节处理、建立小说数据库或进行章节级分析的情况

方案对比选型指南

运行结果如下:


爬取在线小说资源是Python网络爬虫的经典应用场景。本文将通过两个优化版本的代码,演示如何实现整本小说抓取的两种不同存储方案。两种方案均已加入防封禁策略和内容清洗功能,读者可根据需求选择使用。(仅供技术研究,请遵守网站规则)


方案一:单文件完整版(一体化存储)

核心特点

  • 全本内容存储为单个txt文件

  • 追加写入模式节省内存

  • 章节间自动添加分隔符

from bs4 import BeautifulSoup
from curl_cffi import requests as cffi_requests
import os
import time
import random

# 配置参数
BASE_URL = "https://www.beqege.cc/2/2{}.html"  # 统一URL模板
SAVE_PATH = os.path.join("D:", "小说")  # 存储路径
FILE_NAME = "凡人修仙传(完整版).txt"  # 统一文件名
HEADERS = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36",
    "Referer": "https://www.beqege.cc/"
}

# 创建存储目录(确保只执行一次)
os.makedirs(SAVE_PATH, exist_ok=True)

# 完整文件路径
full_path = os.path.join(SAVE_PATH, FILE_NAME)

for chapter_num in range(1, 2456):
    # 添加随机延迟防止封禁
    time.sleep(random.uniform(0.5, 2))

    try:
        # 请求页面
        response = cffi_requests.get(
            BASE_URL.format(chapter_num),
            impersonate='chrome110',
            headers=HEADERS,
            timeout=15,
            verify=False  # 保持与原始设置一致
        )
        response.raise_for_status()

        # 解析内容
        soup = BeautifulSoup(response.text, "lxml")

        # 提取章节标题(更精准的选择器)
        chapter_title = soup.find("div", class_="bookname").h1.text.strip()

        # 提取正文内容(优化选择器)
        content_div = soup.find("div", id="content")
        # 清理广告等无关内容
        [x.decompose() for x in content_div.find_all("div", class_="ads")]
        chapter_content = "\n".join([p.text.strip() for p in content_div.find_all("p")])

        # 写入文件(追加模式)
        with open(full_path, "a", encoding="utf-8") as f:
            f.write(f"\n\n{chapter_title}\n\n")  # 添加章节分隔符
            f.write(chapter_content)
            f.write("\n\n\n")  # 章节结束

        print(f"已保存第 {chapter_num} 章:{chapter_title}")

    except Exception as e:
        print(f"第 {chapter_num} 章抓取失败,错误信息:{str(e)}")
        # 可以在此添加重试逻辑

print("全部章节抓取完成!")

技术亮点

  1. 流量模拟技术:

    • 使用curl_cffi库模拟Chrome110浏览器TLS指纹

    • 随机延时(0.5-2秒)配合动态UA降低被封风险

  2. 精准内容提取:

    # 定位章节标题
    chapter_title = soup.find("div", class_="bookname").h1.text.strip()
    
    # 提取正文并清理广告
    content_div = soup.find("div", id="content")
    [x.decompose() for x in content_div.find_all("div", class_="ads")]
  3. 健壮性增强:

    • 异常捕获模块记录失败章节

    • 自动创建存储目录(exist_ok=True防重复创建)

适用场景:需要整本连续阅读、进行文本分析或训练NLP模型的情况


方案二:分章节存储版(模块化管理)

核心特点

  • 按章节独立存储为txt文件

  • 自动生成规范化文件名

  • 原子写入防止数据损坏

from bs4 import BeautifulSoup
from curl_cffi import requests as cffi_requests
import os
import time
import random
import re

# 配置参数
BASE_URL = "https://www.beqege.cc/2/2{}.html"
SAVE_DIR = os.path.join("D:", "小说", "凡人修仙传")
HEADERS = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36",
    "Referer": "https://www.beqege.cc/"
}

# 预处理存储目录
os.makedirs(SAVE_DIR, exist_ok=True)


def sanitize_filename(title):
    """清理非法文件名字符"""
    return re.sub(r'[\\/*?:"<>|]', "", title).strip()


for chapter_num in range(1, 2456):
    # 智能延迟控制
    time.sleep(random.uniform(0.8, 2.5))

    try:
        # 带重试的请求
        for retry in range(3):
            try:
                response = cffi_requests.get(
                    BASE_URL.format(chapter_num),
                    impersonate='chrome110',
                    headers=HEADERS,
                    timeout=15,
                    verify=False
                )
                response.raise_for_status()
                break
            except Exception as e:
                if retry == 2:
                    raise
                time.sleep(2 ** retry)

        # 精准内容解析
        soup = BeautifulSoup(response.text, "lxml")

        # 提取并清理标题
        title_div = soup.find("div", class_="bookname")
        chapter_title = title_div.h1.text.strip() if title_div else f"第{chapter_num}章"

        # 提取并清理正文
        content_div = soup.find("div", id="content")
        if content_div:
            # 移除广告内容
            for ad in content_div.find_all(["div", "script", "a"]):
                ad.decompose()
            # 优化段落结构
            paragraphs = [p.text.strip() for p in content_div.find_all("p") if p.text.strip()]
            chapter_content = "\n".join(paragraphs)
        else:
            chapter_content = "内容获取失败"

        # 生成安全文件名
        safe_title = sanitize_filename(chapter_title)
        file_path = os.path.join(SAVE_DIR, f"{chapter_num:04d}_{safe_title}.txt")

        # 原子化写入
        with open(file_path, "w", encoding="utf-8") as f:
            f.write(f"  {chapter_title}  \n\n")
            f.write(chapter_content)

        print(f"成功保存:{chapter_num:04d} {chapter_title}")

    except Exception as e:
        print(f"章节 {chapter_num} 抓取失败: {str(e)}")
        # 可在此记录失败章节用于重试

print("全部章节处理完成!")

关键技术突破

  1. 智能命名系统:

    def sanitize_filename(title):
        return re.sub(r'[\\/*?:"<>|]', "", title).strip()
    
    # 生成示例:0001_第一章.txt
    file_path = os.path.join(SAVE_DIR, f"{chapter_num:04d}_{safe_title}.txt")
  2. 三重内容防护:

    • 广告标签移除(decompose()彻底清除DOM节点)

    • 段落有效性验证(if p.text.strip()过滤空段落)

    • 失败章节内容占位("内容获取失败"提示)

  3. 高级请求策略:

    # 指数退避重试机制
    for retry in range(3):
        try:
            # 请求逻辑
            break
        except Exception:
            time.sleep(2 ** retry)

适用场景:需要分章节处理、建立小说数据库或进行章节级分析的情况


方案对比选型指南

特性单文件版分章节版
文件数量12000+
存储空间较小较大
容错能力一般优秀
章节定位需全文搜索直接文件访问
内容更新需重新抓取可增量更新
适合场景终端阅读数据分析

运行结果如下:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值