PycURL proxy: cấu hình libcurl trong Python và đọc mã lỗi
PycURL proxy là cách cho binding libcurl trong Python gửi request qua máy trung gian bằng các tùy chọn setopt trên đối tượng Curl. PycURL không giống Requests: anh em tự quản bộ đệm, tự đọc mã lỗi và tự đóng đối tượng. ProxyVN chạy PycURL 7.49.0 với libcurl 8.23.0 qua proxy HTTP có mật khẩu và SOCKS5 tự dựng, ghi lại 21 ca thử cùng bảng errno.
PycURL proxy khác cURL CLI và Requests ở đâu
PycURL là lớp mỏng trên libcurl
PycURL là binding Python của libcurl, thư viện truyền dữ liệu đứng sau lệnh curl. Mỗi request là một đối tượng pycurl.Curl. Anh em gọi setopt để đặt từng tùy chọn, gọi perform để chạy, gọi getinfo để đọc kết quả, rồi close để giải phóng. Không có đối tượng response, không có phương thức json, không có ngoại lệ cho mã 4xx.
Cách làm việc gần với C như vậy đổi lại tốc độ và quyền kiểm soát. PycURL cho truy cập gần như mọi tùy chọn của libcurl, kể cả những tùy chọn proxy mà thư viện Python khác không có, như ép đường hầm cho URL http hay chọn kiểu xác thực proxy. Trang PycURL trên GitHub mô tả thư viện là giao diện Python tới libcurl.
Với PycURL, mọi tùy chọn proxy là tùy chọn của libcurl. Khi tra cứu, đọc tài liệu libcurl cho tên tùy chọn tương ứng, bỏ tiền tố CURLOPT_.
Ranh giới với các bài đã có
Bài curl proxy là gì nói về lệnh curl trên dòng lệnh với cờ -x và -U. Bài PHP cURL proxy nói về curl_setopt trong PHP, dùng cùng tên tùy chọn CURLOPT_PROXY. Bài Python Requests proxy nói về dict proxies của Requests.
Bài này không lặp cú pháp dòng lệnh hay PHP. Nó tập trung vào vòng đời đối tượng Curl trong Python, cách dùng bộ đệm BytesIO, cách đọc HTTP_CONNECTCODE, và bảng errno của libcurl đặt cạnh mã HTTP từ máy chủ, đúng yêu cầu của brief.
Môi trường lab
Lab chạy trên Windows 10, Python 3.12 trong môi trường ảo, PycURL cài từ PyPI. Chuỗi phiên bản in ra là PycURL 7.49.0, libcurl 8.23.0, OpenSSL 3.6.5 và Schannel, kèm zlib, brotli, nghttp2. Bản wheel cho Windows đã có sẵn libcurl bên trong, không cần cài curl riêng.
Proxy thử là một chương trình Python nghe các cổng riêng: website thử, proxy HTTP cần tài khoản user1 với mật khẩu p@ss#2026, proxy SOCKS5 cùng tài khoản. Website tên shop.test, chỉ phân giải được bên trong proxy. Request đi thẳng sẽ báo lỗi phân giải, request qua proxy sẽ nhận JSON.
Chuẩn bị PycURL proxy: cài đặt và hàm chạy thử
Cài đặt và kiểm phiên bản
Trên Windows, pip cài bản wheel có sẵn libcurl. Trên Linux, có thể phải cài gói phát triển libcurl và OpenSSL trước để biên dịch. Sau khi cài, in pycurl.version để biết đúng bản libcurl và thư viện TLS, vì hành vi proxy phụ thuộc vào libcurl chứ không phụ thuộc vào số phiên bản PycURL.
python -m venv venv
venv\Scripts\python -m pip install pycurl
venv\Scripts\python -c "import pycurl; print(pycurl.version)"
Ghi chuỗi phiên bản này vào README dự án. Khi có máy báo lỗi khác máy khác, so chuỗi phiên bản trước tiên, rất nhiều khác biệt đến từ bản libcurl hoặc thư viện TLS đi kèm.
Hàm chạy một request có bộ đệm

