突破反爬:使用代理IP和User-Agent轮询爬取音乐数据

小白学大数据
• 阅读 1

一、反爬虫机制的原理与应对策略 在深入技术实现之前,我们有必要了解常见的反爬虫机制及其工作原理:

  1. IP频率限制:网站会监控单个IP地址的请求频率,如果短时间内请求过多,会判定为该IP存在爬虫行为,从而实施封禁。
  2. User-Agent检测:通过检查HTTP请求头中的User-Agent字段,识别并拦截非常规浏览器或爬虫工具的请求。
  3. 行为模式分析:高级反爬系统会分析用户的点击模式、鼠标移动轨迹等行为特征,区分人类用户和自动化程序。
  4. 验证码挑战:当检测到可疑活动时,要求用户完成验证码验证,阻止自动化访问。 针对这些限制,我们的技术对策是: ● 使用代理IP池,分散请求来源,避免IP被封 ● 轮换User-Agent,模拟不同浏览器和设备的访问 ● 合理控制请求频率,加入随机延迟模拟人类行为 二、技术架构设计与核心组件 一个健壮的音乐数据爬虫系统应该包含以下核心组件: 代理IP管理模块: ● 代理IP的获取与验证 ● IP池的维护与更新 ● 代理质量评估与筛选 请求头管理模块: ● User-Agent字符串的收集与管理 ● 其他必要请求头的动态生成 爬虫调度模块: ● 请求频率控制 ● 异常处理与重试机制 ● 数据解析与存储 三、完整代码实现 下面我们通过一个具体的示例,演示如何实现一个具备反反爬能力的音乐数据爬虫。 python
    import time
    import random
    from typing import List, Dict, Optional
    from fake_useragent import UserAgent
    from concurrent.futures import ThreadPoolExecutor, as_completed
    

class MusicDataCrawler: """ 音乐数据爬虫类 具备代理IP和User-Agent轮询功能 """

def __init__(self):
    self.session = requests.Session()
    self.ua_generator = UserAgent()

    # 设置固定代理信息
    self.proxyHost = "www.16yun.cn"
    self.proxyPort = "5445"
    self.proxyUser = "16QMSOML"
    self.proxyPass = "280651"

    # 初始化代理IP池(包含付费代理和免费代理)
    self.proxy_pool = self._init_proxy_pool()

    # 请求统计
    self.request_count = 0
    self.success_count = 0

    # 爬虫配置
    self.max_retries = 3
    self.timeout = 10
    self.request_delay = (1, 3)  # 请求延迟范围(秒)

def _init_proxy_pool(self) -> List[Dict]:
    """
    初始化代理IP池,包含付费代理和免费代理
    """
    # 构建认证代理
    auth_proxy = self._build_auth_proxy()

    # 代理池包含付费代理和免费代理
    proxies = [
        auth_proxy,  # 付费认证代理
        {'http': 'http://103.156.144.121:80', 'https': 'http://103.156.144.121:80'},
        {'http': 'http://45.65.132.180:8080', 'https': 'http://45.65.132.180:8080'},
        # 可以添加更多代理...
    ]
    return proxies

def _build_auth_proxy(self) -> Dict:
    """
    构建带认证的代理配置
    """
    proxy_url = f"http://{self.proxyUser}:{self.proxyPass}@{self.proxyHost}:{self.proxyPort}"
    return {
        'http': proxy_url,
        'https': proxy_url
    }

def _get_auth_proxy(self) -> Dict:
    """
    获取带认证的代理(优先使用)
    """
    return self._build_auth_proxy()

def _get_random_user_agent(self) -> str:
    """
    获取随机User-Agent
    """
    return self.ua_generator.random

def _get_random_proxy(self) -> Optional[Dict]:
    """
    从代理池中随机选择一个代理
    增加权重,让付费代理有更高使用概率
    """
    if not self.proxy_pool:
        return None

    # 给付费代理更高权重(60%概率使用付费代理)
    if random.random() < 0.6:
        return self._get_auth_proxy()
    else:
        return random.choice(self.proxy_pool)

