Parsing data medis adalah tugas yang memerlukan pendekatan khusus dalam memilih proksi. Portal medis, basis data penelitian klinis, dan sumber daya farmasi menggunakan sistem perlindungan canggih terhadap pengumpulan data otomatis. Dalam artikel ini, kita akan membahas cara mengatur proksi dengan benar untuk parsing informasi medis dengan aman, menghindari pemblokiran, dan mengumpulkan data yang diperlukan secara efisien.
Mengapa Situs Medis Memblokir Parsing
Portal medis dan basis data sangat sensitif terhadap pengumpulan informasi otomatis karena beberapa alasan. Pertama, banyak dari mereka beroperasi secara komersial dan menjual akses ke data melalui langganan berbayar. Parsing otomatis dapat melanggar syarat penggunaan dan perjanjian lisensi.
Kedua, data medis sering kali mengandung informasi rahasia yang dilindungi oleh hukum (HIPAA di AS, GDPR di Eropa). Pemilik sumber daya wajib mengontrol akses ke data tersebut dan mencegah penyebaran yang tidak sah. Oleh karena itu, mereka menggunakan sistem perlindungan canggih:
- Rate limiting — pembatasan jumlah permintaan dari satu alamat IP dalam satu waktu (biasanya 10-50 permintaan per menit)
- Fingerprinting — analisis karakteristik browser, header HTTP, urutan pemuatan sumber daya
- CAPTCHA — sistem seperti reCAPTCHA v3 yang diaktifkan saat aktivitas mencurigakan terdeteksi
- IP-blocking — pemblokiran sementara atau permanen alamat IP dari pusat data
- Cloudflare dan sejenisnya — perlindungan terhadap bot di tingkat CDN
Alasan ketiga adalah beban pada server. Basis data medis sering kali berisi jutaan catatan, dan parsing massal dapat menciptakan beban yang signifikan pada infrastruktur. Oleh karena itu, administrator secara aktif melawan pengumpulan data otomatis dengan melacak pola perilaku yang khas untuk bot: interval yang sama antara permintaan, penelusuran halaman secara linier, dan tidak adanya JavaScript dan cookies.
Penting: Sebelum memulai parsing data medis, pastikan untuk mempelajari syarat penggunaan situs dan hukum yang berlaku. Beberapa data mungkin dilindungi oleh hak cipta atau mengandung informasi pribadi pasien. Pastikan bahwa aktivitas Anda legal dan tidak melanggar hak pihak ketiga.
Jenis Proksi Apa yang Harus Dipilih untuk Data Medis
Memilih jenis proksi sangat penting untuk keberhasilan parsing data medis. Sumber yang berbeda memerlukan pendekatan yang berbeda. Mari kita bahas jenis proksi utama dan penerapannya:
| Jenis Proksi | Keuntungan | Kerugian | Kapan Digunakan |
|---|---|---|---|
| Proksi Pusat Data | Kecepatan tinggi (100+ Mbps), biaya rendah, koneksi stabil | Mudah terdeteksi, sering diblokir di situs yang dilindungi | Basis data terbuka tanpa perlindungan ketat (PubMed, WHO) |
| Proksi Residensial | IP nyata dari pengguna rumah, risiko pemblokiran rendah, melewati Cloudflare | Biaya lebih tinggi, kecepatan bervariasi, bisa tidak stabil | Basis data komersial yang dilindungi (Elsevier, Springer), situs dengan Cloudflare |
| Proksi Seluler | Kepercayaan maksimum (IP dari operator seluler), hampir tidak diblokir | Paling mahal, geografi terbatas, bisa lebih lambat | Sumber daya yang sangat dilindungi, ketika proksi residensial tidak membantu |
| Proksi ISP | Kecepatan pusat data + kepercayaan residensial, IP statis | Biaya rata-rata, ketersediaan terbatas | Parsing jangka panjang dari satu IP, ketika stabilitas diperlukan |
Untuk sebagian besar tugas parsing data medis, disarankan untuk menggunakan proksi residensial. Mereka memberikan keseimbangan optimal antara biaya dan efektivitas. Proksi pusat data hanya cocok untuk sumber terbuka tanpa perlindungan. Proksi seluler sebaiknya digunakan dalam kasus ekstrem, ketika jenis lain tidak berfungsi.
Rekomendasi Pemilihan untuk Sumber Tertentu
- PubMed, PubMed Central — proksi pusat data cukup, tetapi dengan pembatasan kecepatan hingga 3 permintaan per detik
- ClinicalTrials.gov — proksi pusat data, ada API resmi
- Elsevier, Springer, Wiley — proksi residensial wajib, menggunakan fingerprinting canggih
- DrugBank, RxList — proksi residensial, perlindungan aktif terhadap parsing
- Basis Data FDA, EMA — proksi pusat data cocok, tetapi dengan kecepatan parsing yang lambat
Sumber Utama Data Medis dan Perlindungannya
Data medis tersebar di banyak sumber, masing-masing memiliki spesifikasi dan tingkat perlindungan sendiri. Memahami fitur-fitur ini akan membantu Anda mengatur strategi parsing dengan benar.
Basis Data Terbuka Pemerintah
PubMed/PubMed Central — basis data publikasi medis terbesar, berisi lebih dari 35 juta catatan. Perpustakaan Medis Nasional AS (NLM) menyediakan API E-utilities resmi yang merupakan cara yang disukai untuk mengakses data. Parsing langsung dari antarmuka web mungkin, tetapi dibatasi hingga 3 permintaan per detik dari satu IP. Melebihi batas ini akan menyebabkan pemblokiran sementara selama 24 jam.
ClinicalTrials.gov — basis data penelitian klinis, berisi informasi tentang lebih dari 400.000 penelitian di 220 negara. Juga menyediakan API untuk akses programatik. Antarmuka web dilindungi oleh rate limiting — maksimum 100 permintaan dalam 5 menit dari satu IP. Menggunakan perlindungan dasar terhadap bot, tetapi tanpa Cloudflare.
Basis Data Obat FDA — basis data obat yang disetujui oleh FDA. Akses terbuka melalui antarmuka web dan API openFDA. Pembatasan: 240 permintaan per menit untuk pengguna anonim, 1000 permintaan per menit dengan kunci API. Pemblokiran jarang terjadi, tetapi mungkin terjadi saat parsing agresif.
Penerbit Ilmiah Komersial
Elsevier (ScienceDirect) — salah satu penerbit literatur ilmiah terbesar. Menggunakan perlindungan multi-level: Cloudflare, fingerprinting browser, analisis perilaku pengguna. Mendeteksi pola pengunduhan otomatis: akses berurutan ke artikel, tidak adanya JavaScript, User-Agent yang tidak biasa. Ketika parsing terdeteksi, memblokir IP di tingkat akun dan dapat memblokir seluruh institusi. Penggunaan proksi residensial dengan rotasi dan emulasi browser penuh sangat disarankan.
Springer Nature — perlindungan serupa, tambahan memantau kecepatan scrolling halaman dan gerakan mouse. Menggunakan machine learning untuk mendeteksi bot. Disarankan untuk tidak mem-parsing lebih dari 10-15 artikel per jam dari satu IP, dengan penundaan acak antara permintaan.
Wiley Online Library — perlindungan yang kurang agresif, tetapi tetap memerlukan penggunaan proksi. Mengizinkan sekitar 50 permintaan per jam dari satu IP tanpa pemblokiran. Menggunakan session cookies untuk melacak aktivitas.
Basis Data Farmasi
DrugBank — basis data komprehensif tentang obat-obatan. Versi gratis dibatasi pada antarmuka web, versi komersial menyediakan API dan ekspor data. Versi web dilindungi oleh Cloudflare dan rate limiting — maksimum 20 permintaan per menit. Mendeteksi otomatisasi berdasarkan tidak adanya cookies dan JavaScript.
RxList, Drugs.com — panduan obat populer untuk konsumen. Menggunakan Cloudflare dan aktif melawan parsing. Memblokir IP pusat data hampir secara instan. Memerlukan proksi residensial dan kecepatan parsing yang lambat (5-10 halaman per menit).
Pengaturan Rotasi IP untuk Parsing Jangka Panjang
Rotasi alamat IP yang benar adalah faktor kunci untuk keberhasilan parsing data medis. Ada dua pendekatan utama: rotasi pada tingkat permintaan dan rotasi berdasarkan waktu.
Rotasi pada Tingkat Permintaan
Dalam pendekatan ini, setiap permintaan dikirim melalui alamat IP baru. Ini meminimalkan risiko pemblokiran, tetapi dapat menyebabkan masalah dengan situs yang melacak sesi melalui cookies. Cocok untuk parsing daftar dan katalog, di mana tidak diperlukan pemeliharaan status sesi.
Sebagian besar penyedia proksi residensial menyediakan rotasi otomatis melalui endpoint khusus. Misalnya, saat menggunakan rotating proxy endpoint, setiap koneksi TCP baru mendapatkan IP baru. Ini bekerja secara otomatis dengan pustaka seperti requests di Python, karena secara default membuat koneksi baru untuk setiap permintaan.
Rotasi Berdasarkan Waktu (Sticky Sessions)
Sticky sessions memungkinkan penggunaan satu alamat IP selama waktu tertentu (biasanya 5-30 menit), setelah itu terjadi pergantian otomatis. Ini berguna untuk situs yang memerlukan otorisasi atau melacak status sesi melalui cookies. Anda dapat mem-parsing beberapa halaman dari satu IP, meniru perilaku pengguna nyata, dan kemudian IP secara otomatis berubah.
Untuk situs medis, disarankan untuk menggunakan sticky sessions dengan durasi 10-15 menit. Dalam waktu ini, Anda dapat mem-parsing 10-20 halaman (tergantung pada penundaan), setelah itu IP berubah, dan Anda memulai "sesi baru". Ini terlihat alami dan mengurangi risiko deteksi.
Ukuran Pool Alamat IP
Untuk parsing jangka panjang, ukuran pool alamat IP yang tersedia sangat penting. Jika Anda menggunakan satu set 100 IP yang sama selama seminggu, situs dapat memperhatikan pola dan memblokir semua alamat tersebut. Proksi residensial biasanya memberikan akses ke jutaan IP, yang hampir mengecualikan penggunaan kembali alamat yang sama.
Saat menggunakan proksi pusat data, disarankan untuk memiliki pool minimal 500-1000 IP untuk parsing volume sedang (10.000-50.000 halaman per bulan). Untuk parsing berskala besar (ratusan ribu halaman), lebih baik menggunakan proksi residensial dengan pool IP yang besar.
Saran Rotasi untuk Sumber Berbeda:
- PubMed — rotasi tidak wajib, cukup 1 IP dengan mematuhi rate limit
- Penerbit Komersial — sticky sessions 10-15 menit, IP baru setiap 15-20 halaman
- Basis Data Farmasi — rotasi untuk setiap permintaan atau sticky sessions 5 menit
- Situs dengan Cloudflare — sticky sessions wajib, rotasi pada tingkat permintaan tidak berfungsi
Contoh Kode Python untuk Parsing dengan Proksi
Mari kita lihat contoh praktis pengaturan proksi untuk parsing data medis menggunakan pustaka Python yang populer. Kita mulai dengan contoh dasar dan secara bertahap membuatnya lebih kompleks.
Pengaturan Dasar dengan Pustaka Requests
import requests
from time import sleep
import random
# Pengaturan proksi (ganti dengan data Anda)
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}'
}
# Header untuk meniru browser nyata
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'
}
# Contoh permintaan ke PubMed
url = "https://pubmed.ncbi.nlm.nih.gov/?term=diabetes"
try:
response = requests.get(url, proxies=proxies, headers=headers, timeout=30)
print(f"Status code: {response.status_code}")
print(f"Panjang konten: {len(response.content)}")
# Menambahkan penundaan antara permintaan (wajib untuk PubMed)
sleep(random.uniform(1.0, 3.0))
except requests.exceptions.RequestException as e:
print(f"Error: {e}")
Pengaturan Lanjutan dengan Rotasi dan Retry Logic
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: daftar kamus dengan proksi
[{'http': 'http://user:pass@host:port', 'https': '...'}, ...]
"""
self.proxy_list = proxy_list
self.current_index = 0
def get_next_proxy(self):
"""Mendapatkan proksi berikutnya dari daftar"""
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():
"""Membuat sesi dengan otomatisasi pengulangan saat terjadi kesalahan"""
session = requests.Session()
# Pengaturan otomatisasi pengulangan
retry_strategy = Retry(
total=3, # maksimum 3 percobaan
backoff_factor=1, # penundaan antara percobaan: 1, 2, 4 detik
status_forcelist=[429, 500, 502, 503, 504], # kode untuk pengulangan
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):
"""Parsing daftar URL dengan rotasi proksi"""
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:
# Mendapatkan proksi baru untuk setiap permintaan
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': 'success',
'content_length': len(response.content)
})
print(f"✓ Sukses: {url}")
else:
results.append({
'url': url,
'status': 'failed',
'error': f"Status code: {response.status_code}"
})
print(f"✗ Gagal: {url} (Status: {response.status_code})")
except requests.exceptions.RequestException as e:
results.append({
'url': url,
'status': 'error',
'error': str(e)
})
print(f"✗ Error: {url} ({e})")
# Penundaan acak antara permintaan (penting!)
sleep(random.uniform(2.0, 5.0))
return results
# Contoh penggunaan
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)
Menggunakan Selenium untuk Situs dengan JavaScript
Banyak situs medis modern menggunakan JavaScript untuk memuat konten. Dalam kasus seperti itu, diperlukan browser 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):
"""Membuat Chrome WebDriver dengan proksi"""
chrome_options = Options()
# Mode headless (tanpa GUI)
chrome_options.add_argument('--headless')
chrome_options.add_argument('--no-sandbox')
chrome_options.add_argument('--disable-dev-shm-usage')
# Pengaturan proksi
chrome_options.add_argument(f'--proxy-server=http://{proxy_host}:{proxy_port}')
# Menonaktifkan otomatisasi (penting untuk menghindari deteksi)
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)
# Untuk proksi dengan otentikasi, perlu menggunakan ekstensi
# atau mengatur melalui capabilities (varian yang lebih rumit)
return driver
def scrape_with_selenium(url, driver):
"""Parsing halaman dengan menunggu pemuatan JavaScript"""
driver.get(url)
# Menunggu pemuatan elemen (misalnya, hasil pencarian)
try:
wait = WebDriverWait(driver, 10)
results = wait.until(
EC.presence_of_element_located((By.CLASS_NAME, "results-article"))
)
# Mengambil data
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"Error waiting for elements: {e}")
return []
# Contoh penggunaan
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"Judul: {result['title']}")
print(f"Penulis: {result['authors']}\n")
finally:
driver.quit()
Kontrol Kecepatan Permintaan dan Menghindari Rate Limiting
Rate limiting adalah salah satu perlindungan utama situs medis terhadap parsing. Pengaturan kecepatan permintaan yang benar sangat penting untuk parsing jangka panjang tanpa pemblokiran.
Menentukan Kecepatan Aman
Langkah pertama adalah menentukan batas untuk situs tertentu. Ini dapat dilakukan secara eksperimental dengan secara bertahap meningkatkan kecepatan permintaan hingga muncul kesalahan 429 (Too Many Requests) atau pemblokiran. Untuk sebagian besar situs medis, nilai aman adalah:
- PubMed — maksimum 3 permintaan per detik (rekomendasi resmi)
- ClinicalTrials.gov — 20 permintaan per menit aman, hingga 100 dalam 5 menit diperbolehkan
- Penerbit Komersial — 10-15 permintaan per jam dari satu IP
- Basis Data Farmasi — 5-10 permintaan per menit
Implementasi Rate Limiter di Python
import time
from collections import deque
class RateLimiter:
def __init__(self, max_calls, period):
"""
max_calls: jumlah maksimum panggilan
period: periode waktu dalam detik
Contoh: RateLimiter(3, 1) = 3 permintaan per detik
"""
self.max_calls = max_calls
self.period = period
self.calls = deque()
def __call__(self, func):
"""Dekorator untuk membatasi kecepatan panggilan fungsi"""
def wrapper(*args, **kwargs):
now = time.time()
# Menghapus panggilan lama di luar periode
while self.calls and self.calls[0] < now - self.period:
self.calls.popleft()
# Jika mencapai batas, tunggu
if len(self.calls) >= self.max_calls:
sleep_time = self.period - (now - self.calls[0])
if sleep_time > 0:
print(f"Batas kecepatan tercapai, tidur {sleep_time:.2f}s")
time.sleep(sleep_time)
# Bersihkan setelah menunggu
self.calls.clear()
# Mencatat waktu panggilan
self.calls.append(time.time())
# Menjalankan fungsi
return func(*args, **kwargs)
return wrapper
# Contoh penggunaan
@RateLimiter(max_calls=3, period=1) # 3 permintaan per detik
def fetch_pubmed_page(url):
response = requests.get(url, headers=headers, proxies=proxies)
return response
# Sekarang fungsi secara otomatis mematuhi rate limit
for i in range(10):
result = fetch_pubmed_page(f"https://pubmed.ncbi.nlm.nih.gov/?term=test&page={i}")
print(f"Halaman {i} diambil")
Rate Limiting Adaptif
Pendekatan yang lebih canggih adalah mengubah kecepatan secara adaptif berdasarkan respons server. Jika kita mendapatkan kesalahan 429 atau 503, secara otomatis kita menurunkan kecepatan:
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):
"""Menunggu sebelum permintaan berikutnya"""
# Menambahkan keacakan untuk kealamian
actual_delay = self.current_delay * random.uniform(0.8, 1.2)
time.sleep(actual_delay)
def on_success(self):
"""Dipanggil saat permintaan berhasil"""
self.success_count += 1
# Setelah 10 permintaan berhasil, sedikit mempercepat
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):
"""Dipanggil saat mendapatkan 429 atau kesalahan serupa"""
# Menggandakan penundaan, tetapi tidak lebih dari maksimum
self.current_delay = min(
self.current_delay * 2,
self.max_delay
)
self.success_count = 0
print(f"Batas kecepatan tercapai! Meningkatkan penundaan menjadi {self.current_delay:.2f}s")
def on_error(self):
"""Dipanggil saat terjadi kesalahan lain"""
# Sedikit meningkatkan penundaan
self.current_delay = min(
self.current_delay * 1.5,
self.max_delay
)
self.success_count = 0
# Contoh penggunaan
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()
# Pemrosesan data
elif response.status_code == 429:
limiter.on_rate_limit()
# Ulangi nanti
else:
limiter.on_error()
except requests.exceptions.RequestException:
limiter.on_error()
Header dan User-Agent yang Benar untuk Situs Medis
Situs medis menganalisis header HTTP untuk mendeteksi bot. Header yang salah atau tidak ada adalah penyebab umum pemblokiran bahkan saat menggunakan proksi berkualitas.
Header Wajib
Setidaknya, berikut adalah header yang harus ada dalam setiap permintaan:
headers = {
# User-Agent — harus menggunakan browser yang aktual
'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 — tipe konten yang diterima oleh browser
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8',
# Accept-Language — bahasa pengguna
'Accept-Language': 'en-US,en;q=0.9',
# Accept-Encoding — dukungan untuk kompresi
'Accept-Encoding': 'gzip, deflate, br',
# Connection — menjaga koneksi
'Connection': 'keep-alive',
# Upgrade-Insecure-Requests — otomatis beralih ke HTTPS
'Upgrade-Insecure-Requests': '1',
# DNT — Do Not Track (opsional, tetapi menambah keaslian)
'DNT': '1',
# Header Sec-Fetch-* (penting untuk browser modern)
'Sec-Fetch-Dest': 'document',
'Sec-Fetch-Mode': 'navigate',
'Sec-Fetch-Site': 'none',
'Sec-Fetch-User': '?1',
# Cache-Control
'Cache-Control': 'max-age=0'
}
Rotasi User-Agent
Menggunakan User-Agent yang sama dapat mencurigakan. Disarankan untuk melakukan rotasi antara beberapa browser yang aktual:
import random
USER_AGENTS = [
# Chrome di 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 di 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 di Windows
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:121.0) Gecko/20100101 Firefox/121.0',
# Firefox di Mac
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:121.0) Gecko/20100101 Firefox/121.0',
# Safari di 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 di 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():
"""Mendapatkan header dengan User-Agent acak"""
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'
}
# Penggunaan
for url in urls:
headers = get_random_headers()
response = requests.get(url, headers=headers, proxies=proxies)
Referer dan Origin untuk Formulir
Saat bekerja dengan formulir pencarian atau mengirimkan permintaan POST, pastikan untuk menambahkan header Referer dan Origin:
# Untuk permintaan POST ke formulir pencarian
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'
}
# Permintaan POST dengan data formulir
data = {
'query': 'diabetes',
'page': '1'
}
response = requests.post(
'https://example.com/search',
headers=headers,
data=data,
proxies=proxies
)
Masalah Umum dan Solusinya
Saat melakukan parsing data medis, muncul masalah spesifik. Mari kita bahas masalah yang paling umum dan cara mengatasinya.
Masalah: Cloudflare Memblokir Semua Permintaan
Gejala: Anda mendapatkan halaman dengan teks "Checking your browser" atau kesalahan 403 Forbidden dengan penyebutan Cloudflare.
Solusi:
- Gunakan proksi residensial alih-alih pusat data — Cloudflare secara default memblokir IP pusat data
- Beralih ke Selenium atau Puppeteer — browser headless lebih baik melewati pemeriksaan Cloudflare
- Gunakan pustaka cloudscraper untuk Python — ini secara otomatis melewati perlindungan dasar Cloudflare
- Aktifkan cookies dan JavaScript — Cloudflare memeriksa keberadaannya
- Tambahkan TLS fingerprinting — gunakan curl_cffi untuk meniru browser nyata di tingkat TLS
Masalah: Mendapatkan Kesalahan 429 Too Many Requests
Gejala: Setelah beberapa permintaan berhasil, server mulai mengembalikan 429.
Solusi:
- Tingkatkan penundaan antara permintaan — coba mulai dengan 3-5 detik
- Aktifkan rotasi IP — setiap permintaan melalui IP baru menghapus rate limiting
- Periksa header Retry-After dalam respons 429 — ini menunjukkan berapa detik yang perlu ditunggu
- Gunakan penundaan eksponensial saat mengulangi — 1s, 2s, 4s, 8s, dll.
Masalah: Proksi Berfungsi Lambat atau Sering Terputus
Gejala: Kesalahan timeout, pemuatan halaman yang sangat lambat, putusnya koneksi.
Solusi:
- Tingkatkan timeout dalam permintaan hingga 30-60 detik — proksi residensial bisa lebih lambat
- Gunakan proksi yang dekat secara geografis — jika mem-parsing situs Eropa, gunakan IP Eropa
- Periksa kualitas penyedia proksi — proksi murah sering kali tidak stabil
- Tambahkan retry logic — secara otomatis ulangi permintaan saat terjadi kesalahan koneksi
- Gunakan connection pooling — gunakan kembali koneksi TCP melalui requests.Session()
Masalah: Situs Memerlukan Otorisasi atau Langganan
Gejala: Akses ke teks lengkap artikel dibatasi, memerlukan login.
Solusi:
- Gunakan akses institusional — banyak universitas dan rumah sakit memiliki langganan
- Periksa ketersediaan versi Open Access — banyak artikel tersedia secara gratis melalui repositori
- Gunakan API alih-alih parsing — beberapa penerbit menyediakan API untuk peneliti
- Hanya mem-parsing metadata (judul, penulis, anotasi) — biasanya tersedia secara gratis
Masalah: Konten JavaScript Tidak Dimuat
Gejala: Dalam HTML tidak ada data yang diperlukan, hanya terlihat spinner pemuatan atau kontainer kosong.
Solusi:
- Beralih ke Selenium/Puppeteer — mereka menjalankan JavaScript
- Temukan endpoint API — buka DevTools di browser, tab Network, dan temukan permintaan XHR dengan data
- Gunakan requests-html — pustaka dengan...