Một request là một đối tượng Curl
Đây là hàm mình dùng cho mọi ca trong lab. Nó tạo đối tượng Curl, gắn bộ đệm BytesIO cho thân response, gắn hàm ghi tiêu đề, đặt timeout, áp các tùy chọn truyền vào, rồi in mã HTTP, mã CONNECT và đoạn đầu thân.
import io
import pycurl
def run(name, url, **opt):
body, headers = io.BytesIO(), io.BytesIO()
c = pycurl.Curl()
c.setopt(pycurl.URL, url)
c.setopt(pycurl.WRITEDATA, body)
c.setopt(pycurl.HEADERFUNCTION, headers.write)
c.setopt(pycurl.CONNECTTIMEOUT, 3)
c.setopt(pycurl.TIMEOUT, opt.pop("timeout", 8))
for key, value in opt.items():
c.setopt(getattr(pycurl, key), value)
try:
c.perform()
print(name, "OK", c.getinfo(pycurl.RESPONSE_CODE),
"connect", c.getinfo(pycurl.HTTP_CONNECTCODE), body.getvalue()[:70])
except pycurl.error as e:
print(name, "ERR errno", e.args[0], e.args[1],
"connect", c.getinfo(pycurl.HTTP_CONNECTCODE))
finally:
c.close()
Khối finally gọi close để giải phóng tài nguyên libcurl dù request lỗi. Với chương trình chạy lâu, quên close là nguồn rò bộ nhớ và rò kết nối hay gặp.
Vì sao phải tự quản bộ đệm
libcurl không tự giữ thân response. Nó gọi một hàm ghi mỗi khi nhận được dữ liệu. PycURL cho anh em truyền một đối tượng có phương thức write qua WRITEDATA, thường là io.BytesIO. Thân response nằm trong bộ đệm dưới dạng bytes, cần tự giải mã bằng đúng bảng mã.
Tiêu đề response đi qua HEADERFUNCTION theo từng dòng. Khi đi qua proxy HTTP với đường hầm, bộ đệm tiêu đề chứa cả dòng trả lời của proxy cho lệnh CONNECT, ví dụ 200 Connection established, rồi mới tới tiêu đề của website. Đọc tiêu đề mà không biết điều này dễ nhầm tiêu đề của proxy là của website.
Cấu hình PycURL proxy tối thiểu
PROXY và PROXYUSERPWD
Tùy chọn PROXY nhận địa chỉ proxy, PROXYUSERPWD nhận chuỗi tên:mật khẩu. Đây là cách mình khuyên dùng, vì mật khẩu nằm riêng, không phải mã hóa phần trăm.
run("proxy", "http://shop.test:8941/b",
PROXY="127.0.0.1:8942", PROXYUSERPWD="user1:p@ss#2026")
Kết quả 200, thân là JSON của shop.test. Nhật ký proxy ghi GET http://shop.test:8941/b với tài khoản user1, xác thực đạt. Không có proxy, cùng URL báo errno 6, Could not resolve host: shop.test.
Mật khẩu p@ss#2026 có @ và # nhưng không gây lỗi ở PROXYUSERPWD. libcurl tách tên và mật khẩu ở dấu hai chấm đầu tiên. Nếu tên người dùng có dấu hai chấm, dùng hai tùy chọn riêng PROXYUSERNAME và PROXYPASSWORD.
Tài khoản trong URL proxy
Cách thứ hai là ghi tài khoản ngay trong URL proxy. Khi đó phải mã hóa phần trăm. Chuỗi http://user1:p%40ss%[email protected]:8942 chạy được, proxy nhận đúng user1. Chuỗi nguyên văn http://user1:p@ss#[email protected]:8942 báo errno 5, Could not resolve proxy: ss.
Thông điệp Could not resolve proxy: ss rất đáng nhớ. Tên ss là phần của mật khẩu bị tách sai. Gặp tên proxy lạ trong lỗi errno 5, kiểm mật khẩu trước khi kiểm DNS. Bài định dạng proxy có bảng mã hóa ký tự.
libcurl gửi tài khoản ngay từ đầu
Nhật ký proxy cho thấy mỗi request PycURL có tài khoản chỉ tạo một dòng, có Proxy-Authorization ngay từ lần đầu. Khác với Apache HttpClient bên Java, libcurl với kiểu xác thực mặc định gửi Basic luôn, không chờ proxy trả 407.
Đặt PROXYAUTH là pycurl.HTTPAUTH_BASIC cho kết quả giống hệt. Với proxy cần kiểu xác thực khác như Digest hay NTLM, đặt PROXYAUTH tương ứng, libcurl sẽ thương lượng. Mình chỉ thử Basic trong lab.
PycURL proxy với HTTPS và đường hầm
URL https đi qua CONNECT
Với https://example.com qua proxy có tài khoản, PycURL trả 200, getinfo HTTP_CONNECTCODE trả 200. Nhật ký proxy ghi CONNECT example.com:443 với user1. Nghĩa là libcurl mở đường hầm rồi bắt tay TLS với example.com bên trong đường hầm.
HTTP_CONNECTCODE là mã proxy trả cho lệnh CONNECT, khác với RESPONSE_CODE là mã website trả. Với URL http đi thẳng qua proxy không đường hầm, HTTP_CONNECTCODE bằng 0 vì không có lệnh CONNECT nào. Đây là cách phân biệt hai chặng trong cùng một request.
Sai mật khẩu với https và http khác nhau