def _make_request(self, url: str, params: Dict = None, retry_count: int = 0) -> Optional[requests.Response]:
    """
    执行单次请求,包含代理和User-Agent轮询
    """
    try:
        # 随机延迟,模拟人类行为
        delay = random.uniform(*self.request_delay)
        time.sleep(delay)

        # 准备请求头
        headers = {
            'User-Agent': self._get_random_user_agent(),
            'Accept': 'application/json, text/plain, */*',
            'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
            'Accept-Encoding': 'gzip, deflate, br',
            'Connection': 'keep-alive',
        }

        # 获取代理
        proxies = self._get_random_proxy()

        self.request_count += 1
        print(f"请求 #{self.request_count}: {url}")

        # 安全地显示代理信息(隐藏密码)
        if proxies and 'http' in proxies:
            proxy_display = proxies['http'].replace(self.proxyPass, '***')
            print(f"使用代理: {proxy_display}")
        else:
            print(f"使用代理: {proxies}")

        print(f"使用User-Agent: {headers['User-Agent'][:50]}...")

        response = self.session.get(
            url,
            params=params,
            headers=headers,
            proxies=proxies,
            timeout=self.timeout,
            verify=False  # 注意:这里为了演示关闭了SSL验证,生产环境应谨慎使用
        )

        # 检查响应状态
        if response.status_code == 200:
            self.success_count += 1
            print(f"请求成功! 成功率: {self.success_count}/{self.request_count} "
                  f"({self.success_count/self.request_count*100:.1f}%)")
            return response
        elif response.status_code in [403, 429]:
            # 遇到访问限制,可能是代理或User-Agent失效
            print(f"遇到访问限制: {response.status_code}")
            if retry_count < self.max_retries:
                print(f"进行重试 ({retry_count + 1}/{self.max_retries})")
                # 重试时更换代理
                return self._make_request(url, params, retry_count + 1)
            else:
                print("达到最大重试次数,放弃请求")
                return None
        else:
            print(f"请求失败,状态码: {response.status_code}")
            return None

    except requests.exceptions.RequestException as e:
        print(f"请求异常: {e}")
        if retry_count < self.max_retries:
            print(f"进行重试 ({retry_count + 1}/{self.max_retries})")
            # 重试时更换代理
            return self._make_request(url, params, retry_count + 1)
        return None

def crawl_music_list(self, search_keyword: str, page_count: int = 3) -> List[Dict]:
    """
    爬取音乐列表数据
    注意:这里使用模拟的API端点,实际应用中需要替换为目标网站的API
    """
    music_data = []

    for page in range(1, page_count + 1):
        print(f"\n开始爬取第 {page} 页数据...")

        # 模拟音乐API请求URL(请替换为实际目标网站的API)
        # 这里使用一个示例URL结构
        api_url = "https://api.example-music-site.com/search"
        params = {
            'keyword': search_keyword,
            'page': page,
            'limit': 20
        }

        response = self._make_request(api_url, params)

        if response:
            try:
                # 解析JSON响应
                data = response.json()

                # 模拟数据提取(根据实际API响应结构调整)
                if data.get('success'):
                    songs = data.get('data', {}).get('songs', [])

                    for song in songs:
                        music_info = {
                            'id': song.get('id'),
                            'name': song.get('name'),
                            'artist': song.get('artist', {}).get('name'),
                            'album': song.get('album', {}).get('name'),
                            'duration': song.get('duration'),
                            'play_url': song.get('play_url')
                        }
                        music_data.append(music_info)
                        print(f"获取歌曲: {music_info['name']} - {music_info['artist']}")

                print(f"第 {page} 页爬取完成,获得 {len(songs)} 首歌曲")

            except ValueError as e:
                print(f"JSON解析错误: {e}")
        else:
            print(f"第 {page} 页爬取失败")

        # 页面间延迟
        time.sleep(random.uniform(2, 5))

    return music_data

