Quay lại danh sách
Xây dựng proxy pool tự động xoay IP với Redis và RoProxy cho scraping quy mô lớn

Xây dựng proxy pool tự động xoay IP với Redis và RoProxy cho scraping quy mô lớn

16 tháng 8, 2026

Tổng quan

Khi scraping quy mô lớn, một địa chỉ IP đơn lẻ nhanh chóng bị chặn do rate limit hoặc cơ chế anti‑bot. Proxy pool tự động xoay IP giải quyết vấn đề này bằng cách duy trì một tập hợp proxy sống, kiểm tra độ trễ liên tục và cấp proxy phù hợp cho mỗi request.

Kiến trúc tổng quan

  1. RoProxy API – cung cấp residential, mobile, ISP proxy với endpoint lấy danh sách và tham số sticky.
  2. Redis – lưu trữ proxy dưới dạng sorted set proxy_pool với score là độ trễ (ms).
  3. Health‑check worker – chạy định kỳ, test mỗi proxy qua URL http://httpbin.org/ip, cập nhật score hoặc xóa proxy chết.
  4. Proxy client wrapper – hàm get_proxy() trả về proxy có score thấp nhất (nhanh nhất) hoặc round‑robin.
  5. Scraper – Python aiohttp hoặc Node.js axios gọi wrapper trước mỗi request.

Bước 1: Lấy danh sách proxy từ RoProxy

curl -s 'https://api.roproxy.com/v1/proxies?type=residential&count=200' -H 'Authorization: Bearer YOUR_API_KEY' > proxies.json

File proxies.json chứa mảng đối tượng {ip, port, username, password, country}.

Bước 2: Nạp proxy vào Redis

import redis, json
r = redis.Redis(decode_responses=True)
with open('proxies.json') as f:
    data = json.load(f)
for p in data:
    proxy = '{}:{}@{}:{}'.format(p['username'], p['password'], p['ip'], p['port'])
    # score ban đầu 0, sẽ được cập nhật sau health‑check
    r.zadd('proxy_pool', {proxy: 0})

Bước 3: Worker kiểm tra sức khỏe (health‑check)

import asyncio, aiohttp, redis, time
r = redis.Redis(decode_responses=True)
TEST_URL = 'http://httpbin.org/ip'
async def check_proxy(proxy):
    url = f'http://{proxy}'
    start = time.perf_counter()
    try:
        async with aiohttp.ClientSession() as sess:
            async with sess.get(TEST_URL, proxy=url, timeout=5) as resp:
                if resp.status == 200:
                    latency = int((time.perf_counter() - start) * 1000)
                    r.zadd('proxy_pool', {proxy: latency})
                    return
    except Exception:
        pass
    # proxy thất bại -> xóa
    r.zrem('proxy_pool', proxy)

async def run_checks():
    proxies = r.zrange('proxy_pool', 0, -1)
    tasks = [check_proxy(p) for p in proxies]
    await asyncio.gather(*tasks)

# Chạy mỗi 5 phút
while True:
    asyncio.run(run_checks())
    await asyncio.sleep(300)

Bước 4: Wrapper lấy proxy tối ưu

def get_proxy():
    # Lấy 10 proxy nhanh nhất
    top = r.zrange('proxy_pool', 0, 9, withscores=True)
    if not top:
        raise RuntimeError('Không có proxy khả dụng')
    # Chọn ngẫu nhiên trong top 10 để phân tán tải
    import random
    proxy, _ = random.choice(top)
    return proxy

Bước 5: Tích hợp vào scraper

Python (aiohttp)

async def fetch(session, url):
    proxy = get_proxy()
    async with session.get(url, proxy=f'http://{proxy}') as resp:
        return await resp.text()

async def main():
    async with aiohttp.ClientSession() as sess:
        html = await fetch(sess, 'https://example.com')
        print(html[:200])

Node.js (axios)

const axios = require('axios');
const redis = require('redis');
const client = redis.createClient();
await client.connect();

async function getProxy() {
  const top = await client.zRange('proxy_pool', 0, 9, { WITHSCORES: true });
  if (!top.length) throw new Error('Không có proxy');
  const idx = Math.floor(Math.random() * top.length / 2) * 2;
  return top[idx]; // proxy string
}

async function fetch(url) {
  const proxy = await getProxy();
  const res = await axios.get(url, {
    proxy: { host: proxy.split('@')[1].split(':')[0], port: Number(proxy.split('@')[1].split(':')[1]), auth: { username: proxy.split('@')[0].split(':')[0], password: proxy.split('@')[0].split(':')[1] } }
  });
  return res.data;
}

Bước 6: Sticky session khi cần giữ IP

Một số tác vụ (đăng nhập, giỏ hàng) yêu cầu IP cố định trong vài phút. RoProxy hỗ trợ tham số session_id. Chỉ cần thêm header X-RoProxy-Session: <id> khi gọi API lấy proxy, hoặc sử dụng endpoint /v1/proxies?sticky=true&session_id=abc123. Wrapper có thể nhận tham số sticky=True và lưu session ID trong Redis với TTL 10 phút.

Mẹo tối ưu và troubleshooting

  • Giới hạn kết nối: đặt max_connections trong aiohttp.TCPConnector để tránh quá tải proxy.
  • Retry logic: dùng tenacity (Python) hoặc axios-retry (Node) với back‑off exponent.
  • Geo‑targeting: lưu thêm field country trong Redis hash proxy_meta:{proxy} để lọc theo khu vực.
  • Monitoring: xuất metric proxy_pool_size, avg_latency ra Prometheus/Grafana.
  • Xử lý lỗi 403/429: khi nhận mã này, gọi r.zincrby('proxy_pool', 5000, proxy) để tăng latency ảo, buộc worker kiểm tra lại sớm.

Kết luận

Với một proxy pool tự động xoay IP được xây dựng trên Redis và RoProxy, bạn có thể mở rộng scraping từ vài trăm request/ngày lên hàng triệu mà không lo bị chặn. Quy trình health‑check liên tục đảm bảo chỉ proxy khỏe được sử dụng, wrapper đơn giản giúp tích hợp vào bất kỳ stack nào (Python, Node, Go). Hãy thử triển khai ngay hôm nay và quan sát độ thành công request tăng vọt.