Hai chỗ bắt lỗi 407
Đây là phát hiện quan trọng nhất của lab. Với URL https và mật khẩu sai, perform ném pycurl.error errno 7, thông điệp CONNECT tunnel failed, response 407, HTTP_CONNECTCODE là 407. Với URL http và mật khẩu sai, perform không ném lỗi nào. RESPONSE_CODE trả 407, thân rỗng.
Nghĩa là cùng một lỗi tài khoản, mã của anh em phải bắt ở hai nơi. Với http, kiểm RESPONSE_CODE bằng 407 sau perform. Với https, bắt pycurl.error và đọc HTTP_CONNECTCODE. Bỏ sót một nơi, chương trình sẽ coi request http bị proxy từ chối là thành công với thân rỗng.
def proxy_rejected(c, err=None):
if err is not None and c.getinfo(pycurl.HTTP_CONNECTCODE) == 407:
return True
return err is None and c.getinfo(pycurl.RESPONSE_CODE) == 407
Bài sửa lỗi 407 Proxy Authentication Required có danh sách nguyên nhân phía nhà cung cấp.
Ép đường hầm cho URL http
Tùy chọn HTTPPROXYTUNNEL bằng 1 buộc libcurl mở đường hầm CONNECT kể cả với URL http. Trong lab, URL http://shop.test qua HTTPPROXYTUNNEL trả 200, HTTP_CONNECTCODE 200, nhật ký ghi CONNECT shop.test:8941.
Dùng tùy chọn này khi proxy chỉ cho phép CONNECT, hoặc khi không muốn proxy đọc nội dung request http. Nhược điểm là một số proxy công ty chặn CONNECT tới cổng khác 443. Thấy lỗi errno 56 hoặc HTTP_CONNECTCODE là 403 khi bật HTTPPROXYTUNNEL, kiểm chính sách cổng của proxy. Bài lỗi curl 56 giải thích nhóm lỗi nhận dữ liệu.
PycURL proxy với SOCKS5
socks5 và socks5h khác nhau thật

