一、请求头是什么?
HTTP请求头是客户端与服务器通信时,用于传递额外信息的元数据部分。它扮演着多种关键角色,帮助服务器理解请求的意图、客户端的身份及其偏好。
主要作用:
- 身份验证:传递凭证信息。
- 内容协商:声明客户端可以接收哪些格式的数据。
- 缓存控制:指示如何管理响应的缓存。
- 会话管理:通过
Cookie 来维持用户状态。
- 安全控制:例如进行 CSRF 防护等。
常见的请求头分类:
-
通用头
Cache-Control:缓存控制,例如 no-cache。
Connection:连接管理,例如 keep-alive。
Date:请求发送的时间。
-
请求头
Authorization:身份验证凭证,例如 Bearer token。
User-Agent:客户端信息,用于标识浏览器、操作系统或设备。
Accept:可接受的响应类型,例如 application/json。
Accept-Language:优先选择的语言。
Cookie:客户端存储的会话数据。
Referer:来源页面的 URL。
Host:目标服务器域名,在 HTTP/1.1 中是必需的。
-
实体头
Content-Type:请求体数据的数据类型,例如 application/json。
Content-Length:请求体的大小。
二、爬虫最容易被识破的地方
大多数网站的反爬机制都会首先检查请求头。如果你的爬虫存在以下问题,就很容易被识别出来:
User-Agent 里包含爬虫关键词 → 直接暴露,比如 Python-urllib。
- 请求头太少或过于简单 → 看着就很可疑。
Accept: */* → 过于宽泛,不够像真人浏览器。
- 没有
Accept-Language → 真人浏览器通常会有。
Connection: close → 浏览器通常会使用 keep-alive 优化连接。
Referer 不合理 → 比如从谷歌搜索直接跳到了内页,而没有经过首页。
- 完全没有缓存控制或
Cookie → 不像一个有状态的“回头客”。
三、如何让你的爬虫“隐身”?
1. 使用 User-Agent 池
一成不变的 User-Agent 是爬虫最大的破绽。你需要模拟不同浏览器和设备的请求。
你可以自己建立一个包含主流浏览器最新 UA 字符串的列表,并随机或按逻辑选取。下面的Python代码示例展示了一个更智能的管理器,它甚至能根据访问时间(模拟工作/非工作时间)来选择不同偏好的 UA。
"""
User-Agent 管理器模块
功能说明:
1. 提供User-Agent池管理功能,包含多个主流浏览器的最新UA字符串
2. 支持随机获取User-Agent,增加请求的随机性
3. 支持基于时间智能选择User-Agent,模拟不同时间段用户的使用习惯:
- 工作时间(9:00-18:00):主要返回Chrome和Edge浏览器UA,模拟办公环境
- 非工作时间:主要返回Firefox和Safari浏览器UA,模拟个人设备使用
4. 适用于网络爬虫、数据采集等需要模拟真实浏览器请求的场景
5. 提供两种获取方式:
- 完全随机选择(get_random_ua)
- 基于时间的智能选择(get_ua_by_time)
"""
import random
import requests
from datetime import datetime
class UserAgentManager:
"""User-Agent管理器"""
def __init__(self):
self.user_agents = self._load_user_agents()
def _load_user_agents(self):
"""加载User-Agent池"""
return [
# Chrome Windows
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
# Chrome Mac
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
# Firefox Windows
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:120.0) Gecko/20100101 Firefox/120.0',
# Firefox Mac
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:120.0) Gecko/20100101 Firefox/120.0',
# Safari
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.1 Safari/605.1.15',
# Edge
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0'
]
def get_random_ua(self):
"""获取随机User-Agent"""
return random.choice(self.user_agents)
def get_ua_by_time(self):
"""根据时间获取不同的UA(模拟不同时间段的用户)"""
hour = datetime.now().hour
if 9 <= hour <= 18: # 工作时间
# 更多Chrome和Edge(办公电脑)
return random.choice([
self.user_agents[0], # Chrome Windows
self.user_agents[1], # Chrome Windows WOW64
self.user_agents[6] # Edge
])
else: # 非工作时间
# 更多Firefox和Safari(个人设备)
return random.choice([
self.user_agents[3], # Firefox Windows
self.user_agents[4], # Firefox Mac
self.user_agents[5] # Safari
])
更方便的方法是使用现成的库,比如 fake-useragent。
安装:pip install fake-useragent
"""
User-Agent 轮换器模块 (增强版)
功能说明:
1. 灵活的User-Agent管理策略,支持三种UA获取方式:
- fake-useragent库自动生成
- 自定义UA列表
- 默认备用UA
2. 多平台支持:
- 桌面端Chrome浏览器UA
- 移动端UA(iOS和Android)
3. 智能回退机制:
- 优先使用自定义UA列表
- 次优先使用fake-useragent库
- 最后使用内置默认UA作为保障
4. 异常容错处理:
- fake-useragent库初始化失败时自动降级
- 确保在任何情况下都能返回有效的UA
5. 支持特定类型UA获取:
- 随机UA(get_random)
- 桌面Chrome UA(get_chrome)
- 移动端UA(get_mobile)
"""
import random
from typing import List, Optional
from fake_useragent import UserAgent
class UARotator:
"""User-Agent 轮换器"""
def __init__(self, use_fake_ua: bool = True, custom_uas: Optional[List[str]] = None):
"""
初始化 UA 轮换器
Args:
use_fake_ua: 是否使用 fake-useragent 库
custom_uas: 自定义 UA 列表
"""
self.use_fake_ua = use_fake_ua
self.custom_uas = custom_uas or []
if use_fake_ua:
try:
self._fake_ua = UserAgent()
except Exception:
self.use_fake_ua = False
def get_random(self) -> str:
"""获取随机 UA"""
# 优先使用自定义列表
if self.custom_uas:
return random.choice(self.custom_uas)
# 使用 fake-useragent
if self.use_fake_ua:
return self._fake_ua.random
# 默认返回 Chrome UA
return (
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/120.0.0.0 Safari/537.36"
)
def get_chrome(self) -> str:
"""获取 Chrome UA"""
if self.use_fake_ua:
return self._fake_ua.chrome
return self.get_random()
def get_mobile(self) -> str:
"""获取移动端 UA"""
mobile_uas = [
"Mozilla/5.0 (iPhone; CPU iPhone OS 17_2 like Mac OS X) AppleWebKit/605.1.15",
"Mozilla/5.0 (Linux; Android 14; Pixel 8) AppleWebKit/537.36",
]
return random.choice(mobile_uas)
2. 智能 Referer 管理
一个合理的 Referer 能极大增强请求的可信度。它模拟了用户是从哪个页面跳转过来的。
"""
Referer 管理器模块
功能说明:
1. Referer模拟生成系统,用于模拟真实用户的页面跳转来源
2. 支持三种Referer生成模式:
- 搜索引擎跳转(get_search_referer):模拟用户通过搜索进入
- 直接访问跳转(get_direct_referer):模拟网站间跳转或直接访问
- 智能Referer生成(get_smart_referer):根据目标URL智能选择来源
3. 模拟真实用户行为:
- 30%概率模拟直接输入网址访问(无Referer)
- 模拟从主流搜索引擎(Google、Bing、百度、搜狗)跳转
- 模拟从热门网站(知乎、微博、B站、GitHub等)跳转
- 模拟本站内页面跳转
4. 行为概率分布:
- 首次访问域名:70%概率来自搜索引擎
- 非首次访问:50%概率从本站其他页面跳转
- 支持自定义搜索关键词或使用预设关键词
5. 容错机制:
- URL解析失败时自动回退到搜索引擎Referer
- 支持空Referer(模拟直接访问)
"""
import random
class RefererManager:
"""Referer管理器"""
def __init__(self):
self.search_engines = [
'https://www.google.com/search?q={query}',
'https://www.bing.com/search?q={query}',
'https://www.baidu.com/s?wd={query}',
'https://www.sogou.com/web?query={query}'
]
self.popular_sites = [
'https://www.zhihu.com/',
'https://weibo.com/',
'https://www.bilibili.com/',
'https://github.com/',
'https://stackoverflow.com/'
]
def get_search_referer(self, keyword=None):
"""生成搜索跳转Referer"""
if keyword is None:
keyword = random.choice(['python教程', '数据分析', '机器学习', '网络爬虫'])
search_url = random.choice(self.search_engines)
return search_url.format(query=keyword)
def get_direct_referer(self, current_domain=None):
"""生成直接访问Referer"""
# 30%几率没有Referer(直接输入网址)
if random.random() < 0.3:
return ''
# 70%几率从其他网站跳转
if current_domain and random.random() < 0.5:
# 50%从本站其他页面跳转
return f'https://{current_domain}/{random.choice(["", "index.html", "home", "main"])}'
else:
# 从其他热门网站跳转
return random.choice(self.popular_sites)
def get_smart_referer(self, url):
"""智能生成Referer"""
from urllib.parse import urlparse
try:
domain = urlparse(url).netloc
# 如果是首次访问该域名,大概率从搜索引擎来
if random.random() < 0.7:
return self.get_search_referer()
else:
return self.get_direct_referer(domain)
except:
return self.get_search_referer()
3. 智能会话保持
最后,我们把这些最佳实践整合起来,创建一个“智能会话”类,它不仅能管理 User-Agent 和 Referer,还会模拟人类的访问延迟、管理 Cookie 和缓存头,并提供错误重试机制。
"""
智能会话管理模块
功能说明:
1. 完整的HTTP会话管理系统,集成了User-Agent管理和Referer管理功能
2. 智能请求模拟:模拟真实用户的浏览行为模式,包括:
- 基于时间的访问延迟(深夜、工作时间、晚上的不同访问速度)
- 智能Referer设置(首次访问、重复访问的不同来源)
- 动态缓存控制(80%概率使用缓存)
3. 完善的错误处理机制:
- 自动重试策略(429、500、502、503、504状态码)
- 指数退避重试(backoff_factor=0.5)
- 异常后的延迟恢复(5-10秒延迟)
4. 会话状态管理:
- Cookie自动维护和更新
- 访问历史记录(记录URL和访问时间)
- 连接池优化(100个连接池大小)
5. 智能头部管理:
- 基于时间的User-Agent选择
- 智能Referer生成策略
- POST请求自动Content-Type设置
6. 多种请求模式支持:
- GET请求:完整的行为模拟
- POST请求:自动设置内容类型
"""
import time
import requests
import random
from datetime import datetime
from urllib.parse import urlparse
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
class SmartSession:
"""智能会话管理"""
def __init__(self):
self.session = requests.Session()
self.ua_manager = UserAgentManager()
self.referer_manager = RefererManager()
# 设置重试策略
retry_strategy = Retry(
total=3,
backoff_factor=0.5,
status_forcelist=[429, 500, 502, 503, 504],
allowed_methods=["GET", "POST"]
)
adapter = HTTPAdapter(
max_retries=retry_strategy,
pool_connections=100,
pool_maxsize=100
)
self.session.mount('http://', adapter)
self.session.mount('https://', adapter)
# 初始化基础头
self._init_base_headers()
# 访问历史记录
self.visit_history = {}
def _init_base_headers(self):
"""初始化基础请求头"""
self.session.headers.update({
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
'Accept-Encoding': 'gzip, deflate',
'Connection': 'keep-alive',
'DNT': '1',
'Upgrade-Insecure-Requests': '1'
})
def _human_delay(self):
"""人类化延迟"""
# 根据时间设置不同的延迟
hour = datetime.now().hour
if 0 <= hour < 6: # 深夜
delay = random.uniform(5, 10) # 深夜访问慢
elif 8 <= hour <= 18: # 工作时间
delay = random.uniform(1, 3) # 工作时间访问快
else: # 晚上
delay = random.uniform(2, 5)
time.sleep(delay)
def get(self, url, **kwargs):
"""智能GET请求"""
# 人类化延迟
self._human_delay()
# 更新动态头
headers = kwargs.get('headers', {})
# 确保有User-Agent
if 'User-Agent' not in headers:
headers['User-Agent'] = self.ua_manager.get_ua_by_time()
# 智能设置Referer
if 'Referer' not in headers:
# 如果是首次访问该URL,生成搜索引擎Referer
if url not in self.visit_history:
headers['Referer'] = self.referer_manager.get_search_referer()
else:
# 非首次访问,可能从其他页面跳转
headers['Referer'] = self.referer_manager.get_direct_referer(
urlparse(url).netloc
)
# 更新缓存头
if random.random() < 0.8: # 80%使用缓存
headers['Cache-Control'] = random.choice([
'max-age=0',
'no-cache'
])
kwargs['headers'] = headers
# 记录访问
self.visit_history[url] = datetime.now()
try:
response = self.session.get(url, **kwargs)
# 更新Cookie
if response.cookies:
self.session.cookies.update(response.cookies)
return response
except Exception as e:
print(f"请求失败: {e}")
# 出错后增加延迟
time.sleep(random.uniform(5, 10))
raise
def post(self, url, data=None, json=None, **kwargs):
"""智能POST请求"""
self._human_delay()
# POST请求通常有特定的Content-Type
if 'Content-Type' not in kwargs.get('headers', {}):
headers = kwargs.get('headers', {})
if json is not None:
headers['Content-Type'] = 'application/json'
else:
headers['Content-Type'] = 'application/x-www-form-urlencoded'
kwargs['headers'] = headers
return self.session.post(url, data=data, json=json, **kwargs)
总结
记住一个核心原则:你的爬虫发出的请求越接近真人浏览器的请求模式,它的存活时间就越长。
需要强调的是,反爬虫技术也在不断演进。今天有效的伪装技巧,明天可能就会失效。因此,最佳的学习方法是实践与观察。打开你浏览器自带的开发者工具(通常按 F12 键),切换到 Network (网络) 标签页。仔细观察当你正常访问一个网站时,浏览器到底发送了哪些请求头。然后,模仿这些请求头来配置你的爬虫。这个方法看似简单,却非常有效。
伪装好请求头只是对抗反爬虫的第一步。你以为这样就万事大吉了吗?对于那些技术储备深厚的大厂,他们可能通过 TLS指纹识别 等更底层、更隐蔽的方式来发现爬虫。如果你想了解更多高级的反反爬技巧,欢迎在云栈社区进行搜索和交流。