简介:随着爬虫技术的普及,越来越多的网站采取了反爬措施。本文将详细介绍常见的反爬策略及其应对方法,帮助你构建更加稳定可靠的爬虫系统。
一、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 在线工具可以快速获取浏览器中的真实请求头和参数,大大简化反爬对策的开发过程。
总结
反爬与反反爬是一个持续的博弈过程。通过本文的学习,你应该能够:
- 识别常见的反爬策略
- 掌握多种应对技术方案
- 构建稳定的爬虫系统
- 遵循爬虫伦理和法律法规