socks5h để proxy tra tên miền
Với PROXY là socks5://127.0.0.1:8943 cùng PROXYUSERPWD, request tới shop.test báo errno 6, Could not resolve host: shop.test. libcurl phân giải tên miền tại máy trước, không phân giải được nên dừng, không kết nối tới proxy SOCKS.
Đổi sang socks5h://127.0.0.1:8943, request trả 200, nhật ký SOCKS ghi CONNECT shop.test với kiểu địa chỉ domain. Chữ h cuối có nghĩa là để proxy phân giải tên miền. Với crawler, đây là khác biệt lớn về rò rỉ DNS: socks5 làm máy hỏi DNS cục bộ cho mọi tên miền. Bài DNS leak khi dùng proxy giải thích rủi ro này.
Tài khoản SOCKS
PROXYUSERPWD dùng chung cho cả proxy HTTP và SOCKS5. Trong lab, proxy SOCKS nhận đúng user1 với mật khẩu có ký tự đặc biệt. Có thể đặt kiểu proxy bằng PROXYTYPE thay vì tiền tố trong URL, nhưng tiền tố dễ đọc hơn và ít nhầm hơn.
Tài liệu libcurl có các hằng số PROXYTYPE_SOCKS5 và PROXYTYPE_SOCKS5_HOSTNAME tương ứng với socks5 và socks5h. Khi đọc mã cũ thấy PROXYTYPE_SOCKS5, nhớ rằng nó tương đương socks5 không có h, tức phân giải tại máy.
Chọn HTTP hay SOCKS5 cho PycURL
libcurl hỗ trợ cả hai rất tốt, nên lựa chọn phụ thuộc gói proxy hơn là thư viện. Proxy HTTP cho thêm HTTP_CONNECTCODE để đọc lỗi rõ ràng. SOCKS5 hợp khi gói chỉ mở cổng SOCKS hoặc cần đi qua giao thức không phải HTTP. Bài proxy HTTP và SOCKS5 so sánh chi tiết.
Biến môi trường và NOPROXY trong PycURL proxy
libcurl đọc biến proxy
Không đặt PROXY, libcurl đọc biến môi trường. Trong lab, đặt http_proxy rồi gọi URL http không có tùy chọn proxy nào, request qua proxy và trả 200. ALL_PROXY cũng có tác dụng. Với URL https, libcurl đọc HTTPS_PROXY hoặc https_proxy.
Tài liệu CURLOPT_PROXY của libcurl ghi biến http_proxy chỉ đọc bản chữ thường, vì lý do bảo mật liên quan tới CGI. Trên Windows, biến môi trường không phân biệt hoa thường nên lab không thấy khác biệt. Trên Linux và macOS, HTTP_PROXY chữ hoa sẽ bị bỏ qua cho URL http. Viết http_proxy chữ thường để chạy được ở mọi nơi.
Đặt PROXY thành chuỗi rỗng để tắt
Khi cần một request đi thẳng dù môi trường có biến proxy, đặt PROXY thành chuỗi rỗng. Tài liệu libcurl ghi chuỗi rỗng tắt proxy, kể cả proxy từ biến môi trường. Đây là cách chắc nhất cho request tới dịch vụ nội bộ.
c.setopt(pycurl.PROXY, "")
NOPROXY
Tùy chọn NOPROXY nhận danh sách host cách nhau bằng dấu phẩy, bỏ qua proxy cho các host đó. Trong lab, đặt PROXY kèm NOPROXY là shop.test, request đi thẳng và báo errno 6. Biến môi trường no_proxy có tác dụng tương tự khi proxy lấy từ môi trường.
Bài no_proxy là gì giải thích quy ước viết danh sách. Với libcurl, giá trị * trong NOPROXY bỏ qua proxy cho mọi host.
Bảng errno libcurl và mã HTTP khi dùng PycURL proxy
Hai loại mã, hai nơi đọc
Brief yêu cầu bảng errno libcurl đặt cạnh lỗi HTTP từ máy chủ. Điều cần nắm trước: errno chỉ có khi perform ném pycurl.error, nghĩa là libcurl không hoàn tất trao đổi. Mã HTTP có khi perform chạy xong, đọc bằng getinfo RESPONSE_CODE, kể cả khi mã là 404 hay 503.
Mặc định libcurl không coi 4xx, 5xx là lỗi. Trong lab, trang trả 503 cho perform chạy xong với RESPONSE_CODE 503. Bật FAILONERROR bằng 1, cùng trang làm perform ném errno 22, The requested URL returned error: 503.
Bảng tra từ lab
Bảng dưới gom các ca đã chạy. Tên mã lỗi theo danh sách lỗi của libcurl.
Ca trong lab |
Kết quả |
Nghĩa |
|---|---|---|
Không proxy, tên chỉ có trong proxy |
errno 6 COULDNT_RESOLVE_HOST |
Request đi thẳng |
Mật khẩu chưa mã hóa trong URL |
errno 5 COULDNT_RESOLVE_PROXY, tên ss |
Chuỗi proxy tách sai |
Proxy không mở cổng |
errno 7 COULDNT_CONNECT, over proxy |
Sai cổng hoặc proxy chết |
Sai mật khẩu, URL https |
errno 7, CONNECT tunnel failed, response 407 |
Proxy từ chối ở bước CONNECT |
Sai mật khẩu, URL http |
Không lỗi, RESPONSE_CODE 407 |
Proxy từ chối, phải tự kiểm |
Trang chậm hơn TIMEOUT |
errno 28 OPERATION_TIMEDOUT |
Quá hạn |
Trang trả 503 |
Không lỗi, RESPONSE_CODE 503 |
Website lỗi |
Trang trả 503, FAILONERROR |
errno 22 HTTP_RETURNED_ERROR |
Website lỗi, ném ngoại lệ |
socks5:// với tên chỉ có trong proxy |
errno 6 |
Phân giải tại máy |
NOPROXY chứa host |
errno 6 |
Đi thẳng như mong đợi |
Thông điệp của errno 7 với proxy chết có chữ over proxy 127.0.0.1, cho biết libcurl đang cố tới proxy chứ không phải website. Thông điệp errno 28 ghi rõ số mili giây đã chờ và số byte đã nhận, giúp biết chậm ở bước nào.
Với PycURL proxy, lỗi tài khoản trên URL http không ném ngoại lệ. Luôn kiểm RESPONSE_CODE bằng 407 sau perform, nếu không chương trình sẽ coi thân rỗng là thành công.
Chạy đối chứng PycURL proxy: timeout, redirect, POST
Timeout
CONNECTTIMEOUT giới hạn thời gian kết nối, khi có proxy là thời gian kết nối tới proxy. TIMEOUT giới hạn cả request. Trong lab, trang chờ 5 giây với TIMEOUT 2, libcurl ném errno 28 sau khoảng 2014 mili giây, không nhận byte nào.
Mặc định libcurl không giới hạn thời gian tổng của request. Với proxy, luôn đặt cả hai tùy chọn. Với tải tệp lớn, dùng LOW_SPEED_LIMIT và LOW_SPEED_TIME để cắt khi tốc độ quá thấp thay vì đặt TIMEOUT quá dài.
Redirect
Mặc định libcurl không theo redirect. Trang /redir trả 302, perform chạy xong với RESPONSE_CODE 302, thân rỗng. Bật FOLLOWLOCATION bằng 1, libcurl theo sang /after-redirect, trả 200. Nhật ký proxy ghi cả hai request, request sau cũng có tài khoản.
Khi theo redirect sang host khác, libcurl mặc định không gửi tài khoản website sang host mới, nhưng tài khoản proxy vẫn dùng cho mọi chặng vì proxy không đổi. Đặt MAXREDIRS để tránh vòng lặp redirect vô hạn qua proxy.
POST JSON
POST với POSTFIELDS là chuỗi JSON và HTTPHEADER Content-Type application/json đi qua proxy, website nhận đúng thân {"sku":"A1"}. Nhật ký ghi một POST có tài khoản, không có vòng 407 nào vì libcurl gửi tài khoản ngay.
libcurl không tự thử lại request. Với POST tạo dữ liệu, giữ nguyên như vậy. Với GET, tự viết vòng thử lại cho errno 7, 28 và 56, giới hạn số lần và có khoảng nghỉ.
Đo thời gian từng chặng của PycURL proxy
getinfo cho biết chậm ở đâu
Một ưu điểm lớn của libcurl là đo thời gian từng chặng của request. Sau perform, getinfo trả các mốc tính từ lúc bắt đầu. NAMELOOKUP_TIME là lúc phân giải xong tên, CONNECT_TIME là lúc kết nối TCP xong, APPCONNECT_TIME là lúc bắt tay TLS xong. PRETRANSFER_TIME là lúc sắp gửi, STARTTRANSFER_TIME là lúc nhận byte đầu, TOTAL_TIME là lúc kết thúc.
Khi đi qua proxy, các mốc này mang nghĩa hơi khác. NAMELOOKUP_TIME và CONNECT_TIME là cho tên và kết nối tới proxy, không phải tới website. Với URL https qua đường hầm, APPCONNECT_TIME gồm cả thời gian proxy mở đường hầm tới website và thời gian bắt tay TLS với website bên trong đường hầm.
def timings(c):
keys = ["NAMELOOKUP_TIME", "CONNECT_TIME", "APPCONNECT_TIME",
"PRETRANSFER_TIME", "STARTTRANSFER_TIME", "TOTAL_TIME"]
return {k.lower(): round(c.getinfo(getattr(pycurl, k)), 3) for k in keys}
Gọi hàm này trước close, ghi kết quả vào log cùng mã trạng thái. Sau vài trăm request, anh em sẽ thấy rõ proxy nào chậm ở bước kết nối và website nào chậm ở bước trả byte đầu.
Đọc kết quả để quyết định
Nếu CONNECT_TIME lớn, chậm nằm ở chặng từ máy tới proxy: proxy ở xa, quá tải hoặc mạng tới proxy kém. Đổi proxy gần hơn hoặc giảm số kết nối đồng thời. Nếu khoảng giữa PRETRANSFER_TIME và STARTTRANSFER_TIME lớn, website xử lý chậm, đổi proxy không giúp gì.
Nếu APPCONNECT_TIME lớn hơn nhiều so với CONNECT_TIME, chặng proxy tới website hoặc bắt tay TLS đang chậm. Với proxy dân cư, chặng này thường dài hơn proxy datacenter vì đi qua mạng của người dùng cuối. Đó là đánh đổi bình thường, không phải lỗi.
PycURL proxy sau proxy kiểm tra TLS
Chứng chỉ của website và chứng chỉ của proxy
libcurl phân biệt hai bộ chứng chỉ. CAINFO là bó chứng chỉ để kiểm website. PROXY_CAINFO là bó chứng chỉ để kiểm chính proxy khi kết nối tới proxy bằng HTTPS. Với proxy HTTP thông thường, chỉ CAINFO có ý nghĩa.
Sau proxy kiểm tra TLS của công ty, chứng chỉ website mà libcurl nhận được do CA nội bộ ký. Nếu bó chứng chỉ không có CA đó, perform ném lỗi chứng chỉ. Cách sửa là đặt CAINFO trỏ tới tệp PEM gồm CA nội bộ, hoặc dùng thư viện TLS của hệ điều hành nếu bản libcurl hỗ trợ.
Không tắt kiểm tra chứng chỉ
Nhiều ví dụ trên mạng đặt SSL_VERIFYPEER bằng 0 để chữa lỗi. Làm vậy, mọi kết nối HTTPS của đối tượng Curl đều có thể bị chặn bắt mà không có cảnh báo. Với crawler hay công cụ gọi API có khóa bí mật, đây là rủi ro không đáng.
Bản wheel Windows trong lab có cả OpenSSL và Schannel trong chuỗi phiên bản. Schannel dùng kho chứng chỉ của Windows, nơi công ty thường đã cài CA nội bộ. Chọn đúng thư viện TLS có thể giải quyết lỗi mà không cần tệp PEM riêng, nhưng cách chọn phụ thuộc bản libcurl, cần thử trên máy thật.
Dùng PycURL proxy cho nhiều request
Dùng lại đối tượng Curl
Tạo đối tượng Curl mới cho mỗi request là đơn giản nhưng tốn. Có thể dùng lại một đối tượng: gọi reset để xóa tùy chọn cũ, đặt lại tùy chọn, rồi perform. libcurl giữ kết nối tới proxy giữa các lần perform trên cùng đối tượng nếu có thể, giảm số lần bắt tay.
Khi dùng lại, nhớ đặt lại PROXY và PROXYUSERPWD sau mỗi reset, vì reset xóa cả chúng. Quên bước này, request sau sẽ đọc proxy từ biến môi trường hoặc đi thẳng.
CurlMulti cho song song
PycURL có CurlMulti để chạy nhiều request song song trong một luồng. Mỗi đối tượng Curl trong multi có tùy chọn proxy riêng, nên có thể chia request ra nhiều proxy. Số request đồng thời nên bằng hoặc thấp hơn hạn mức luồng của gói proxy.
Với CurlMulti, lỗi của từng request đọc qua info_read, không ném ngoại lệ như perform. Mã xử lý lỗi cần đọc errno từ danh sách request lỗi trả về. Mình chưa chạy CurlMulti trong lab, phần này dựa trên tài liệu PycURL.
Đổi proxy theo phiên
Với proxy xoay đổi IP theo tên người dùng, đổi PROXYUSERPWD theo mã phiên của nhà cung cấp. Vì tài khoản đặt trên từng đối tượng Curl, đổi phiên chỉ cần đổi giá trị. Với kết nối đang giữ, libcurl có thể dùng lại kết nối cũ với tài khoản cũ, đặt FORBID_REUSE hoặc tạo đối tượng mới khi bắt buộc phải có IP mới.
Gỡ cấu hình thử PycURL proxy và quản lý bí mật
Không ghi mật khẩu vào mã
Đọc tài khoản proxy từ biến môi trường hoặc kho bí mật, không ghi trong mã. Với PROXYUSERPWD, chuỗi tài khoản nằm trong bộ nhớ của đối tượng Curl, không tự in ra. Tùy chọn VERBOSE in chi tiết trao đổi, có thể gồm tiêu đề Proxy-Authorization mã hóa base64, đừng bật VERBOSE trong log của hệ thống đang chạy.
Khi cần gỡ lỗi bằng VERBOSE, dùng DEBUGFUNCTION để lọc dòng chứa Proxy-Authorization trước khi ghi. Base64 không phải mã hóa, ai đọc được log đều giải ra mật khẩu.
Dọn dẹp sau khi thử
Xóa tệp có tài khoản thử, xóa lịch sử lệnh có chuỗi proxy. Nếu đã dùng tài khoản proxy thật để thử, đổi mật khẩu sau khi xong. Trên CI, đưa tài khoản vào mục secret.
Kiểm IP ra trước khi crawl
Trước một đợt crawl, gọi một dịch vụ trả IP công khai qua đúng cấu hình proxy, so với IP của máy chủ. Nếu trùng, dừng ngay. Ca này bắt được lỗi quên PROXY sau reset, biến môi trường bị xóa hay mật khẩu sai trên URL http mà không có ngoại lệ.
Với PycURL, nhớ rằng nếu mật khẩu sai và URL kiểm IP là http, perform vẫn chạy xong với RESPONSE_CODE 407 và thân rỗng. Ca kiểm IP vì thế phải kiểm cả mã trạng thái lẫn nội dung, không chỉ kiểm có ngoại lệ hay không. Dùng URL https cho ca kiểm IP sẽ gọn hơn, vì lỗi tài khoản sẽ thành ngoại lệ errno 7.
Ghi IP ra vào log mỗi lần chạy, kèm thời gian. Khi website phản ánh truy cập bất thường hay khi cần đối chiếu với hóa đơn của nhà cung cấp proxy, log này là bằng chứng rõ ràng về IP đã dùng.
Chọn loại proxy
PycURL hay dùng trong hệ thống cần tốc độ cao và kiểm soát chi tiết, như crawler lớn hay công cụ kiểm thử mạng. Với crawler nhiều trang, proxy xoay giúp chia tải. Với API cần IP cố định, proxy tĩnh phù hợp. Với cả hai, chọn proxy có cổng HTTP để đọc được HTTP_CONNECTCODE.
ProxyVN có proxy dân cư tĩnh, datacenter và proxy xoay, hỗ trợ HTTP và SOCKS5, cấp tài khoản user và mật khẩu. Nếu cần proxy để chạy hàm run ở trên với tài khoản thật, anh em có thể mua proxy tại trang chủ ProxyVN rồi chạy lại bảng ca thử.
Câu hỏi thường gặp về PycURL proxy
PROXYUSERPWD có cần mã hóa ký tự đặc biệt không. Không. Chỉ khi ghi tài khoản trong URL proxy mới cần mã hóa phần trăm.
Vì sao sai mật khẩu mà không có ngoại lệ. Với URL http, proxy trả 407 như một response bình thường. Kiểm RESPONSE_CODE sau perform.
HTTP_CONNECTCODE dùng để làm gì. Đọc mã proxy trả cho lệnh CONNECT. Bằng 0 khi không có đường hầm, 200 khi thành công, 407 khi bị từ chối.
socks5 hay socks5h. socks5h để proxy phân giải tên miền, tránh rò DNS. socks5 phân giải tại máy.
Đặt HTTP_PROXY chữ hoa trên Linux mà không có tác dụng. libcurl chỉ đọc http_proxy chữ thường. Với https, cả hai bản đều được.
Làm sao một request đi thẳng dù có biến proxy. Đặt PROXY thành chuỗi rỗng.
libcurl có tự thử lại không. Không. Tự viết vòng thử lại cho GET.
Checklist PycURL proxy