def batch_crawl(self, keywords: List[str], max_workers: int = 3) -> Dict[str, List[Dict]]:
    """
    批量爬取多个关键词的音乐数据
    """
    results = {}

    with ThreadPoolExecutor(max_workers=max_workers) as executor:
        # 提交任务
        future_to_keyword = {
            executor.submit(self.crawl_music_list, keyword, 2): keyword 
            for keyword in keywords
        }

        # 收集结果
        for future in as_completed(future_to_keyword):
            keyword = future_to_keyword[future]
            try:
                results[keyword] = future.result()
            except Exception as e:
                print(f"关键词 '{keyword}' 爬取失败: {e}")
                results[keyword] = []

    return results

def get_proxy_status(self) -> Dict:
    """
    获取代理使用状态统计
    """
    return {
        'total_requests': self.request_count,
        'successful_requests': self.success_count,
        'success_rate': self.success_count / self.request_count * 100 if self.request_count > 0 else 0,
        'proxy_count': len(self.proxy_pool),
        'primary_proxy': f"{self.proxyUser}@{self.proxyHost}:{self.proxyPort}"
    }

def main(): """ 主函数:演示爬虫的使用 """ # 初始化爬虫 crawler = MusicDataCrawler()

# 显示代理状态
status = crawler.get_proxy_status()
print(f"代理状态: {status}")

# 单个关键词爬取示例
print("=== 开始单关键词爬取 ===")
songs = crawler.crawl_music_list("周杰伦", page_count=2)
print(f"\n爬取完成! 共获得 {len(songs)} 首歌曲")

# 显示前几首歌曲信息
for i, song in enumerate(songs[:5]):
    print(f"{i+1}. {song['name']} - {song['artist']}")

# 批量爬取示例
print("\n=== 开始批量爬取 ===")
keywords = ["流行", "摇滚", "古典"]
batch_results = crawler.batch_crawl(keywords)

for keyword, songs in batch_results.items():
    print(f"关键词 '{keyword}': 获得 {len(songs)} 首歌曲")

# 最终统计
final_status = crawler.get_proxy_status()
print(f"\n最终统计:")
print(f"总请求数: {final_status['total_requests']}")
print(f"成功请求: {final_status['successful_requests']}")
print(f"成功率: {final_status['success_rate']:.1f}%")

if name == "main": main()

