某小说网站爬虫

devtools/2025/3/5 6:05:11/

今晚上一篇小说网站给我干难受了,先是五秒盾,还有页面page参数的不规则

直接请求

首先肯定是直接请求

直接请求的代码

import requestsurl="https://beqege.cc/2/21.html"
headers={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36'
}
response=requests.get(url,headers=headers)
print(response.text)

我们看一下返回值

image-20250303220403004

这里我打印了请求,正常是会返回空,none或者403相应的

可以看到返回值是一串我们看不懂的文字,然后还带一个just moment— 小说反爬还有五秒盾?

没办法,普通请求肯定是没办法了,对于五秒盾来说,换headers或者cookie都没有用,在这里使用一个过五秒盾的库就ok了


具体如下

过5s盾

代码如下

from curl_cffi import requests as cffi_requests
res = cffi_requests.get("https://www.beqege.cc/2/21.html", impersonate='chrome110', timeout=10,verify=False)
print("============cffi_requests的方式", res.status_code, res.cookies, res.text)

image-20250303220725987

提示以下这个库在使用的时候会查询整数,由于只是个人使用,直接禁用证书即可!

可以看到可以正常返回数据了,现在我们只需要对数据进行处理就行了


不对,不对,破案了,这本数的章节不是随着数字一直增加的,偶尔会有一个大跳!

image-20250303230324162

需要先找一下它大跳的规律

我说我刚才按照顺序请求的时候为什么不对!

我扒了一下,发现小说章节链接是这样一个规律:

#21-29
#210-299
#2100-2999
#21000-22455

image-20250303230739623

加到一块就是2456!再加上其余的彩蛋或者番外,就刚好!

代码如下(全本小说)

from bs4 import BeautifulSoup
import lxml
from curl_cffi import requests as cffi_requests
import os
#21-29
#210-299
#2100-2999
#21000-22455
data = [(21, 29),(210, 250),(2100, 2999),(21000, 22455)
]
for start, end in data:for i in range(start, end + 1):res = cffi_requests.get(f"https://www.beqege.cc/2/{i}.html", impersonate='chrome110', timeout=10, verify=False)res = res.textsoup = BeautifulSoup(res, "lxml")title = soup.find("div", id="content").texthead = soup.find("div", class_="bookname").texthead = head.replace("\n", "")folder_path = f"D:/小说/凡人修仙转"if not os.path.exists(folder_path):os.makedirs(folder_path)with open(f"{folder_path}/{head}.txt", "w", encoding="utf-8") as f:f.write(title)

可以正常处理了!~

image-20250303231936169

这个代码处理了一下空格,以至于正常创建文件夹

如果想爬取的更快一些,可以使用异步或者多线程,我这里使用的是异步

多线程(全本小说)

from bs4 import BeautifulSoup
from curl_cffi import requests as cffi_requests
import os
import random
import time
from concurrent.futures import ThreadPoolExecutor, as_completed# 定义章节范围列表 (包含起始和结束页码)
CHAPTER_RANGES = [(21, 29),(210, 299),# (2100, 2999),# (21000, 22455)
]def download_page(i, retries=3):"""下载单个页面并保存"""folder_path = "D:/小说/凡人修仙转"url = f"https://www.beqege.cc/2/{i}.html"# 随机延迟(0.5-3秒)time.sleep(random.uniform(0.5, 3))for attempt in range(retries):try:# 随机选择浏览器指纹browsers = ['chrome110', 'chrome107', 'edge101']res = cffi_requests.get(url,impersonate=random.choice(browsers),timeout=10,verify=False)# 检测Cloudflare验证if "Checking your browser before accessing" in res.text:raise Exception("触发Cloudflare验证")if res.status_code != 200:raise Exception(f"HTTP状态码异常: {res.status_code}")soup = BeautifulSoup(res.text, "lxml")content_div = soup.find("div", id="content")bookname_div = soup.find("div", class_="bookname")if not content_div or not bookname_div:raise Exception("关键元素未找到")title = content_div.get_text(strip=True)head = bookname_div.get_text(strip=True).replace("\n", "")# 保存文件os.makedirs(folder_path, exist_ok=True)  # 自动创建目录with open(f"{folder_path}/{head}.txt", "w", encoding="utf-8") as f:f.write(title)print(f"页码 {i} 下载成功")return Trueexcept Exception as e:print(f"页码 {i}{attempt + 1} 次尝试失败: {str(e)}")if attempt < retries - 1:# 指数退避+随机抖动wait_time = 2 ** attempt + random.uniform(0, 1)time.sleep(wait_time)print(f"页码 {i} 下载失败,已重试 {retries} 次")return Falsedef generate_page_numbers():"""生成所有需要爬取的页码"""for (start, end) in CHAPTER_RANGES:yield from range(start, end + 1)  # 包含结束页码def main():# 配置线程池 (建议4-8个线程)max_workers = 6total_pages = sum(end - start + 1 for (start, end) in CHAPTER_RANGES)with ThreadPoolExecutor(max_workers=max_workers) as executor:# 提交所有页码的下载任务futures = {executor.submit(download_page, page): pagefor page in generate_page_numbers()}# 进度跟踪completed = 0for future in as_completed(futures):completed += 1page = futures[future]try:future.result()status = "成功"except Exception as e:status = f"失败: {str(e)[:30]}"print(f"进度: {completed}/{total_pages} | 页码 {page} {status}")if __name__ == "__main__":# 随机初始化延迟(1-5秒)time.sleep(random.uniform(1, 5))main()
  1. 增加了多浏览器指纹随即切换
  2. 随机请求延迟
  3. 自动重试失败请求
    tr(e)[:30]}"
    print(f"进度: {completed}/{total_pages} | 页码 {page} {status}")

