Hướng dẫn thực hành: cấu hình HTTP/SOCKS5 proxy, kiểm tra IP và vị trí đầu ra, xử lý retry/timeout, và dùng proxy một cách có trách nhiệm.
Công khai: Mình đang làm việc tại ipvora, một dịch vụ residential proxy. Toàn bộ code trong bài là code chung, chạy được với bất kỳ nhà cung cấp nào hỗ trợ HTTP/HTTPS/SOCKS5.
Nếu bạn từng phải kiểm tra một trang web "trông như thế nào" khi người dùng ở Việt Nam truy cập, theo dõi giá công khai trên nhiều thị trường, hay xác minh quảng cáo hiển thị đúng khu vực, sớm muộn bạn sẽ cần đến proxy. Bài này đi thẳng vào phần thực hành: chọn loại proxy nào, khi nào dùng IP xoay (rotating), khi nào giữ phiên (sticky session), và cách viết code Python cho đúng.
1. Datacenter, residential và ISP proxy khác nhau thế nào?
- Datacenter proxy: IP thuộc các trung tâm dữ liệu/nhà cung cấp cloud. Nhanh, rẻ, nhưng nhiều website nhận diện được đây là IP máy chủ, nên nội dung hoặc cách xử lý có thể khác với người dùng thật.
- Residential proxy: IP do nhà mạng cấp cho kết nối dân dụng. Lưu lượng đi qua những IP này giống với người dùng bình thường ở khu vực đó, nên phù hợp cho kiểm thử theo vùng địa lý. Thường tính phí theo GB.
- ISP proxy (static residential): IP dân dụng nhưng cố định, được thuê theo IP/tháng. Phù hợp khi bạn cần một địa chỉ IP ổn định trong thời gian dài, ví dụ quản lý tài khoản mà bạn được phép quản lý, hoặc whitelist IP ở phía đối tác.
2. Rotating hay sticky session?
| Tình huống | Nên dùng |
|---|---|
| Thu thập nhiều trang công khai độc lập (danh sách giá, trang sản phẩm) | Rotating – mỗi request (hoặc mỗi kết nối) có thể ra một IP khác |
| Luồng nhiều bước cần giữ cùng IP: đăng nhập, giỏ hàng, form nhiều trang | Sticky session – giữ một IP trong N phút |
| Cần IP cố định nhiều ngày/tuần | Static/ISP proxy |
Cách bật sticky session (tham số trong username, cổng riêng, hay tuỳ chọn trên dashboard) khác nhau giữa các nhà cung cấp. Trong bài này mình dùng placeholder USERNAME, PASSWORD, PROXY_HOST:PORT – hãy lấy giá trị thật và định dạng xác thực từ dashboard của nhà cung cấp bạn dùng, đừng đoán.
Ví dụ: với ipvora, phiên sticky có thể giữ từ 1 đến 120 phút, còn static residential được thuê theo IP mỗi tháng. Nhà cung cấp khác có thể có giới hạn khác.
Để không hard-code thông tin đăng nhập, ta đặt biến môi trường:
export PROXY_USER="USERNAME" export PROXY_PASS="PASSWORD" export PROXY_HOST="PROXY_HOST" export PROXY_PORT="PORT" 3. Cài đặt
pip install "requests[socks]" "httpx[socks]" playwright playwright install chromium requests[socks] cài thêm PySocks để requests hiểu được URL dạng socks5://; httpx[socks] cài socksio cho httpx.
4. requests: HTTP và SOCKS5
import os import requests USER = os.environ["PROXY_USER"] PASS = os.environ["PROXY_PASS"] HOST = os.environ["PROXY_HOST"] PORT = os.environ["PROXY_PORT"] # HTTP proxy (dùng cho cả URL http:// và https://, HTTPS đi qua CONNECT) http_proxy = f"http://{USER}:{PASS}@{HOST}:{PORT}" # SOCKS5: dùng "socks5h" để DNS được phân giải ở phía proxy socks_proxy = f"socks5h://{USER}:{PASS}@{HOST}:{PORT}" proxies = {"http": http_proxy, "https": http_proxy} resp = requests.get("https://httpbin.org/ip", proxies=proxies, timeout=(5, 20)) resp.raise_for_status() print(resp.json()) Vài lưu ý:
-
socks5hvssocks5: vớisocks5, máy bạn tự phân giải DNS rồi mới gửi IP cho proxy. Khi kiểm thử theo vùng, kết quả DNS có thể khác nhau theo vị trí, nênsocks5hthường là lựa chọn đúng hơn. - Ký tự đặc biệt trong mật khẩu (
@,:,#…) phải được mã hoá bằngurllib.parse.quote(PASS, safe=""). -
timeout=(5, 20): 5 giây để kết nối, 20 giây để đọc. Đừng bao giờ gọi qua proxy mà không có timeout – một request treo có thể chặn cả worker.
5. Kiểm tra IP và vị trí đầu ra
Trước khi chạy job thật, hãy xác nhận proxy đang ra đúng quốc gia bạn cần:
import os import requests proxy = ( f"http://{os.environ['PROXY_USER']}:{os.environ['PROXY_PASS']}" f"@{os.environ['PROXY_HOST']}:{os.environ['PROXY_PORT']}" ) proxies = {"http": proxy, "https": proxy} info = requests.get("https://ipinfo.io/json", proxies=proxies, timeout=(5, 20)).json() print(info.get("ip"), info.get("country"), info.get("city"), info.get("org")) if info.get("country") != "VN": raise SystemExit(f"Proxy không ra IP Việt Nam: {info.get('country')}") Gọi đoạn này vài lần liên tiếp: với rotating proxy, IP thường thay đổi; với sticky session, IP phải giữ nguyên trong suốt thời gian phiên.
6. Retry, backoff và timeout
Residential IP là kết nối dân dụng, nên thỉnh thoảng sẽ có lỗi kết nối hoặc chậm. Thay vì retry vô hạn, hãy dùng urllib3.Retry với backoff tăng dần:
import os import requests from requests.adapters import HTTPAdapter from urllib3.util.retry import Retry def make_session() -> requests.Session: proxy = ( f"http://{os.environ['PROXY_USER']}:{os.environ['PROXY_PASS']}" f"@{os.environ['PROXY_HOST']}:{os.environ['PROXY_PORT']}" ) retry = Retry( total=3, connect=3, read=2, backoff_factor=1.0, # chờ khoảng 0s, 2s, 4s giữa các lần thử status_forcelist=(429, 500, 502, 503, 504), allowed_methods=frozenset({"GET", "HEAD"}), respect_retry_after_header=True, ) session = requests.Session() adapter = HTTPAdapter(max_retries=retry) session.mount("http://", adapter) session.mount("https://", adapter) session.proxies = {"http": proxy, "https": proxy} session.headers["User-Agent"] = "my-qa-bot/1.0 (+mailto:you@example.com)" return session if __name__ == "__main__": s = make_session() r = s.get("https://httpbin.org/ip", timeout=(5, 20)) print(r.status_code, r.json()) Chú ý 429 nằm trong status_forcelist và respect_retry_after_header=True: khi website bảo bạn chậm lại, code sẽ thực sự chậm lại thay vì đổi IP để "lách". Đó là khác biệt giữa một công cụ có trách nhiệm và một công cụ gây hại.
7. httpx (async) với giới hạn đồng thời
Khi cần kiểm tra nhiều URL, httpx.AsyncClient kết hợp asyncio.Semaphore giúp bạn kiểm soát tốc độ:
import asyncio import os import httpx PROXY = ( f"http://{os.environ['PROXY_USER']}:{os.environ['PROXY_PASS']}" f"@{os.environ['PROXY_HOST']}:{os.environ['PROXY_PORT']}" ) URLS = [ "https://httpbin.org/ip", "https://httpbin.org/headers", ] async def fetch(client: httpx.AsyncClient, sem: asyncio.Semaphore, url: str) -> None: async with sem: for attempt in range(3): try: r = await client.get(url) if r.status_code == 429: await asyncio.sleep(int(r.headers.get("Retry-After", "5"))) continue r.raise_for_status() print(url, r.status_code, len(r.content)) break except (httpx.TransportError, httpx.HTTPStatusError) as exc: wait = 2 ** attempt print(f"{url}: {exc!r}, thử lại sau {wait}s") await asyncio.sleep(wait) await asyncio.sleep(1) # nghỉ giữa các request async def main() -> None: sem = asyncio.Semaphore(3) # tối đa 3 request cùng lúc timeout = httpx.Timeout(20.0, connect=5.0) # httpx >= 0.26 dùng tham số `proxy`; bản cũ hơn dùng `proxies` async with httpx.AsyncClient(proxy=PROXY, timeout=timeout) as client: await asyncio.gather(*(fetch(client, sem, u) for u in URLS)) if __name__ == "__main__": asyncio.run(main()) Muốn dùng SOCKS5 với httpx, chỉ cần đổi scheme thành socks5:// (đã cài httpx[socks]).
8. Playwright: kiểm thử giao diện như người dùng ở Việt Nam
Đây là trường hợp mình thấy hữu ích nhất: bạn làm QA cho một website thương mại điện tử và muốn kiểm tra xem người dùng tại Việt Nam có thấy đúng tiếng Việt, giá bằng VND, phương thức thanh toán nội địa và banner khuyến mãi theo vùng hay không. Chạy trình duyệt qua một IP Việt Nam (ví dụ residential proxies tại Việt Nam của ipvora, hoặc của nhà cung cấp bạn đang dùng) sẽ cho bạn đúng góc nhìn đó.
import os from playwright.sync_api import sync_playwright PROXY = { "server": f"http://{os.environ['PROXY_HOST']}:{os.environ['PROXY_PORT']}", "username": os.environ["PROXY_USER"], "password": os.environ["PROXY_PASS"], } with sync_playwright() as p: browser = p.chromium.launch(proxy=PROXY) context = browser.new_context( locale="vi-VN", timezone_id="Asia/Ho_Chi_Minh", viewport={"width": 390, "height": 844}, # giả lập màn hình điện thoại ) page = context.new_page() page.goto("https://ipinfo.io/json", timeout=30_000) print(page.inner_text("body")) page.goto("https://example.com", wait_until="domcontentloaded", timeout=30_000) page.screenshot(path="example_vn.png", full_page=True) browser.close() Mẹo:
- Đặt
localevàtimezone_idkhớp với quốc gia của IP, nếu không bạn đang kiểm thử một tổ hợp mà người dùng thật hiếm khi có. - Với luồng nhiều bước (đăng nhập → giỏ hàng → thanh toán), hãy dùng sticky session để IP không đổi giữa chừng.
- Chromium trong Playwright không hỗ trợ xác thực username/password cho SOCKS5; nếu cần SOCKS5 có mật khẩu, hãy dùng HTTP proxy hoặc whitelist IP (nếu nhà cung cấp hỗ trợ).
9. Dùng proxy có trách nhiệm
Proxy là công cụ mạng, không phải giấy phép. Một vài nguyên tắc mình luôn áp dụng:
- Đọc
robots.txtvà điều khoản sử dụng (ToS) của website. Python có sẵnurllib.robotparser:
from urllib.robotparser import RobotFileParser rp = RobotFileParser("https://example.com/robots.txt") rp.read() print(rp.can_fetch("my-qa-bot", "https://example.com/products")) print(rp.crawl_delay("my-qa-bot")) - Giới hạn tốc độ: dùng semaphore,
sleep, tôn trọngRetry-After. Đừng dùng việc xoay IP để vượt qua rate limit. - Chỉ thu thập dữ liệu công khai, không thu thập dữ liệu cá nhân, không vượt tường đăng nhập/paywall khi không được phép.
- Tuân thủ pháp luật: tại Việt Nam, lưu ý Nghị định 13/2023/NĐ-CP về bảo vệ dữ liệu cá nhân; nếu dữ liệu liên quan đến người dùng ở EU thì có GDPR. Khi không chắc, hỏi bộ phận pháp lý.
- Chỉ quản lý những tài khoản bạn được phép quản lý.
- Đặt User-Agent có thông tin liên hệ để quản trị website có thể liên hệ bạn thay vì chặn.
10. Các use case hợp lệ thường gặp
- Ad verification: kiểm tra quảng cáo hiển thị đúng vùng, đúng nội dung, không bị chèn vào trang không phù hợp.
- Localization/QA testing: xem website, app web hoặc landing page của bạn hiển thị thế nào với người dùng tại Việt Nam, Mỹ, Nhật Bản hay châu Âu.
- Theo dõi giá công khai: so sánh giá niêm yết công khai giữa các thị trường cho nghiên cứu thị trường.
- Kiểm tra CDN và geo-redirect: đảm bảo người dùng ở từng quốc gia được chuyển đến đúng phiên bản trang.
Tổng kết
- Dùng rotating cho các request độc lập, sticky session cho luồng nhiều bước, static/ISP khi cần IP cố định lâu dài.
- Luôn đặt timeout, dùng retry có backoff, và kiểm tra IP/quốc gia đầu ra trước khi chạy job.
- Với SOCKS5 trong
requests, ưu tiênsocks5h://để DNS phân giải ở phía proxy. - Tôn trọng
robots.txt, ToS, rate limit và pháp luật – đó là cách để công cụ của bạn chạy được lâu dài.
Nếu bạn có cách cấu hình proxy hay hơn cho Playwright hoặc httpx, hãy chia sẻ trong phần bình luận nhé!