``` 四、技术要点解析

  1. 代理IP的管理策略 在实际应用中,代理IP的质量直接决定爬虫的稳定性。建议: ● 使用付费代理服务:免费代理通常稳定性差、速度慢 ● 实现代理健康检查:定期测试代理的可用性和速度 ● 设置代理权重:根据成功率动态调整代理使用频率
  2. User-Agent的真实性 除了随机性,User-Agent的真实性也很重要: ● 确保User-Agent与设备类型、浏览器版本匹配 ● 定期更新User-Agent库,避免使用过时版本 ● 可以考虑使用真实的浏览器指纹模拟
  3. 请求行为的拟人化 高级反爬系统会分析请求行为模式: ● 随机化请求间隔,避免固定频率 ● 模拟页面浏览序列,而不是直接访问API ● 添加鼠标移动、滚动等行为模拟(对于需要渲染的页面) 五、伦理与法律考量 在实施爬虫项目时,必须考虑以下因素:
  4. 遵守robots.txt:尊重网站的爬虫协议
  5. 控制访问频率:避免对目标网站造成负担
  6. 数据使用范围:遵守版权法和相关服务条款
  7. 商业用途限制:明确数据的商业使用权限 六、总结 通过代理IP轮询和User-Agent管理的结合使用,我们可以有效应对大多数基础和中级的反爬措施。本文提供的代码框架具有良好的扩展性,可以根据具体需求添加以下高级功能: ● 自动化代理IP采集和验证 ● 基于机器学习的反爬检测规避 ● 分布式爬虫架构 ● 浏览器自动化与渲染支持
点赞
收藏
评论区
推荐文章
菜鸟阿都 菜鸟阿都
4年前
创建免费ip代理池
&ensp;&ensp;&ensp;&ensp; 反爬技术越来越成熟,为了爬取目标数据,必须对爬虫的请求进行伪装,骗过目标系统,目标系统通过判断请求的访问频次或请求参数将疑似爬虫的ip进行封禁,要求进行安全验证,通过python的第三方库faker可以随机生成header伪装请求头,并且减缓爬虫的爬取速度,能很好的避过多数目标系统的反扒机制,但对一些安全等级
python使用aiohttp通过设置代理爬取基金数据
说到python爬虫,我们就会想到它那强大的库,很多新手小白在选择框架的时候都会想到使用Scrapy,但是仅仅停留在会使用的阶段。在实际爬虫过程中遇到反爬机制是再常见不过的,今天为了增加对爬虫机制的理解,我们就通过手动实现多线程的爬虫过程,同时引入IP代理
Stella981 Stella981
4年前
Nginx反爬虫: 禁止某些User Agent抓取网站
一、概述网站反爬虫的原因不遵守规范的爬虫会影响网站的正常使用网站上的数据是公司的重要资产爬虫对网站的爬取会造成网站统计数据的污染常见反爬虫手段1\.根据IP访问频率封禁IP2\.设置账号登陆时长,账号访问过多封禁设置账号的登录限制,只有登录才能展现内容
Stella981 Stella981
4年前
Selenium使用代理出现弹窗验证如何处理
部分商业网站对爬虫程序限制较多,在数据采集的过程中对爬虫请求进行了多种验证,导致爬虫程序需要深入分析目标网站的反爬策略,定期更新和维护爬虫程序,增加了研发的时间和投入成本。这种情况下,使用无头浏览器例如Selenium,模拟用户的请求进行数据采集是更加方便快捷的方式。同时为了避免目标网站出现IP限制,配合爬虫代理,实现每次请求自动切换IP,能够保证长期稳定
采集数据的时候,碰到反爬虫程序怎么办?
当碰到反爬虫程序时,可以尝试以下几种方法来应对:一、调整访问频率降低请求速度:大多数反爬虫机制是基于访问频率来判断是否为爬虫的。如果采集数据时请求发送得过于频繁,很容易被目标网站识别出来。例如,原本你每秒发送10个请求,现在将其降低到每秒12个请求,使其更
小白学大数据 小白学大数据
5个月前
如何通过requests和time模块限制爬虫请求速率?
一、为什么需要限制爬虫请求速率?在爬取网站数据时,网站服务器需要处理我们的请求并返回数据。如果爬虫的请求过于频繁,服务器可能会因为负载过高而崩溃,或者将我们的爬虫IP地址封禁。此外,许多网站都有反爬虫机制,例如检测单位时间内来自同一IP的请求频率。如果请求
网站反爬之封IP应对措施
作为爬虫工作者爬取数据是基本的技能,在日常获取数据的过程中遇到网站反爬也是家常事,网站的反爬方式有很多,今天我们重点来分析下封IP的行为。这种情况下大家都是很简单的使用代理IP就解决了,但是网上ip代理有很多家,到底选哪家好呢?这里推荐口碑很好的亿牛云
爬虫中使用代理IP的一些误区
做为爬虫工作者在日常工作中使用爬虫多次爬取同一网站时,经常会被网站的IP反爬虫机制给禁掉,为了解决封禁IP的问题通常会使用代理IP。但也有一部分人在HTTP代理IP的使用上存在着误解,他们认为使用了代理IP就能解决一切问题,然而实际上代理IP不是万
爬虫代理IP是什么?为什么需要它?
爬虫代理IP是什么?为什么需要它?爬虫代理IP是指使用其他计算机的网络地址来访问目标网站的一种技术。它可以隐藏爬虫程序的真实IP地址,避免被网站识别和封禁12。在进行网络数据采集时,我们经常会遇到一些反爬措施,比如网站限制同一个IP地址的访问频率、次数或时
小白学大数据
小白学大数据
Lv1
男 · 亿牛云 · python技术
宁为代码类弯腰,不为bug点提交!
文章
125
粉丝
5
获赞
18