Python 爬虫常见反爬策略及应对方案

深入理解反爬虫机制,掌握有效的应对技巧

简介:随着爬虫技术的普及,越来越多的网站采取了反爬措施。本文将详细介绍常见的反爬策略及其应对方法,帮助你构建更加稳定可靠的爬虫系统。

一、User-Agent 检测

检测原理

网站通过检查请求头中的 User-Agent 字段来识别客户端类型,默认的 Python requests 库 User-Agent 容易被识别。

应对方案

import requests # 方案1:设置自定义 User-Agent headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36' } response = requests.get('https://example.com', headers=headers) # 方案2:使用 fake_useragent 库随机切换 from fake_useragent import UserAgent ua = UserAgent() headers = {'User-Agent': ua.random} response = requests.get('https://example.com', headers=headers)

使用技巧:维护一个 User-Agent 池,每次请求随机选择,避免使用单一 UA 被封锁。

二、IP 限制与封锁

检测原理

网站记录请求 IP,对同一 IP 的频繁请求进行限制或直接封锁。

应对方案

import requests from itertools import cycle # 方案1:使用代理 IP 池 proxies = [ {'http': 'http://proxy1.example.com:8080'}, {'http': 'http://proxy2.example.com:8080'}, {'http': 'http://proxy3.example.com:8080'}, ] proxy_pool = cycle(proxies) # 循环使用代理 for i in range(10): proxy = next(proxy_pool) response = requests.get('https://example.com', proxies=proxy) print(f"使用代理: {proxy}, 状态码: {response.status_code}") # 方案2:设置请求延迟 import time import random def fetch_with_delay(url): time.sleep(random.uniform(1, 3)) # 随机延迟 1-3 秒 return requests.get(url)

三、验证码识别

验证码类型

  • 图形验证码:扭曲的文字和数字
  • 滑块验证码:需要拖动滑块完成拼图
  • 点选验证码:点击图中特定元素
  • 行为验证码:通过鼠标轨迹判断是否为真人

应对方案

# 方案1:使用 OCR 识别简单验证码 import pytesseract from PIL import Image def solve_captcha(image_path): image = Image.open(image_path) code = pytesseract.image_to_string(image) return code.strip() # 方案2:使用第三方验证码识别服务 def solve_with_service(image_path): import requests with open(image_path, 'rb') as f: files = {'file': f} response = requests.post('https://api.captcha-service.com/solve', files=files) return response.json()['code'] # 方案3:使用 Selenium 处理滑块验证 from selenium import webdriver from selenium.webdriver import ActionChains def solve_slider(driver, slider_element, distance): action = ActionChains(driver) # 模拟人类拖动轨迹 action.click_and_hold(slider_element).perform() current = 0 while current < distance: action.move_by_offset(5, 0) action.perform() current += 5 time.sleep(0.05) action.release().perform()

注意事项:大规模使用验证码识别服务可能涉及法律风险,请遵守网站服务条款和相关法律法规。

四、Cookies 和 Session 管理

检测原理

网站通过 Cookie 追踪用户状态,验证用户的合法性。

应对方案

import requests # 使用 Session 保持会话 session = requests.Session() # 登录获取 Cookie login_data = { 'username': 'your_username', 'password': 'your_password' } session.post('https://example.com/login', data=login_data) # 使用 Session 自动携带 Cookie response = session.get('https://example.com/protected-page') # 手动设置 Cookie cookies = { 'session_id': 'abc123', 'user_token': 'xyz789' } response = requests.get('https://example.com', cookies=cookies)

五、动态加载内容(AJAX)

检测原理

数据通过 JavaScript 异步加载,直接请求 HTML 无法获取完整数据。

应对方案

# 方案1:分析网络请求,直接调用 API import requests headers = { 'User-Agent': 'Mozilla/5.0 ...', 'X-Requested-With': 'XMLHttpRequest' } response = requests.get('https://api.example.com/data', headers=headers) data = response.json() # 方案2:使用 Selenium 渲染 JavaScript from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC driver = webdriver.Chrome() driver.get('https://example.com') # 等待元素加载完成 element = WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.ID, 'data-container')) ) data = driver.page_source driver.quit() # 方案3:使用 Playwright from playwright.sync_api import sync_playwright with sync_playwright() as p: browser = p.chromium.launch() page = browser.new_page() page.goto('https://example.com') data = page.content() browser.close()