Checklist PycURL proxy
Trước khi chạy thật
- Ghi chuỗi pycurl.version vào README.
- Dùng PROXYUSERPWD thay vì tài khoản trong URL.
- Kiểm RESPONSE_CODE 407 với URL http, HTTP_CONNECTCODE với https.
- Dùng socks5h cho SOCKS5.
- Viết http_proxy chữ thường nếu dựa vào biến môi trường.
- Đặt CONNECTTIMEOUT và TIMEOUT.
- Bật FOLLOWLOCATION và MAXREDIRS khi cần theo redirect.
- close hoặc reset đối tượng Curl sau khi dùng.
- Không bật VERBOSE trong log hệ thống đang chạy.
Giới hạn của lab
Lab chạy PycURL 7.49.0, libcurl 8.23.0 trên Windows với proxy tự dựng. Chưa thử proxy HTTPS, chưa thử NTLM hay Digest, chưa chạy CurlMulti, chưa thử trên Linux để thấy khác biệt chữ hoa chữ thường và chưa thử gateway thương mại.
PycURL proxy và những điều cần nhớ
PycURL proxy đặt bằng PROXY và PROXYUSERPWD trên từng đối tượng Curl. libcurl gửi tài khoản ngay, lỗi 407 với http nằm ở RESPONSE_CODE, với https nằm ở errno 7 và HTTP_CONNECTCODE. Dùng socks5h, đặt timeout, tự quản bộ đệm. Cần proxy ổn định cho PycURL proxy, liên hệ Proxy.vn - Nhà cung cấp dịch vụ proxy chất lượng hàng đầu Việt Nam.