找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

2238

积分

0

好友

291

主题
发表于 11 小时前 | 查看: 2| 回复: 0

一、请求头是什么?

HTTP请求头是客户端与服务器通信时,用于传递额外信息的元数据部分。它扮演着多种关键角色,帮助服务器理解请求的意图、客户端的身份及其偏好。

主要作用:

  • 身份验证:传递凭证信息。
  • 内容协商:声明客户端可以接收哪些格式的数据。
  • 缓存控制:指示如何管理响应的缓存。
  • 会话管理:通过 Cookie 来维持用户状态。
  • 安全控制:例如进行 CSRF 防护等。

常见的请求头分类:

  1. 通用头

    • Cache-Control:缓存控制,例如 no-cache
    • Connection:连接管理,例如 keep-alive
    • Date:请求发送的时间。
  2. 请求头

    • Authorization:身份验证凭证,例如 Bearer token
    • User-Agent:客户端信息,用于标识浏览器、操作系统或设备。
    • Accept:可接受的响应类型,例如 application/json
    • Accept-Language:优先选择的语言。
    • Cookie:客户端存储的会话数据。
    • Referer:来源页面的 URL。
    • Host:目标服务器域名,在 HTTP/1.1 中是必需的。
  3. 实体头

    • Content-Type:请求体数据的数据类型,例如 application/json
    • Content-Length:请求体的大小。

二、爬虫最容易被识破的地方

大多数网站的反爬机制都会首先检查请求头。如果你的爬虫存在以下问题,就很容易被识别出来:

  1. User-Agent 里包含爬虫关键词 → 直接暴露,比如 Python-urllib
  2. 请求头太少或过于简单 → 看着就很可疑。
  3. Accept: */* → 过于宽泛,不够像真人浏览器。
  4. 没有 Accept-Language → 真人浏览器通常会有。
  5. Connection: close → 浏览器通常会使用 keep-alive 优化连接。
  6. Referer 不合理 → 比如从谷歌搜索直接跳到了内页,而没有经过首页。
  7. 完全没有缓存控制或 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-AgentReferer,还会模拟人类的访问延迟、管理 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指纹识别 等更底层、更隐蔽的方式来发现爬虫。如果你想了解更多高级的反反爬技巧,欢迎在云栈社区进行搜索和交流。




上一篇:rrweb 实战指南:攻克前端“复现难”,实现精准Web录制与回放
下一篇:告别无效记录,试试开源时间追踪工具TimeTagger如何?
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-2-7 20:42 , Processed in 0.384529 second(s), 38 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表