if name == “main”:
# 随机初始化延迟(1-5秒)
time.sleep(random.uniform(1, 5))
main()


>1. 增加了多浏览器指纹随即切换
>2. 随机请求延迟
>3. 自动重试失败请求
>4. 显示成功和错误日志

http://www.ppmy.cn/devtools/164666.html

相关文章

增删改查 数据下载 一键编辑 删除

index 首页 <template><div class"box"><el-card :style"{ width: treeButton ? 19.5% : 35px, position: relative, transition: 1s }"><el-tree v-if"treeButton" :data"treeData" :props"defaultPro…

【Canny 边缘检测详细讲解】

Canny 边缘检测详细讲解 目录 Canny 边缘检测详细讲解一. Canny 边缘检测的基本原理二. 在 MATLAB 中实现 Canny 边缘检测三. 运行结果展示四. 关键参数解释五. 实验与验证六. 总结 Canny 边缘检测是一种经典的图像处理算法&#xff0c;广泛应用于计算机视觉领域。它通过多步骤…

Gartner发布安全运营指标构建指南

如何为安全运营指标构建坚实的基础 安全运营经理需要报告威胁检测、调查和响应计划的有效性&#xff0c;但难以驾驭大量潜在的 SOC 指标。本研究提供了设计针对 SOC 的指标系统的示例和实践。 主要发现 需要清晰、一致的衡量标准来向董事会成员或服务提供商等更广泛的团队传达…

Stable Diffusion 反向提示词(Negative Prompt)深度解析

Stable Diffusion 反向提示词深度解析&#xff08;2025最新版&#xff09; 一、核心定义与作用 反向提示词&#xff08;Negative Prompt&#xff09;是用于排除生成图像中特定内容或特征的指令集。通过明确告知模型不应出现的元素&#xff0c;反向提示词可有效解决以下三大问…

MySQL表连接详解

MySQL表连接详解 在 MySQL 中&#xff0c;表连接&#xff08;Join&#xff09;用于将多个表中的数据组合在一起&#xff0c;基于它们之间的关系进行查询。常见的表连接类型包括内连接、左连接、右连接和全外连接。以下是这些连接类型的详细说明&#xff1a; 1. 内连接&#x…

什么是线程安全?并行计算

当一个库声称自己“不是线程安全的”&#xff08;not thread-safe&#xff09;&#xff0c;意思是它在多线程环境下使用时&#xff0c;可能会出现数据竞争&#xff08;data race&#xff09;、未定义行为&#xff08;undefined behavior&#xff09;或不一致的结果。线程安全&a…

跨域问题解释及前后端解决方案(SpringBoot)

一、问题引出 有时,控制台出现如下问题。 二、为什么会有跨域 2.1浏览器同源策略 浏览器的同源策略 &#xff08; Same-origin policy &#xff09;是一种重要的安全机制&#xff0c;用于限制一个源&#xff08; origin &#xff09;的文档或 脚本如何与另一个源的资源进行…

11.【线性代数】——矩阵空间,秩1矩阵,小世界图

十一 矩阵空间&#xff0c;秩1矩阵&#xff0c;小世界图 1. 矩阵空间交集 和 和集 2. 所有解空间3. r 1 r1 r1的矩阵4. 题目5. 小世界图 空间&#xff1a;组成空间的元素的线性组合都在这个空间中。 1. 矩阵空间 举例&#xff1a;矩阵空间&#xff08; M M M 所有3x3的矩阵&…