Proxy cho Python
Python là ngôn ngữ số 1 cho việc thu thập dữ liệu (parsing) và tự động hóa. Tuy nhiên, bất kỳ script nào sớm hay muộn cũng sẽ gặp phải tình trạng bị chặn IP. Để tránh điều này, bạn cần tích hợp proxy một cách chuyên nghiệp.
Trong hướng dẫn này, chúng ta sẽ tìm hiểu cách kết nối proxy trong bốn kịch bản phổ biến nhất: từ các yêu cầu đơn giản đến quản lý trình duyệt.
📌 Cách 1. Thư viện requests (Phổ biến nhất)
Nếu bạn đang viết một trình thu thập dữ liệu đơn giản hoặc làm việc với API, bạn sẽ sử dụng requests. Ở đây, proxy được truyền qua một dictionary (dict) thông thường.
Mã nguồn:
import requests
# Định dạng: login:password@ip:port
# Trong CyberYozh App, chúng tôi sử dụng cổng 5959 cho HTTP
proxy = "http://user:pass@51.77.190.247:5959"
proxies = {
"http": proxy,
"https": proxy
}
try:
# Luôn phải chỉ định timeout!
response = requests.get("https://httpbin.org/ip", proxies=proxies, timeout=10)
print(f"IP của bạn: {response.json()['origin']}")
except Exception as e:
print(f"Lỗi: {e}")
Lời khuyên: Đừng để proxy trực tiếp trong mã nguồn (hardcode). Tốt nhất nên đưa chúng vào các biến môi trường (os.getenv).
Nếu bạn muốn sử dụng SOCKS5 trong Python, bạn cần:
1. Cài đặt thư viện bổ sung: requests bản thân nó không biết làm việc với SOCKS. Bạn cần cài đặt phần mở rộng:
pip install requests[socks]
# hoặc
pip install pysocks
2. Thay đổi giao thức trong mã nguồn: Tại đây cổng và cú pháp thay đổi thành 9595 và socks5h://.
import requests
# Sử dụng socks5h để bảo vệ chống rò rỉ DNS (Remote DNS resolution)
socks_proxy = "socks5h://user:pass@51.77.190.247:9595"
proxies = {
"http": socks_proxy,
"https": socks_proxy
}
try:
response = requests.get("https://httpbin.org/ip", proxies=proxies, timeout=10)
print(f"IP của bạn qua SOCKS5: {response.json()['origin']}")
except Exception as e:
print(f"Lỗi: {e}")
🤖 Cách 2. Thư viện Selenium (Mô phỏng trình duyệt)
Nếu trang web sử dụng JavaScript phức tạp (React, Vue), Single Page Application (SPA) hoặc bảo vệ Cloudflare, requests thông thường sẽ không thể xử lý — nó đơn giản là không thể thực thi mã JS. Bạn cần Selenium, công cụ mở và điều khiển một trình duyệt thực (Chrome/Firefox).
⚠️ Vấn đề chính: Xác thực
Chrome tiêu chuẩn có một điểm yếu: nó không hỗ trợ việc truyền tên đăng nhập và mật khẩu proxy thông qua các đối số khởi chạy. Nếu bạn cố gắng truyền http://user:pass@ip:port, trình duyệt sẽ bỏ qua việc xác thực và hiện cửa sổ popup yêu cầu nhập mật khẩu, điều này sẽ làm hỏng quá trình tự động hóa.
✅ Giải pháp: Thư viện selenium-wire
Đây là một bản nâng cấp của Selenium thông thường, có khả năng chặn các yêu cầu và tự động điền tên đăng nhập cũng như mật khẩu proxy.
Cài đặt:
pip install selenium-wire
Mã nguồn (Thiết lập đúng với xác thực):
# Lưu ý: import webdriver từ seleniumwire chứ không phải từ selenium
from seleniumwire import webdriver
# Dữ liệu proxy của bạn từ CyberYozh App
PROXY_HOST = "51.77.190.247"
PROXY_PORT = "5959" # Cổng cho HTTP
PROXY_USER = "login_của_bạn"
PROXY_PASS = "mật_khẩu_của_bạn"
# Tạo dictionary thiết lập
proxy_options = {
'proxy': {
'http': f'http://{PROXY_USER}:{PROXY_PASS}@{PROXY_HOST}:{PROXY_PORT}',
'https': f'http://{PROXY_USER}:{PROXY_PASS}@{PROXY_HOST}:{PROXY_PORT}',
'no_proxy': 'localhost,127.0.0.1' # Không dùng proxy cho địa chỉ nội bộ
}
}
# Khởi tạo trình duyệt với tùy chọn seleniumwire_options
driver = webdriver.Chrome(seleniumwire_options=proxy_options)
print("Trình duyệt đã chạy, đang kiểm tra IP...")
driver.get("https://httpbin.org/ip")
# Xuất nội dung trang (nơi sẽ hiển thị IP proxy của bạn)
print(driver.find_element("tag name", "body").text)
driver.quit()
Tại sao cách này hiệu quả: selenium-wire tạo ra một máy chủ trung gian cục bộ, chịu trách nhiệm giao tiếp với proxy của bạn. Trình duyệt nghĩ rằng nó đang hoạt động không cần mật khẩu, trong khi thư viện tự động "gắn" các header xác thực cần thiết. Đây là cách đáng tin cậy nhất cho Python.
Selenium và SOCKS5:
Tương tự như đối với requests, để selenium-wire hoạt động với proxy SOCKS, bạn cần cài đặt thư viện pysocks (nếu chưa có):
pip install pysocks
Mã nguồn cho SOCKS5 (Selenium Wire)
Logic vẫn giữ nguyên: các khóa của dictionary ('http', 'https') cho thư viện biết loại lưu lượng nào cần chặn, và giá trị (socks5://...) — hướng nó đi đâu.
from seleniumwire import webdriver # Import chính xác từ seleniumwire!
# Dữ liệu proxy SOCKS5 của bạn
PROXY_HOST = "51.77.190.247"
PROXY_PORT = "9595" # Đảm bảo đây là cổng dành riêng cho SOCKS5 (thường khác với HTTP)
PROXY_USER = "login_của_bạn"
PROXY_PASS = "mật_khẩu_của_bạn"
# Thiết lập
proxy_options = {
'proxy': {
# Giao thức thay đổi thành socks5://
'http': f'socks5://{PROXY_USER}:{PROXY_PASS}@{PROXY_HOST}:{PROXY_PORT}',
'https': f'socks5://{PROXY_USER}:{PROXY_PASS}@{PROXY_HOST}:{PROXY_PORT}',
'no_proxy': 'localhost,127.0.0.1'
}
}
# Chạy trình duyệt
# Có thể thêm các tùy chọn Chrome thông thường (headless...) qua chrome_options=...
driver = webdriver.Chrome(seleniumwire_options=proxy_options)
try:
print("Trình duyệt đã chạy, đang kiểm tra IP...")
driver.get("https://httpbin.org/ip")
# Xuất IP
print(driver.find_element("tag name", "body").text)
# Khuyên bạn nên kiểm tra loại proxy trên trang web chi tiết hơn
# driver.get("https://browserleaks.com/ip")
except Exception as e:
print(f"Lỗi: {e}")
finally:
driver.quit()
Sự khác biệt là gì?
Trong dictionary proxy_options, chúng ta thay đổi giao thức từ http:// thành socks5://.
Lưu ý các khóa của dictionary: Chúng ta KHÔNG thay đổi các khóa 'http' và 'https' thành 'socks'.
-
Khóa
'https'nghĩa là: "Khi trình duyệt yêu cầu các trang HTTPS..." -
Giá trị
socks5://...nghĩa là: "...hãy gửi chúng qua đường hầm SOCKS5 này".
Thế còn DNS (socks5h)?
Trong selenium-wire, việc giải quyết DNS do logic nội bộ của thư viện đảm nhận. Thông thường, nó sẽ tự xử lý việc chuyển hướng các yêu cầu DNS qua proxy nếu sử dụng giao thức socks5, vì selenium-wire hoạt động như một Man-in-the-Middle (người trung gian) giữa trình duyệt và internet.
Nếu đột nhiên bạn thấy rò rỉ DNS (nhà cung cấp mạng của bạn hiển thị trên các trang kiểm tra), hãy thử chỉ định socks5h:// trong chuỗi kết nối — selenium-wire hỗ trợ định dạng này nhờ thư viện requests bên dưới.
🚀 Cách 3. Thư viện aiohttp (Bất đồng bộ)
Khi cần thu thập 10.000 trang mỗi phút, người ta sử dụng phương pháp bất đồng bộ (async/await). Ở đây requests thông thường không phù hợp, bạn cần aiohttp.
Mã nguồn:
import aiohttp
import asyncio
async def fetch_ip():
proxy_auth = aiohttp.BasicAuth('user', 'pass') # Login và password riêng biệt
proxy_url = "http://51.77.190.247:5959"
async with aiohttp.ClientSession() as session:
async with session.get("https://httpbin.org/ip",
proxy=proxy_url,
proxy_auth=proxy_auth) as resp:
print(await resp.json())
asyncio.run(fetch_ip())
SOCKS5 cho aiohttp
Đối với aiohttp, tình hình hơi phức tạp hơn so với requests. Bản thân thư viện aiohttp không hỗ trợ SOCKS proxy trực tiếp. Nó chỉ có thể làm việc với proxy HTTP.
Để "dạy" nó làm việc với SOCKS5, bạn cần sử dụng một connector đặc biệt.
1. Cài đặt
Bạn sẽ cần thư viện bổ sung aiohttp-socks:
pip install aiohttp-socks
2. Mã nguồn (cách tiếp cận đúng qua Connector)
Khác với ví dụ HTTP nơi chúng ta truyền proxy vào mỗi yêu cầu (session.get(..., proxy=...)), đối với SOCKS5, chúng ta thiết lập proxy một lần khi tạo session.
Điều này thậm chí còn tốt hơn cho hiệu năng (kết nối Keep-Alive).
import aiohttp
import asyncio
from aiohttp_socks import ProxyConnector # Import connector
async def fetch_ip():
# Tạo chuỗi kết nối.
# Lưu ý: lồng tên đăng nhập và mật khẩu trực tiếp vào chuỗi URL.
socks_url = "socks5://user:pass@51.77.190.247:9595"
# Tạo connector
# rdns=True tương đương với socks5h (bảo vệ rò rỉ DNS).
# Đây là điều BẮT BUỘC để đảm bảo ẩn danh.
connector = ProxyConnector.from_url(socks_url, rdns=True)
# Truyền connector vào ClientSession
# Bây giờ toàn bộ session này sẽ hoạt động qua SOCKS5
async with aiohttp.ClientSession(connector=connector) as session:
try:
# LƯU Ý: Bên trong .get() KHÔNG CẦN viết proxy=... nữa
# Proxy đã được tích hợp vào session thông qua connector.
async with session.get("https://httpbin.org/ip") as resp:
print(await resp.json())
except Exception as e:
print(f"Lỗi: {e}")
if __name__ == '__main__':
# Khởi chạy đúng cách cho Windows/Linux
asyncio.run(fetch_ip())
🔍 Những điểm khác biệt chính so với phương án HTTP là gì?
-
Thư viện: Chúng ta đã thêm
from aiohttp_socks import ProxyConnector. -
Vị trí thiết lập:
-
Trước đây:
session.get(..., proxy=...)(thiết lập trong mỗi yêu cầu). -
Hiện nay:
aiohttp.ClientSession(connector=...)(thiết lập cho toàn bộ session).
-
-
DNS (rdns=True): Tham số
rdns=Truethực hiện cùng chức năng nhưsocks5h— bắt buộc giải quyết tên miền ở phía proxy, che giấu điểm đến của bạn khỏi nhà cung cấp mạng.
Mã nguồn này hoàn hảo để thu thập 10.000 trang, vì connector quản lý hiệu quả nhóm kết nối qua đường hầm SOCKS.
🔧 Cách 4. Sử dụng biến môi trường (Best Practice)
Các nhà phát triển chuyên nghiệp không viết proxy trực tiếp trong mã nguồn. Điều này không an toàn (nếu bạn đăng mã lên GitHub, proxy của bạn sẽ bị đánh cắp). Python có khả năng tự động lấy proxy từ hệ thống.
Trong terminal (Linux/Mac):
export HTTP_PROXY="http://user:pass@51.77.190.247:5959"
Trong mã nguồn:
import requests
# Không cần truyền bất kỳ đối số proxies=... nào!
# Thư viện sẽ tự tìm thiết lập trong hệ thống.
requests.get("https://httpbin.org/ip")
💡 Nên chọn loại proxy nào cho script Python?
Viết code chỉ là một nửa công việc. Điều quan trọng nhất là chất lượng của chính proxy đó và cách quản lý xoay vòng (rotation). Tùy vào nhiệm vụ, kiến trúc của script sẽ thay đổi.
1. Proxy Server IPv4, IPv6 (Server Data Center)
Hoàn hảo cho: Các yêu cầu API đơn giản, tải tệp, làm việc với các trang web không có bảo mật gắt gao.
-
Logic trong Python: Nếu IP bị chặn — chỉ cần dùng script thay đổi nó sang IP tiếp theo trong danh sách proxy của bạn.
-
Ưu điểm: Tốc độ cao (lên đến 1 Gbps) và giá thành rẻ.
2. Proxy Dân cư Xoay vòng (Residential Rotating)
Hoàn hảo cho: Thu thập dữ liệu cường độ cao (Amazon, Avito), vượt qua Cloudflare và thu thập khối lượng dữ liệu lớn.
-
Cách hoạt động của xoay vòng: Bạn không cần viết code xoay vòng phức tạp. Trong CyberYozh App, chúng tôi sử dụng "Trình tạo thông tin đăng nhập thông minh". Bạn thay đổi logic hành vi của proxy chỉ bằng cách thay đổi tên đăng nhập:
-
login-res-any: Script nhận một IP mới cho mỗi yêu cầu (requests.get). login-res-any-sid-12345678: IP được cố định cho bộ số này (sid) trong thời gian tối đa 1 phút.-
login-resfix: Script cố định IP cho chính nó (Sticky Session) để xác thực.
-
-
Điểm cộng cho Python: Bạn chỉ sử dụng duy nhất một chuỗi kết nối nhưng lại có quyền truy cập vào hàng triệu IP.
👉 Bạn có thể đọc thêm về xoay vòng cho proxy dân cư tại đây.
3. Proxy Di động (Mobile 4G/LTE)
Hoàn hảo cho: Đăng ký tài khoản, làm việc với mạng xã hội (Instagram, TikTok) và giả lập người dùng thực qua Selenium/Appium. Mức độ tin cậy (trust) cao nhất.
Có hai kịch bản quản lý trong mã nguồn tại đây:
-
🅰️ Riêng tư (Private): Xoay vòng qua link Bạn thuê toàn bộ modem. Để thay đổi IP, script Python của bạn phải "gọi" đến một link API đặc biệt.
-
Ví dụ logic:
# 1. Thực hiện một chu kỳ hành động do_registration() # 2. Khởi động lại modem qua API requests.get("https://app.cyberyozh.com/api/v1/...") time.sleep(15) # Chờ cho modem khởi động xong # 3. Bắt đầu chu kỳ mới
-
-
🅱️ Chia sẻ (Shared): Tự động xoay vòng IP tự thay đổi theo bộ hẹn giờ của dịch vụ (ví dụ: mỗi 5 hoặc 30 phút).
- Logic trong Python: Bạn cần xử lý việc ngắt kết nối. Nếu trong khi gửi yêu cầu mà modem đang khởi động lại — script phải bắt lỗi
ConnectionError, chờ vài giây và thử lại yêu cầu (Retry).
- Logic trong Python: Bạn cần xử lý việc ngắt kết nối. Nếu trong khi gửi yêu cầu mà modem đang khởi động lại — script phải bắt lỗi
👉 Bạn có thể đọc thêm về proxy di động tại đây.
Kết luận
Tích hợp proxy trong Python chỉ mất từ 3-5 dòng mã. Quan trọng nhất là chọn đúng loại proxy phù hợp với nhiệm vụ và thư viện tương ứng.
👉 Bạn đã sẵn sàng lập trình chưa? Trong danh mục CyberYozh App, bạn sẽ tìm thấy tất cả các loại proxy đã nêu. Chỉ cần chọn gói cước phù hợp với nhiệm vụ của bạn (thu thập dữ liệu, đăng ký hoặc lướt web), sao chép thông tin truy cập và tích hợp vào dự án của bạn chỉ trong vài phút.