Việc thu thập dữ liệu y tế là một nhiệm vụ đòi hỏi cách tiếp cận đặc biệt trong việc chọn proxy. Các cổng thông tin y tế, cơ sở dữ liệu nghiên cứu lâm sàng và các nguồn tài nguyên dược phẩm sử dụng các hệ thống bảo vệ tiên tiến chống lại việc thu thập dữ liệu tự động. Trong bài viết này, chúng ta sẽ xem xét cách cấu hình proxy một cách chính xác để thu thập thông tin y tế một cách an toàn, tránh bị chặn và thu thập dữ liệu hiệu quả.
Tại sao các trang web y tế chặn việc thu thập dữ liệu
Các cổng thông tin y tế và cơ sở dữ liệu đặc biệt nhạy cảm với việc thu thập thông tin tự động vì một số lý do. Thứ nhất, nhiều trong số đó hoạt động trên cơ sở thương mại và bán quyền truy cập vào dữ liệu thông qua các đăng ký trả phí. Việc thu thập tự động có thể vi phạm các điều khoản sử dụng và thỏa thuận cấp phép.
Thứ hai, dữ liệu y tế thường chứa thông tin nhạy cảm, được bảo vệ bởi luật pháp (HIPAA ở Mỹ, GDPR ở châu Âu). Các chủ sở hữu tài nguyên có nghĩa vụ kiểm soát quyền truy cập vào những dữ liệu này và ngăn chặn việc phát tán không được phép. Do đó, họ sử dụng các hệ thống bảo vệ tiên tiến:
- Giới hạn tốc độ — giới hạn số lượng yêu cầu từ một địa chỉ IP trong một khoảng thời gian nhất định (thường là 10-50 yêu cầu mỗi phút)
- Phân tích dấu vân tay — phân tích các đặc điểm của trình duyệt, tiêu đề HTTP, thứ tự tải tài nguyên
- CAPTCHA — các hệ thống như reCAPTCHA v3, kích hoạt khi có hoạt động nghi ngờ
- Khóa IP — khóa tạm thời hoặc vĩnh viễn các địa chỉ IP của trung tâm dữ liệu
- Cloudflare và các dịch vụ tương tự — bảo vệ chống lại bot ở cấp độ CDN
Lý do thứ ba là tải trên các máy chủ. Các cơ sở dữ liệu y tế thường chứa hàng triệu bản ghi, và việc thu thập hàng loạt có thể tạo ra tải trọng đáng kể lên cơ sở hạ tầng. Do đó, các quản trị viên tích cực chống lại việc thu thập dữ liệu tự động, theo dõi các mẫu hành vi đặc trưng cho bot: khoảng thời gian giống nhau giữa các yêu cầu, duyệt trang theo thứ tự tuyến tính, không có JavaScript và cookies.
Quan trọng: Trước khi bắt đầu thu thập dữ liệu y tế, hãy chắc chắn nghiên cứu các điều khoản sử dụng của trang web và luật pháp hiện hành. Một số dữ liệu có thể được bảo vệ bởi bản quyền hoặc chứa thông tin cá nhân của bệnh nhân. Hãy đảm bảo rằng hoạt động của bạn là hợp pháp và không vi phạm quyền của bên thứ ba.
Loại proxy nào nên chọn cho dữ liệu y tế
Việc chọn loại proxy là rất quan trọng cho việc thu thập dữ liệu y tế thành công. Các nguồn khác nhau yêu cầu cách tiếp cận khác nhau. Hãy xem xét các loại proxy chính và tính khả dụng của chúng:
| Loại proxy | Ưu điểm | Nhược điểm | Khi nào sử dụng |
|---|---|---|---|
| Proxy trung tâm dữ liệu | Tốc độ cao (100+ Mbit/s), chi phí thấp, kết nối ổn định | Dễ bị phát hiện, thường bị chặn trên các trang web bảo mật | Cơ sở dữ liệu mở không có bảo vệ nghiêm ngặt (PubMed, WHO) |
| Proxy cư trú | IP thực tế của người dùng tại nhà, rủi ro bị chặn thấp, vượt qua Cloudflare | Chi phí cao hơn, tốc độ biến đổi, có thể không ổn định | Cơ sở dữ liệu thương mại bảo mật (Elsevier, Springer), trang web có Cloudflare |
| Proxy di động | Tin cậy tối đa (IP của nhà mạng), hầu như không bị chặn | Đắt nhất, địa lý hạn chế, có thể chậm hơn | Tài nguyên bảo mật đặc biệt, khi proxy cư trú không giúp được |
| Proxy ISP | Tốc độ của trung tâm dữ liệu + độ tin cậy của cư trú, IP tĩnh | Chi phí trung bình, tính khả dụng hạn chế | Thu thập dữ liệu lâu dài từ một IP, khi cần độ ổn định |
Đối với hầu hết các nhiệm vụ thu thập dữ liệu y tế, nên sử dụng proxy cư trú. Chúng cung cấp sự cân bằng tối ưu giữa chi phí và hiệu quả. Proxy trung tâm dữ liệu chỉ phù hợp cho các nguồn mở không có bảo vệ. Proxy di động nên được sử dụng trong các trường hợp cực đoan, khi các loại khác không hoạt động.
Khuyến nghị cho việc chọn cho các nguồn cụ thể
- PubMed, PubMed Central — proxy trung tâm dữ liệu là đủ, nhưng với giới hạn tốc độ tối đa 3 yêu cầu mỗi giây
- ClinicalTrials.gov — proxy trung tâm dữ liệu, có API chính thức
- Elsevier, Springer, Wiley — proxy cư trú là bắt buộc, sử dụng phân tích dấu vân tay tiên tiến
- DrugBank, RxList — proxy cư trú, bảo vệ tích cực chống lại việc thu thập dữ liệu
- Cơ sở dữ liệu FDA, EMA — proxy trung tâm dữ liệu phù hợp, nhưng với tốc độ thu thập dữ liệu chậm
Các nguồn dữ liệu y tế chính và cách bảo vệ của chúng
Dữ liệu y tế được phân phối qua nhiều nguồn, mỗi nguồn có đặc điểm và mức độ bảo vệ riêng. Hiểu những đặc điểm này sẽ giúp bạn cấu hình chiến lược thu thập dữ liệu một cách chính xác.
Cơ sở dữ liệu nhà nước mở
PubMed/PubMed Central — cơ sở dữ liệu lớn nhất về các ấn phẩm y tế, chứa hơn 35 triệu bản ghi. Thư viện y tế quốc gia Mỹ (NLM) cung cấp API E-utilities chính thức, đây là cách truy cập dữ liệu được ưu tiên. Việc thu thập trực tiếp từ giao diện web là khả thi, nhưng bị giới hạn ở 3 yêu cầu mỗi giây từ một IP. Việc vượt quá giới hạn này sẽ dẫn đến việc bị chặn tạm thời trong 24 giờ.
ClinicalTrials.gov — cơ sở dữ liệu về các nghiên cứu lâm sàng, chứa thông tin về hơn 400,000 nghiên cứu ở 220 quốc gia. Cũng cung cấp API cho truy cập lập trình. Giao diện web được bảo vệ bằng giới hạn tốc độ — tối đa 100 yêu cầu trong 5 phút từ một IP. Sử dụng bảo vệ cơ bản chống lại bot, nhưng không có Cloudflare.
Cơ sở dữ liệu thuốc FDA — cơ sở dữ liệu về các loại thuốc được FDA phê duyệt. Truy cập mở thông qua giao diện web và API openFDA. Giới hạn: 240 yêu cầu mỗi phút cho người dùng ẩn danh, 1000 yêu cầu mỗi phút với khóa API. Việc bị chặn là hiếm, nhưng có thể xảy ra khi thu thập dữ liệu một cách tích cực.
Các nhà xuất bản khoa học thương mại
Elsevier (ScienceDirect) — một trong những nhà xuất bản lớn nhất về tài liệu khoa học. Sử dụng bảo vệ đa cấp: Cloudflare, phân tích dấu vân tay của trình duyệt, phân tích hành vi người dùng. Phát hiện các mẫu tải xuống tự động: truy cập tuần tự vào các bài báo, không có JavaScript, User-Agent không điển hình. Khi phát hiện việc thu thập dữ liệu, sẽ chặn IP ở cấp độ tài khoản và có thể chặn toàn bộ viện. Bắt buộc phải sử dụng proxy cư trú với việc xoay vòng và mô phỏng hoàn toàn trình duyệt.
Springer Nature — bảo vệ tương tự, thêm vào đó theo dõi tốc độ cuộn trang và chuyển động chuột. Sử dụng machine learning để phát hiện bot. Khuyến nghị không thu thập quá 10-15 bài báo mỗi giờ từ một IP, với các độ trễ ngẫu nhiên giữa các yêu cầu.
Wiley Online Library — bảo vệ ít nghiêm ngặt hơn, nhưng vẫn yêu cầu sử dụng proxy. Cho phép khoảng 50 yêu cầu mỗi giờ từ một IP mà không bị chặn. Sử dụng session cookies để theo dõi hoạt động.
Các cơ sở dữ liệu dược phẩm
DrugBank — cơ sở dữ liệu toàn diện về các loại thuốc. Phiên bản miễn phí bị giới hạn bởi giao diện web, phiên bản thương mại cung cấp API và xuất dữ liệu. Phiên bản web được bảo vệ bởi Cloudflare và giới hạn tốc độ — tối đa 20 yêu cầu mỗi phút. Phát hiện tự động hóa qua việc thiếu cookies và JavaScript.
RxList, Drugs.com — các hướng dẫn thuốc phổ biến cho người tiêu dùng. Sử dụng Cloudflare và tích cực chống lại việc thu thập dữ liệu. Chặn IP của trung tâm dữ liệu gần như ngay lập tức. Cần proxy cư trú và tốc độ thu thập dữ liệu chậm (5-10 trang mỗi phút).
Cấu hình xoay vòng IP cho việc thu thập dữ liệu lâu dài
Việc xoay vòng địa chỉ IP đúng cách là yếu tố chính cho việc thu thập dữ liệu y tế thành công. Có hai cách tiếp cận chính: xoay vòng theo yêu cầu và xoay vòng theo thời gian.
Xoay vòng theo yêu cầu
Với cách tiếp cận này, mỗi yêu cầu được gửi qua một địa chỉ IP mới. Điều này giảm thiểu tối đa rủi ro bị chặn, nhưng có thể gây ra vấn đề với các trang web theo dõi phiên thông qua cookies. Phù hợp cho việc thu thập danh sách và thư mục, nơi không yêu cầu duy trì trạng thái phiên.
Hầu hết các nhà cung cấp proxy cư trú cung cấp việc xoay vòng tự động thông qua một endpoint đặc biệt. Ví dụ, khi sử dụng rotating proxy endpoint, mỗi kết nối TCP mới sẽ nhận được một IP mới. Điều này hoạt động tự động với các thư viện như requests trong Python, vì theo mặc định, một kết nối mới được tạo ra cho mỗi yêu cầu.
Xoay vòng theo thời gian (sticky sessions)
Sticky sessions cho phép sử dụng một địa chỉ IP trong một khoảng thời gian nhất định (thường là 5-30 phút), sau đó sẽ tự động thay đổi. Điều này hữu ích cho các trang web yêu cầu xác thực hoặc theo dõi trạng thái phiên thông qua cookies. Bạn có thể thu thập một số trang từ một IP, mô phỏng hành vi của người dùng thực, sau đó IP sẽ tự động thay đổi.
Đối với các trang web y tế, nên sử dụng sticky sessions kéo dài 10-15 phút. Trong khoảng thời gian này, bạn có thể thu thập 10-20 trang (tùy thuộc vào độ trễ), sau đó IP sẽ thay đổi và bạn bắt đầu "một phiên mới". Điều này trông tự nhiên và giảm rủi ro phát hiện.
Kích thước của pool địa chỉ IP
Đối với việc thu thập dữ liệu lâu dài, kích thước của pool địa chỉ IP có sẵn là rất quan trọng. Nếu bạn sử dụng cùng một tập hợp 100 IP trong suốt một tuần, trang web có thể nhận thấy mẫu và chặn tất cả các địa chỉ này. Proxy cư trú thường cung cấp quyền truy cập vào hàng triệu IP, điều này gần như loại trừ việc sử dụng lại cùng một địa chỉ.
Khi sử dụng proxy trung tâm dữ liệu, nên có ít nhất 500-1000 IP cho việc thu thập dữ liệu ở mức trung bình (10,000-50,000 trang mỗi tháng). Đối với việc thu thập dữ liệu quy mô lớn (hàng trăm nghìn trang), tốt hơn nên sử dụng proxy cư trú với các pool IP khổng lồ của chúng.
Lời khuyên về việc xoay vòng cho các nguồn khác nhau:
- PubMed — xoay vòng không bắt buộc, chỉ cần 1 IP với việc tuân thủ giới hạn tốc độ
- Các nhà xuất bản thương mại — sticky sessions 10-15 phút, IP mới mỗi 15-20 trang
- Các cơ sở dữ liệu dược phẩm — xoay vòng cho mỗi yêu cầu hoặc sticky sessions 5 phút
- Trang web có Cloudflare — sticky sessions là bắt buộc, xoay vòng theo yêu cầu không hoạt động
Ví dụ mã Python cho việc thu thập dữ liệu với proxy
Hãy xem xét các ví dụ thực tế về việc cấu hình proxy cho việc thu thập dữ liệu y tế bằng cách sử dụng các thư viện Python phổ biến. Bắt đầu với ví dụ cơ bản và dần dần phức tạp hơn.
Cấu hình cơ bản với thư viện requests
import requests
from time import sleep
import random
# Cấu hình proxy (thay thế bằng thông tin của bạn)
PROXY_HOST = "proxy.example.com"
PROXY_PORT = "8080"
PROXY_USER = "username"
PROXY_PASS = "password"
proxies = {
'http': f'http://{PROXY_USER}:{PROXY_PASS}@{PROXY_HOST}:{PROXY_PORT}',
'https': f'http://{PROXY_USER}:{PROXY_PASS}@{PROXY_HOST}:{PROXY_PORT}'
}
# Tiêu đề để mô phỏng trình duyệt thực
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
'Accept-Language': 'en-US,en;q=0.9',
'Accept-Encoding': 'gzip, deflate, br',
'DNT': '1',
'Connection': 'keep-alive',
'Upgrade-Insecure-Requests': '1'
}
# Ví dụ yêu cầu đến PubMed
url = "https://pubmed.ncbi.nlm.nih.gov/?term=diabetes"
try:
response = requests.get(url, proxies=proxies, headers=headers, timeout=30)
print(f"Mã trạng thái: {response.status_code}")
print(f"Chiều dài nội dung: {len(response.content)}")
# Thêm độ trễ giữa các yêu cầu (bắt buộc cho PubMed)
sleep(random.uniform(1.0, 3.0))
except requests.exceptions.RequestException as e:
print(f"Lỗi: {e}")
Cấu hình nâng cao với xoay vòng và logic thử lại
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
from time import sleep
import random
class ProxyRotator:
def __init__(self, proxy_list):
"""
proxy_list: danh sách từ điển với proxy
[{'http': 'http://user:pass@host:port', 'https': '...'}, ...]
"""
self.proxy_list = proxy_list
self.current_index = 0
def get_next_proxy(self):
"""Lấy proxy tiếp theo từ danh sách"""
proxy = self.proxy_list[self.current_index]
self.current_index = (self.current_index + 1) % len(self.proxy_list)
return proxy
def create_session_with_retries():
"""Tạo phiên với các lần thử tự động khi có lỗi"""
session = requests.Session()
# Cấu hình các lần thử tự động
retry_strategy = Retry(
total=3, # tối đa 3 lần thử
backoff_factor=1, # độ trễ giữa các lần thử: 1, 2, 4 giây
status_forcelist=[429, 500, 502, 503, 504], # mã cho việc thử lại
allowed_methods=["GET", "POST"]
)
adapter = HTTPAdapter(max_retries=retry_strategy)
session.mount("http://", adapter)
session.mount("https://", adapter)
return session
def scrape_with_rotation(urls, proxy_rotator):
"""Thu thập dữ liệu từ danh sách URL với việc xoay vòng proxy"""
session = create_session_with_retries()
results = []
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': 'en-US,en;q=0.9',
}
for url in urls:
# Lấy proxy mới cho mỗi yêu cầu
proxy = proxy_rotator.get_next_proxy()
try:
response = session.get(
url,
proxies=proxy,
headers=headers,
timeout=30
)
if response.status_code == 200:
results.append({
'url': url,
'status': 'thành công',
'content_length': len(response.content)
})
print(f"✓ Thành công: {url}")
else:
results.append({
'url': url,
'status': 'thất bại',
'error': f"Mã trạng thái: {response.status_code}"
})
print(f"✗ Thất bại: {url} (Mã: {response.status_code})")
except requests.exceptions.RequestException as e:
results.append({
'url': url,
'status': 'lỗi',
'error': str(e)
})
print(f"✗ Lỗi: {url} ({e})")
# Độ trễ ngẫu nhiên giữa các yêu cầu (quan trọng!)
sleep(random.uniform(2.0, 5.0))
return results
# Ví dụ sử dụng
proxy_list = [
{
'http': 'http://user1:pass1@proxy1.example.com:8080',
'https': 'http://user1:pass1@proxy1.example.com:8080'
},
{
'http': 'http://user2:pass2@proxy2.example.com:8080',
'https': 'http://user2:pass2@proxy2.example.com:8080'
}
]
rotator = ProxyRotator(proxy_list)
urls_to_scrape = [
"https://pubmed.ncbi.nlm.nih.gov/?term=diabetes",
"https://pubmed.ncbi.nlm.nih.gov/?term=cancer",
"https://pubmed.ncbi.nlm.nih.gov/?term=covid"
]
results = scrape_with_rotation(urls_to_scrape, rotator)
Sử dụng Selenium cho các trang web có JavaScript
Nhiều trang web y tế hiện đại sử dụng JavaScript để tải nội dung. Trong những trường hợp như vậy, cần một trình duyệt headless:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time
def create_proxy_driver(proxy_host, proxy_port, proxy_user, proxy_pass):
"""Tạo Chrome WebDriver với proxy"""
chrome_options = Options()
# Chế độ Headless (không GUI)
chrome_options.add_argument('--headless')
chrome_options.add_argument('--no-sandbox')
chrome_options.add_argument('--disable-dev-shm-usage')
# Cấu hình proxy
chrome_options.add_argument(f'--proxy-server=http://{proxy_host}:{proxy_port}')
# Tắt tự động hóa (quan trọng để vượt qua phát hiện)
chrome_options.add_experimental_option("excludeSwitches", ["enable-automation"])
chrome_options.add_experimental_option('useAutomationExtension', False)
# User-Agent
chrome_options.add_argument('--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36')
driver = webdriver.Chrome(options=chrome_options)
# Đối với proxy có xác thực, cần sử dụng tiện ích mở rộng
# hoặc cấu hình qua capabilities (phương pháp phức tạp hơn)
return driver
def scrape_with_selenium(url, driver):
"""Thu thập dữ liệu từ trang với việc chờ tải JavaScript"""
driver.get(url)
# Chờ tải phần tử (ví dụ, kết quả tìm kiếm)
try:
wait = WebDriverWait(driver, 10)
results = wait.until(
EC.presence_of_element_located((By.CLASS_NAME, "results-article"))
)
# Trích xuất dữ liệu
articles = driver.find_elements(By.CLASS_NAME, "results-article")
data = []
for article in articles:
try:
title = article.find_element(By.CLASS_NAME, "docsum-title").text
authors = article.find_element(By.CLASS_NAME, "docsum-authors").text
data.append({
'title': title,
'authors': authors
})
except:
continue
return data
except Exception as e:
print(f"Lỗi khi chờ các phần tử: {e}")
return []
# Ví dụ sử dụng
proxy_host = "proxy.example.com"
proxy_port = "8080"
proxy_user = "username"
proxy_pass = "password"
driver = create_proxy_driver(proxy_host, proxy_port, proxy_user, proxy_pass)
try:
url = "https://pubmed.ncbi.nlm.nih.gov/?term=diabetes"
results = scrape_with_selenium(url, driver)
for result in results:
print(f"Tiêu đề: {result['title']}")
print(f"Tác giả: {result['authors']}\n")
finally:
driver.quit()
Kiểm soát tốc độ yêu cầu và vượt qua giới hạn tốc độ
Giới hạn tốc độ là một trong những biện pháp bảo vệ chính của các trang web y tế chống lại việc thu thập dữ liệu. Cấu hình tốc độ yêu cầu đúng cách là rất quan trọng cho việc thu thập dữ liệu lâu dài mà không bị chặn.
Xác định tốc độ an toàn
Bước đầu tiên là xác định giới hạn của trang web cụ thể. Điều này có thể được thực hiện một cách thử nghiệm, từ từ tăng tốc độ yêu cầu cho đến khi xuất hiện lỗi 429 (Quá nhiều yêu cầu) hoặc bị chặn. Đối với hầu hết các trang web y tế, các giá trị an toàn là:
- PubMed — tối đa 3 yêu cầu mỗi giây (khuyến nghị chính thức)
- ClinicalTrials.gov — 20 yêu cầu mỗi phút là an toàn, tối đa 100 trong 5 phút là chấp nhận được
- Các nhà xuất bản thương mại — 10-15 yêu cầu mỗi giờ từ một IP
- Các cơ sở dữ liệu dược phẩm — 5-10 yêu cầu mỗi phút
Triển khai giới hạn tốc độ trên Python
import time
from collections import deque
class RateLimiter:
def __init__(self, max_calls, period):
"""
max_calls: số lượng gọi tối đa
period: khoảng thời gian trong giây
Ví dụ: RateLimiter(3, 1) = 3 yêu cầu mỗi giây
"""
self.max_calls = max_calls
self.period = period
self.calls = deque()
def __call__(self, func):
"""Decorator để giới hạn tốc độ gọi hàm"""
def wrapper(*args, **kwargs):
now = time.time()
# Xóa các cuộc gọi cũ vượt quá khoảng thời gian
while self.calls and self.calls[0] < now - self.period:
self.calls.popleft()
# Nếu đã đạt giới hạn, chờ
if len(self.calls) >= self.max_calls:
sleep_time = self.period - (now - self.calls[0])
if sleep_time > 0:
print(f"Đã đạt giới hạn tốc độ, đang chờ {sleep_time:.2f}s")
time.sleep(sleep_time)
# Xóa sau khi chờ
self.calls.clear()
# Ghi lại thời gian gọi
self.calls.append(time.time())
# Thực hiện hàm
return func(*args, **kwargs)
return wrapper
# Ví dụ sử dụng
@RateLimiter(max_calls=3, period=1) # 3 yêu cầu mỗi giây
def fetch_pubmed_page(url):
response = requests.get(url, headers=headers, proxies=proxies)
return response
# Bây giờ hàm tự động tuân thủ giới hạn tốc độ
for i in range(10):
result = fetch_pubmed_page(f"https://pubmed.ncbi.nlm.nih.gov/?term=test&page={i}")
print(f"Trang {i} đã được lấy")
Giới hạn tốc độ thích ứng
Một cách tiếp cận tiên tiến hơn là thay đổi tốc độ một cách thích ứng dựa trên phản hồi của máy chủ. Nếu nhận được lỗi 429 hoặc 503, tự động giảm tốc độ:
import time
import random
class AdaptiveRateLimiter:
def __init__(self, initial_delay=1.0, max_delay=60.0):
self.current_delay = initial_delay
self.initial_delay = initial_delay
self.max_delay = max_delay
self.success_count = 0
def wait(self):
"""Chờ trước yêu cầu tiếp theo"""
# Thêm ngẫu nhiên để tự nhiên hơn
actual_delay = self.current_delay * random.uniform(0.8, 1.2)
time.sleep(actual_delay)
def on_success(self):
"""Gọi khi yêu cầu thành công"""
self.success_count += 1
# Sau 10 yêu cầu thành công, tăng tốc độ một chút
if self.success_count >= 10:
self.current_delay = max(
self.initial_delay,
self.current_delay * 0.9
)
self.success_count = 0
def on_rate_limit(self):
"""Gọi khi nhận được lỗi 429 hoặc lỗi tương tự"""
# Nhân đôi độ trễ, nhưng không vượt quá mức tối đa
self.current_delay = min(
self.current_delay * 2,
self.max_delay
)
self.success_count = 0
print(f"Đã đạt giới hạn tốc độ! Tăng độ trễ lên {self.current_delay:.2f}s")
def on_error(self):
"""Gọi khi có lỗi khác"""
# Tăng độ trễ một chút
self.current_delay = min(
self.current_delay * 1.5,
self.max_delay
)
self.success_count = 0
# Ví dụ sử dụng
limiter = AdaptiveRateLimiter(initial_delay=2.0, max_delay=30.0)
for url in urls_to_scrape:
limiter.wait()
try:
response = requests.get(url, proxies=proxies, headers=headers)
if response.status_code == 200:
limiter.on_success()
# Xử lý dữ liệu
elif response.status_code == 429:
limiter.on_rate_limit()
# Thử lại sau
else:
limiter.on_error()
except requests.exceptions.RequestException:
limiter.on_error()
Tiêu đề và User-Agent đúng cho các trang web y tế
Các trang web y tế phân tích các tiêu đề HTTP để phát hiện bot. Các tiêu đề không đúng hoặc thiếu là nguyên nhân phổ biến gây ra việc bị chặn ngay cả khi sử dụng proxy chất lượng.
Các tiêu đề bắt buộc
Tập hợp các tiêu đề tối thiểu mà mỗi yêu cầu phải có:
headers = {
# User-Agent — bắt buộc là trình duyệt hiện tại
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
# Accept — các loại nội dung mà trình duyệt chấp nhận
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8',
# Accept-Language — ngôn ngữ của người dùng
'Accept-Language': 'en-US,en;q=0.9',
# Accept-Encoding — hỗ trợ nén
'Accept-Encoding': 'gzip, deflate, br',
# Connection — duy trì kết nối
'Connection': 'keep-alive',
# Upgrade-Insecure-Requests — tự động chuyển sang HTTPS
'Upgrade-Insecure-Requests': '1',
# DNT — Do Not Track (tùy chọn, nhưng thêm tính thực tế)
'DNT': '1',
# Tiêu đề Sec-Fetch-* (quan trọng cho các trình duyệt hiện đại)
'Sec-Fetch-Dest': 'document',
'Sec-Fetch-Mode': 'navigate',
'Sec-Fetch-Site': 'none',
'Sec-Fetch-User': '?1',
# Cache-Control
'Cache-Control': 'max-age=0'
}
Xoay vòng User-Agent
Việc sử dụng cùng một User-Agent có thể gây nghi ngờ. Khuyến nghị xoay vòng giữa nhiều trình duyệt hiện tại:
import random
USER_AGENTS = [
# Chrome trên Windows
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
# Chrome trên Mac
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
# Firefox trên Windows
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:121.0) Gecko/20100101 Firefox/121.0',
# Firefox trên Mac
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:121.0) Gecko/20100101 Firefox/121.0',
# Safari trên Mac
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.1 Safari/605.1.15',
# Edge trên Windows
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0'
]
def get_random_headers():
"""Lấy tiêu đề với User-Agent ngẫu nhiên"""
return {
'User-Agent': random.choice(USER_AGENTS),
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': 'en-US,en;q=0.9',
'Accept-Encoding': 'gzip, deflate, br',
'Connection': 'keep-alive',
'Upgrade-Insecure-Requests': '1',
'DNT': '1'
}
# Sử dụng
for url in urls:
headers = get_random_headers()
response = requests.get(url, headers=headers, proxies=proxies)
Referer và Origin cho các biểu mẫu
Khi làm việc với các biểu mẫu tìm kiếm hoặc gửi các yêu cầu POST, hãy chắc chắn thêm các tiêu đề Referer và Origin:
# Đối với các yêu cầu POST đến biểu mẫu tìm kiếm
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': 'en-US,en;q=0.9',
'Accept-Encoding': 'gzip, deflate, br',
'Content-Type': 'application/x-www-form-urlencoded',
'Origin': 'https://example.com',
'Referer': 'https://example.com/search',
'Connection': 'keep-alive'
}
# Yêu cầu POST với dữ liệu biểu mẫu
data = {
'query': 'diabetes',
'page': '1'
}
response = requests.post(
'https://example.com/search',
headers=headers,
data=data,
proxies=proxies
)
Các vấn đề thường gặp và cách giải quyết
Khi thu thập dữ liệu y tế, có những vấn đề cụ thể phát sinh. Hãy xem xét các vấn đề thường gặp nhất và cách giải quyết chúng.
Vấn đề: Cloudflare chặn tất cả các yêu cầu
Triệu chứng: Nhận được trang với văn bản "Đang kiểm tra trình duyệt của bạn" hoặc lỗi 403 Forbidden với đề cập đến Cloudflare.
Giải pháp:
- Sử dụng proxy cư trú thay vì trung tâm dữ liệu — Cloudflare chặn IP của trung tâm dữ liệu theo mặc định
- Chuyển sang Selenium hoặc Puppeteer — trình duyệt headless vượt qua kiểm tra Cloudflare tốt hơn
- Sử dụng thư viện cloudscraper cho Python — nó tự động vượt qua bảo vệ cơ bản của Cloudflare
- Bật cookies và JavaScript — Cloudflare kiểm tra sự hiện diện của chúng
- Thêm phân tích dấu vân tay TLS — sử dụng curl_cffi để mô phỏng trình duyệt thực ở cấp độ TLS
Vấn đề: Nhận được lỗi 429 Quá nhiều yêu cầu
Triệu chứng: Sau một vài yêu cầu thành công, máy chủ bắt đầu trả về 429.
Giải pháp:
- Tăng độ trễ giữa các yêu cầu — thử bắt đầu với 3-5 giây
- Bật xoay vòng IP — mỗi yêu cầu qua một IP mới sẽ loại bỏ giới hạn tốc độ
- Kiểm tra tiêu đề Retry-After trong phản hồi 429 — nó chỉ ra số giây cần chờ
- Sử dụng độ trễ theo cấp số nhân khi thử lại — 1s, 2s, 4s, 8s, v.v.
Vấn đề: Proxy hoạt động chậm hoặc thường bị ngắt kết nối
Triệu chứng: Lỗi timeout, tải trang rất lâu, ngắt kết nối.
Giải pháp:
- Tăng timeout trong các yêu cầu lên 30-60 giây — proxy cư trú có thể chậm hơn
- Sử dụng proxy gần về mặt địa lý — nếu thu thập dữ liệu từ trang web châu Âu, hãy sử dụng IP châu Âu
- Kiểm tra chất lượng của nhà cung cấp proxy — proxy giá rẻ thường không ổn định
- Thêm logic thử lại — tự động thử lại yêu cầu khi có lỗi kết nối
- Sử dụng connection pooling — tái sử dụng các kết nối TCP thông qua requests.Session()
Vấn đề: Trang web yêu cầu xác thực hoặc đăng ký
Triệu chứng: Truy cập vào các văn bản đầy đủ của bài báo bị hạn chế, yêu cầu đăng nhập.
Giải pháp:
- Sử dụng quyền truy cập từ tổ chức — nhiều trường đại học và bệnh viện có đăng ký
- Kiểm tra sự tồn tại của các phiên bản Open Access — nhiều bài báo có sẵn miễn phí qua các kho lưu trữ
- Sử dụng API thay vì thu thập dữ liệu — một số nhà xuất bản cung cấp API cho các nhà nghiên cứu
- Chỉ thu thập siêu dữ liệu (tiêu đề, tác giả, tóm tắt) — chúng thường có sẵn miễn phí
Vấn đề: Nội dung JavaScript không tải
Triệu chứng: Trong HTML không có dữ liệu cần thiết, chỉ thấy các spinner tải hoặc các container trống.
Giải pháp:
- Chuyển sang Selenium/Puppeteer — chúng thực thi JavaScript
- Tìm endpoint API — mở DevTools trong trình duyệt, tab Network, và tìm các yêu cầu XHR với dữ liệu
- Sử dụng requests-html — thư viện với khả năng thực thi JavaScript