六、请求频率限制

检测原理

检测请求频率,超过阈值时返回 429 Too Many Requests 错误。

应对方案

import requests import time from requests.adapters import HTTPAdapter from urllib3.util.retry import Retry # 方案1:实现自动重试和退避策略 session = requests.Session() retry_strategy = Retry( total=3, backoff_factor=1, status_forcelist=[429, 500, 502, 503, 504] ) adapter = HTTPAdapter(max_retries=retry_strategy) session.mount("http://", adapter) session.mount("https://", adapter) # 方案2:令牌桶算法控制速率 import threading import time class RateLimiter: def __init__(self, rate): self.rate = rate self.lock = threading.Lock() self.tokens = rate self.last_time = time.time() def acquire(self): with self.lock: now = time.time() elapsed = now - self.last_time self.tokens += elapsed * self.rate self.tokens = min(self.tokens, self.rate * 10) if self.tokens < 1: sleep_time = (1 - self.tokens) / self.rate time.sleep(sleep_time) self.tokens = 0 else: self.tokens -= 1 self.last_time = now # 使用示例 limiter = RateLimiter(rate=10) # 每秒 10 个请求 for url in urls: limiter.acquire() response = requests.get(url)

七、加密参数生成

检测原理

关键参数通过 JavaScript 动态加密,逆推加密算法困难。

应对方案

# 方案1:使用 PyExecJS 执行 JavaScript import execjs ctx = execjs.compile(""" function generateSignature(params, secret) { // 这里是网站的加密算法 return MD5(params + secret); } """) signature = ctx.call('generateSignature', 'data123', 'secret_key') # 方案2:使用浏览器环境执行 JS from selenium import webdriver import json driver = webdriver.Chrome() # 注入加密函数 with open('crypto.js', 'r') as f: crypto_code = f.read() driver.execute_script(crypto_code) # 调用函数生成参数 params = {'data': 'test'} signature = driver.execute_script('return generateSignature(arguments[0])', json.dumps(params))

八、字体反爬(自定义字体)

检测原理

使用自定义字体文件,将文本内容替换为特殊字符,浏览器渲染时显示正常文本。

应对方案

# 解析字体文件,建立字符映射 from fontTools.ttLib import TTFont import requests # 下载字体文件 font_url = 'https://example.com/custom.woff' response = requests.get(font_url) with open('custom.woff', 'wb') as f: f.write(response.content) # 解析字体 font = TTFont('custom.woff') # 获取字符映射 glyph_map = {} for cmap in font['cmap'].tables: for code, name in cmap.cmap.items(): if name.startswith('uni'): glyph_map[chr(code)] = name # 使用映射关系替换文本 def decode_text(encoded_text): decoded_text = '' for char in encoded_text: if char in glyph_map: # 根据实际规则映射回原文本 decoded_text += mapping[glyph_map[char]] else: decoded_text += char return decoded_text

九、最佳实践建议

  • 遵守 robots.txt:尊重网站的爬虫规则
  • 控制请求频率:避免对服务器造成压力
  • 使用分布式架构:多 IP、多节点分散请求
  • 异常处理完善:处理各种异常情况,实现自动恢复
  • 数据验证:确保获取的数据完整准确
  • 日志记录:详细记录爬取过程,便于问题排查
  • 定期更新策略:网站反爬策略会不断更新,需要及时应对

温馨提示:使用 EasySpider 在线工具可以快速获取浏览器中的真实请求头和参数,大大简化反爬对策的开发过程。

总结

反爬与反反爬是一个持续的博弈过程。通过本文的学习,你应该能够:

  • 识别常见的反爬策略
  • 掌握多种应对技术方案
  • 构建稳定的爬虫系统
  • 遵循爬虫伦理和法律法规