2025-11-20 17:07

一、 引言:为何我们的爬虫会被“封杀”?当我们兴致勃勃地编写好一个爬虫脚本,初期运行顺畅,但很快便会遭遇403 Forbidden429 Too Many Requests,甚至IP被直接封禁的窘境。这背后,是网站防御系统对我们发起的挑战:频率特征:同一IP在短时间内发起大量请求,行为明显异于正常人类用户。指纹特征:使用默认的requestsurllib库的User-Agent,服务器可轻易识别出这是爬虫程序。行为模式:缺乏有效的Cookie、Referer等头部信息,访问路径单一。要解决这些问题,我们的核心策略是:让爬虫尽可能地模拟真实用户的访问行为。这其中的两大基石便是IP代理请求头伪装二、 核心技术一:请求头伪装 - 成为“浏览器”而非“脚本”请求头是HTTP请求的“身份证”,它向服务器传递了客户端的详细信息。我们的首要任务就是为爬虫伪造一张合法的“身份证”。1. 基础伪装:设置User-AgentUser-Agent是标识浏览器类型和版本的最关键字段。2. 高级伪装:构建完整的浏览器指纹一个真实的浏览器请求会携带数十个头部字段。仅设置User-Agent是远远不够的。关键点Referer字段尤为重要,它告诉服务器当前请求是从哪个页面链接过来的,模拟用户的连续浏览行为。三、 核心技术二:IP代理 - 打造“千面”爬虫即使请求头伪装得再好,来自单一IP的高频请求依然会暴露。使用IP代理池,让请求来自全球各地的不同机器,是突破IP封锁的根本手段。1. 获取代理IP代理IP的来源主要有以下几类:免费代理:缺点是稳定性差、可用率低,仅适用于测试。付费代理服务:提供高匿、稳定的HTTP/HTTPS/SOCKS5代理,通常通过API接口获取IP列表,是商业项目的首选。自建代理池:通过扫描公网或云服务器自建,技术门槛和成本较高,但控制力最强。2. 构建IP代理池管理器我们将创建一个类来管理代理IP,包括获取、验证、轮换和剔除失效IP。3. 集成IP代理与请求头伪装现在,我们将两大技术整合到番茄小说爬虫的核心请求函数中。

Plain Text

复制代码

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

import requests

# 即使代理失败,也继续请求,但风险自负

# 3. 添加超时和重试逻辑

if 'timeout' not in kwargs:

kwargs['timeout'] = 15  # 稍微增加超时时间,因为代理可能较慢

max_retries = 3

for attempt in range(max_retries):

try:

print(f"第 {attempt + 1} 次尝试请求: {url}")

response = session.request(method, url, **kwargs)

# 检查响应状态和内容

if response.status_code == 200:

if "验证码" not in response.text and "access denied" not in response.text.lower():

print("请求成功!")

return response

else:

print("请求可能被反爬系统拦截,检测到验证码页面")

else:

print(f"请求失败,状态码: {response.status_code}")

except (requests.exceptions.ProxyError,

requests.exceptions.ConnectTimeout,

requests.exceptions.ReadTimeout,

requests.exceptions.ConnectionError) as e:

print(f"第 {attempt + 1} 次请求失败: {e}")

if attempt < max_retries - 1:

wait_time = 2 ** attempt  # 指数退避策略

print(f"等待 {wait_time} 秒后重试...")

time.sleep(wait_time)

continue

else:

print("所有重试均失败")

raise e

# 如果不是网络错误,但请求被拦截,也进行重试

if attempt < max_retries - 1:

wait_time = 2 ** attempt

print(f"请求可能被拦截,等待 {wait_time} 秒后重试...")

time.sleep(wait_time)

return None

# 为session绑定新的方法

session.robust_request = _make_request

return session

# 主爬虫函数

def crawl_fanqie_novel(book_id):

"""爬取番茄小说内容"""

# 初始化代理池管理器

proxy_manager = ProxyPoolManager()

# 创建稳健的Session

session = create_robust_session(proxy_manager)

# 构造目标URL

url = f'https://fanqienovel.com/reader/{book_id}'

print(f"开始爬取: {url}")

try:

# 使用我们自定义的稳健请求方法

response = session.robust_request(url)

if response and response.status_code == 200:

# 此处接续你的HTML解析逻辑

print("成功获取页面内容!")

# 可以在这里添加内容解析代码

# soup = BeautifulSoup(response.text, 'html.parser')

# ... 解析逻辑

return response.text

else:

print("爬取失败,请检查网络或反爬策略。")

return None

except Exception as e:

print(f"爬虫执行过程中发生错误: {e}")

return None

# 使用示例

if __name__ == "__main__":

# 测试爬虫

book_id = '123456789012345'

result = crawl_fanqie_novel(book_id)

if result:

print("爬取成功!")

# 处理爬取到的内容

else:

print("爬取失败!")

四、 高级策略与最佳实践请求频率控制:在关键请求之间使用time.sleep(random.uniform(1, 3)),模拟人类阅读的随机间隔。会话保持:对于需要登录或保持状态的任务,使用requests.Session()对象,它会自动处理Cookies。CAPTCHA处理:当遭遇验证码时,可以:a) 使用第三方打码平台;b) 临时切换更高匿名度的代理;c) 暂停爬虫一段时间。监控与日志:记录每个请求使用的代理、耗时、状态码,便于分析代理质量和网站反爬策略的变化。五、 总结通过系统地集成请求头伪装IP代理池,我们的番茄小说爬虫成功地从一只容易被拍死的“苍蝇”,进化成了一个拥有无数伪装身份的“特工”。这不仅是技术的叠加,更是一种工程思维的体现:将爬虫系统视为一个需要持续对抗、适应和演化的有机体。


评论