Cách khắc phục các vấn đề về cookies thông qua proxy
Cookies là một trong những nguồn gốc lỗi phổ biến nhất khi làm việc với proxy. Các phiên bị ngắt, xác thực bị lỗi, dữ liệu bị mất. Trong bài viết này, chúng tôi sẽ tìm hiểu lý do tại sao điều này xảy ra và cách cấu hình đúng cách xử lý cookies để hoạt động ổn định.
Tại sao cookies bị mất khi sử dụng proxy
Khi bạn gửi yêu cầu thông qua proxy, một nút trung gian sẽ xuất hiện giữa máy khách của bạn và máy chủ đích. Điều này tạo ra một số vấn đề:
- Các địa chỉ IP khác nhau cho một phiên. Máy chủ có thể nhận thấy rằng các yêu cầu đến từ các địa chỉ khác nhau và từ chối cookies như đáng ngờ.
- Mất các tiêu đề Set-Cookie. Cấu hình proxy không chính xác có thể không truyền các tiêu đề Set-Cookie cho máy khách.
- Miền và đường dẫn không khớp. Nếu proxy viết lại tiêu đề Host, cookies có thể không được lưu do miền không khớp.
- Thiếu lưu trữ trạng thái. Nếu bạn gửi từng yêu cầu riêng biệt mà không lưu trữ cookies, phiên sẽ bị mất.
Cookie jar là gì và cách sử dụng nó
Cookie jar là kho lưu trữ cookies tự động quản lý việc gửi và nhận chúng. Thay vì thêm tiêu đề Cookie vào từng yêu cầu theo cách thủ công, bạn cho phép thư viện thực hiện việc này tự động.
Hầu hết các máy khách HTTP đều có hỗ trợ cookie jar tích hợp:
import requests
from requests.cookies import RequestsCookieJar
# Tạo jar để lưu trữ cookies
jar = RequestsCookieJar()
# Yêu cầu đầu tiên — máy chủ sẽ gửi Set-Cookie
response1 = requests.get(
'https://example.com/login',
cookies=jar,
proxies={'https': 'http://proxy.example.com:8080'}
)
# Cookies được lưu trữ tự động trong jar
print(jar)
# Yêu cầu thứ hai — cookies sẽ được gửi tự động
response2 = requests.get(
'https://example.com/dashboard',
cookies=jar,
proxies={'https': 'http://proxy.example.com:8080'}
)
Nếu không có jar, bạn sẽ phải phân tích cú pháp Set-Cookie theo cách thủ công và thêm chúng vào yêu cầu tiếp theo — điều này không đáng tin cậy và cumbersome.
Lưu trữ cookies giữa các yêu cầu
Nếu tập lệnh của bạn chạy trong thời gian dài hoặc bạn cần khôi phục phiên sau khi khởi động lại, hãy lưu cookies vào tệp:
import requests
from http.cookiejar import LWPCookieJar
# Tạo jar với lưu trữ vào tệp
jar = LWPCookieJar('cookies.txt')
# Tải cookies cũ nếu chúng tồn tại
try:
jar.load(ignore_discard=True, ignore_expires=True)
except FileNotFoundError:
pass
# Sử dụng jar trong các yêu cầu
response = requests.get(
'https://example.com/login',
cookies=jar,
proxies={'https': 'http://proxy.example.com:8080'}
)
# Lưu trữ cookies được cập nhật
jar.save(ignore_discard=True, ignore_expires=True)
Các cờ ignore_discard=True và ignore_expires=True cho phép lưu trữ ngay cả các cookies tạm thời.
Các vấn đề với liên kết miền của cookies
Cookies có thuộc tính Domain xác định những miền nào sẽ nhận được chúng. Các vấn đề phát sinh nếu:
- Proxy viết lại Host. Nếu proxy thay đổi tiêu đề Host, cookie jar có thể từ chối cookie vì nó thuộc về miền khác.
- Các miền con không khớp. Cookie cho
example.comcó thể không được gửi đếnapi.example.com. - Đường dẫn không khớp. Cookie cho
/apisẽ không được gửi đến/admin.
Kiểm tra các thuộc tính cookie như sau:
import requests
response = requests.get(
'https://example.com',
proxies={'https': 'http://proxy.example.com:8080'}
)
# Xuất tất cả các cookies
for cookie in response.cookies:
print(f"Name: {cookie.name}")
print(f"Value: {cookie.value}")
print(f"Domain: {cookie.domain}")
print(f"Path: {cookie.path}")
print(f"Secure: {cookie.secure}")
print(f"HttpOnly: {cookie.has_nonstandard_attr('HttpOnly')}")
print("---")
Nếu Domain quá hẹp, hãy thử chỉ định cookies một cách rõ ràng thay vì quản lý tự động:
headers = {
'Cookie': 'session_id=abc123; user_token=xyz789'
}
response = requests.get(
'https://example.com/api',
headers=headers,
proxies={'https': 'http://proxy.example.com:8080'}
)
Các cờ Secure và HttpOnly
Cờ Secure có nghĩa là cookie chỉ được gửi qua HTTPS. Nếu bạn sử dụng proxy HTTP để truy cập tài nguyên HTTPS, hãy đảm bảo rằng kết nối đến proxy được bảo vệ hoặc proxy chuyển tiếp HTTPS một cách chính xác.
Cờ HttpOnly cấm truy cập cookie từ JavaScript. Điều này không ảnh hưởng đến việc gửi cookie trong các yêu cầu, nhưng điều quan trọng cần nhớ là bạn sẽ không thể đọc các cookies như vậy từ trình duyệt.
Khi làm việc với proxy dân cư, hãy đảm bảo rằng:
- Proxy hỗ trợ HTTPS (phương thức CONNECT)
- Chứng chỉ hợp lệ (không sử dụng
verify=Falsetrong production) - Các tiêu đề không được viết lại bởi proxy
Các ví dụ thực tế với mã
Ví dụ 1: Đăng nhập với lưu trữ phiên
import requests
from requests.cookies import RequestsCookieJar
jar = RequestsCookieJar()
proxy = 'http://proxy.example.com:8080'
# Đăng nhập
login_response = requests.post(
'https://example.com/login',
data={'username': 'user', 'password': 'pass'},
cookies=jar,
proxies={'https': proxy}
)
if login_response.status_code == 200:
print("Đăng nhập thành công")
# Sử dụng phiên được lưu trữ
dashboard = requests.get(
'https://example.com/dashboard',
cookies=jar,
proxies={'https': proxy}
)
print(dashboard.text)
Ví dụ 2: Xử lý nhiều yêu cầu
import requests
from http.cookiejar import LWPCookieJar
import time
jar = LWPCookieJar('session.txt')
try:
jar.load(ignore_discard=True)
except:
pass
proxy = 'http://proxy.example.com:8080'
urls = [
'https://example.com/page1',
'https://example.com/page2',
'https://example.com/page3'
]
for url in urls:
response = requests.get(
url,
cookies=jar,
proxies={'https': proxy},
timeout=10
)
print(f"{url}: {response.status_code}")
jar.save(ignore_discard=True)
time.sleep(1) # Không quá tải máy chủ
Ví dụ 3: Truyền cookies một cách rõ ràng khi có vấn đề
import requests
proxy = 'http://proxy.example.com:8080'
# Nếu quản lý tự động không hoạt động
cookies_dict = {
'session_id': 'abc123def456',
'user_pref': 'dark_mode'
}
headers = {
'User-Agent': 'Mozilla/5.0...',
'Cookie': '; '.join([f"{k}={v}" for k, v in cookies_dict.items()])
}
response = requests.get(
'https://example.com/api/data',
headers=headers,
proxies={'https': proxy}
)
print(response.json())
Gỡ lỗi các vấn đề về cookies
Nếu cookies không hoạt động, hãy sử dụng các công cụ này:
| Công cụ | Mục đích |
|---|---|
requests.Session |
Tự động quản lý cookies cho tất cả các yêu cầu trong phiên |
logging |
Bật DEBUG cho requests để xem tất cả các tiêu đề |
Fiddler / Charles |
Chặn lưu lượng và xem các tiêu đề Set-Cookie và Cookie |
curl -v |
Kiểm tra điều tương tự thông qua proxy từ dòng lệnh |
Bật ghi nhật ký để gỡ lỗi:
import logging
import requests
logging.basicConfig(level=logging.DEBUG)
# Bây giờ tất cả các yêu cầu sẽ xuất ra các tiêu đề và cookies
response = requests.get(
'https://example.com',
proxies={'https': 'http://proxy.example.com:8080'}
)
Kiểm tra xem proxy có chặn cookies không:
curl -v -x http://proxy.example.com:8080 https://example.com
# Xem các tiêu đề:
# Set-Cookie: ... (nên có)
# Cookie: ... (nên được gửi trong yêu cầu tiếp theo)
Mẹo: Nếu sử dụng proxy dân cư, hãy nhớ rằng chúng có thể xoay vòng IP giữa các yêu cầu. Hãy đảm bảo rằng logic xử lý cookies của bạn tính đến điều này — một số máy chủ từ chối các yêu cầu từ các IP khác nhau trong cùng một phiên.
Tóm tắt
Các vấn đề về cookies khi làm việc thông qua proxy được giải quyết bằng cách cấu hình đúng:
- Sử dụng cookie jar để quản lý cookies tự động
- Lưu trữ cookies giữa các yêu cầu vào tệp
- Kiểm tra liên kết miền và các thuộc tính Path
- Đảm bảo hỗ trợ HTTPS của proxy
- Sử dụng gỡ lỗi để xác định các vấn đề
Đối với các tác vụ tự động hóa và phân tích cú pháp, nơi cần hoạt động đáng tin cậy với các phiên thông qua proxy, proxy dân cư với hỗ trợ HTTPS và quản lý cookies là phù hợp. Bắt đầu với cookie jar đơn giản và chuyển sang các lược đồ phức tạp hơn chỉ khi cần thiết.