Парсинг медицинских данных — задача, требующая особого подхода к выбору прокси. Медицинские порталы, базы данных клинических исследований и фармацевтические ресурсы используют продвинутые системы защиты от автоматизированного сбора данных. В этой статье разберём, как правильно настроить прокси для безопасного парсинга медицинской информации, избежать блокировок и собрать нужные данные эффективно.
Почему медицинские сайты блокируют парсинг
Медицинские порталы и базы данных особенно чувствительны к автоматизированному сбору информации по нескольким причинам. Во-первых, многие из них работают на коммерческой основе и продают доступ к данным через платные подписки. Автоматический парсинг может нарушать условия использования и лицензионные соглашения.
Во-вторых, медицинские данные часто содержат конфиденциальную информацию, защищённую законодательством (HIPAA в США, GDPR в Европе). Владельцы ресурсов обязаны контролировать доступ к таким данным и предотвращать их несанкционированное распространение. Поэтому они используют продвинутые системы защиты:
- Rate limiting — ограничение количества запросов с одного IP-адреса в единицу времени (обычно 10-50 запросов в минуту)
- Fingerprinting — анализ характеристик браузера, заголовков HTTP, порядка загрузки ресурсов
- CAPTCHA — системы типа reCAPTCHA v3, которые срабатывают при подозрительной активности
- IP-блокировки — временная или постоянная блокировка IP-адресов дата-центров
- Cloudflare и аналоги — защита от ботов на уровне CDN
Третья причина — нагрузка на серверы. Медицинские базы данных часто содержат миллионы записей, и массовый парсинг может создать значительную нагрузку на инфраструктуру. Поэтому администраторы активно борются с автоматизированным сбором данных, отслеживая паттерны поведения, характерные для ботов: одинаковые интервалы между запросами, линейный обход страниц, отсутствие JavaScript и cookies.
Важно: Перед началом парсинга медицинских данных обязательно изучите условия использования сайта и применимое законодательство. Некоторые данные могут быть защищены авторским правом или содержать персональную информацию пациентов. Убедитесь, что ваша деятельность законна и не нарушает права третьих лиц.
Какой тип прокси выбрать для медицинских данных
Выбор типа прокси критически важен для успешного парсинга медицинских данных. Разные источники требуют разного подхода. Рассмотрим основные типы прокси и их применимость:
| Тип прокси | Преимущества | Недостатки | Когда использовать |
|---|---|---|---|
| Прокси дата-центров | Высокая скорость (100+ Мбит/с), низкая стоимость, стабильное соединение | Легко детектируются, часто заблокированы на защищённых сайтах | Открытые базы данных без строгой защиты (PubMed, WHO) |
| Резидентные прокси | Реальные IP домашних пользователей, низкий риск блокировки, проходят Cloudflare | Выше стоимость, переменная скорость, могут быть нестабильны | Защищённые коммерческие базы (Elsevier, Springer), сайты с Cloudflare |
| Мобильные прокси | Максимальное доверие (IP мобильных операторов), практически не блокируются | Самые дорогие, ограниченная география, могут быть медленнее | Особо защищённые ресурсы, когда резидентные прокси не помогают |
| ISP прокси | Скорость дата-центров + доверие резидентных, статичные IP | Средняя стоимость, ограниченная доступность | Долгосрочный парсинг с одного IP, когда нужна стабильность |
Для большинства задач парсинга медицинских данных рекомендуется использовать резидентные прокси. Они обеспечивают оптимальный баланс между стоимостью и эффективностью. Прокси дата-центров подходят только для открытых источников без защиты. Мобильные прокси стоит использовать в крайних случаях, когда другие типы не работают.
Рекомендации по выбору для конкретных источников
- PubMed, PubMed Central — прокси дата-центров достаточно, но с ограничением скорости до 3 запросов в секунду
- ClinicalTrials.gov — прокси дата-центров, есть официальный API
- Elsevier, Springer, Wiley — резидентные прокси обязательны, используют продвинутый fingerprinting
- DrugBank, RxList — резидентные прокси, активная защита от парсинга
- FDA, EMA базы данных — прокси дата-центров подходят, но с медленной скоростью парсинга
Основные источники медицинских данных и их защита
Медицинские данные распределены по множеству источников, каждый из которых имеет свою специфику и уровень защиты. Понимание этих особенностей поможет правильно настроить стратегию парсинга.
Открытые государственные базы данных
PubMed/PubMed Central — крупнейшая база медицинских публикаций, содержит более 35 миллионов записей. Национальная медицинская библиотека США (NLM) предоставляет официальный API E-utilities, который является предпочтительным способом доступа к данным. Прямой парсинг веб-интерфейса возможен, но ограничен 3 запросами в секунду с одного IP. Превышение лимита приводит к временной блокировке на 24 часа.
ClinicalTrials.gov — база данных клинических исследований, содержит информацию о более чем 400,000 исследованиях в 220 странах. Также предоставляет API для программного доступа. Веб-интерфейс защищён rate limiting — максимум 100 запросов в 5 минут с одного IP. Используется базовая защита от ботов, но без Cloudflare.
FDA Drugs Database — база данных одобренных лекарственных препаратов FDA. Открытый доступ через веб-интерфейс и API openFDA. Ограничения: 240 запросов в минуту для анонимных пользователей, 1000 запросов в минуту с API-ключом. Блокировки редки, но при агрессивном парсинге возможны.
Коммерческие научные издательства
Elsevier (ScienceDirect) — один из крупнейших издателей научной литературы. Использует многоуровневую защиту: Cloudflare, fingerprinting браузера, анализ поведения пользователя. Детектирует паттерны автоматического скачивания: последовательный доступ к статьям, отсутствие JavaScript, нетипичные User-Agent. При обнаружении парсинга блокирует IP на уровне аккаунта и может заблокировать весь институт. Обязательно использование резидентных прокси с ротацией и полной эмуляцией браузера.
Springer Nature — аналогичная защита, дополнительно отслеживает скорость скроллинга страниц и движения мыши. Использует machine learning для детекции ботов. Рекомендуется парсить не более 10-15 статей в час с одного IP, с рандомизированными задержками между запросами.
Wiley Online Library — менее агрессивная защита, но всё равно требует использования прокси. Допускает около 50 запросов в час с одного IP без блокировки. Использует session cookies для отслеживания активности.
Фармацевтические базы данных
DrugBank — комплексная база данных лекарственных препаратов. Бесплатная версия ограничена веб-интерфейсом, коммерческая предоставляет API и выгрузки данных. Веб-версия защищена Cloudflare и rate limiting — максимум 20 запросов в минуту. Детектирует автоматизацию по отсутствию cookies и JavaScript.
RxList, Drugs.com — популярные справочники лекарств для потребителей. Используют Cloudflare и активно борются с парсингом. Блокируют IP дата-центров практически моментально. Требуются резидентные прокси и медленная скорость парсинга (5-10 страниц в минуту).
Настройка ротации IP для долгосрочного парсинга
Правильная ротация IP-адресов — ключевой фактор успешного парсинга медицинских данных. Существует два основных подхода: ротация на уровне запросов и ротация по времени.
Ротация на уровне запросов
При этом подходе каждый запрос отправляется через новый IP-адрес. Это максимально снижает риск блокировки, но может вызвать проблемы с сайтами, которые отслеживают сессии через cookies. Подходит для парсинга списков и каталогов, где не требуется поддержание состояния сессии.
Большинство провайдеров резидентных прокси предоставляют автоматическую ротацию через специальный endpoint. Например, при использовании rotating proxy endpoint каждый новый TCP-коннект получает новый IP. Это работает автоматически с библиотеками типа requests в Python, так как по умолчанию создаётся новое соединение для каждого запроса.
Ротация по времени (sticky sessions)
Sticky sessions позволяют использовать один IP-адрес в течение определённого времени (обычно 5-30 минут), после чего происходит автоматическая смена. Это полезно для сайтов, требующих авторизации или отслеживающих состояние сессии через cookies. Вы можете парсить несколько страниц с одного IP, имитируя поведение реального пользователя, а затем IP автоматически меняется.
Для медицинских сайтов рекомендуется использовать sticky sessions длительностью 10-15 минут. За это время можно спарсить 10-20 страниц (в зависимости от задержек), после чего IP меняется, и вы начинаете "новую сессию". Это выглядит естественно и снижает риск детекции.
Размер пула IP-адресов
Для долгосрочного парсинга важен размер пула доступных IP-адресов. Если вы используете один и тот же набор из 100 IP в течение недели, сайт может заметить паттерн и заблокировать все эти адреса. Резидентные прокси обычно предоставляют доступ к миллионам IP, что практически исключает повторное использование одного и того же адреса.
При использовании прокси дата-центров рекомендуется иметь пул минимум из 500-1000 IP для парсинга среднего объёма (10,000-50,000 страниц в месяц). Для крупномасштабного парсинга (сотни тысяч страниц) лучше использовать резидентные прокси с их огромными пулами IP.
Совет по ротации для разных источников:
- PubMed — ротация не обязательна, достаточно 1 IP с соблюдением rate limit
- Коммерческие издательства — sticky sessions 10-15 минут, новый IP каждые 15-20 страниц
- Фармацевтические базы — ротация на каждый запрос или sticky sessions 5 минут
- Сайты с Cloudflare — sticky sessions обязательны, ротация на уровне запросов не работает
Примеры кода на Python для парсинга с прокси
Рассмотрим практические примеры настройки прокси для парсинга медицинских данных с использованием популярных Python-библиотек. Начнём с базового примера и постепенно усложним его.
Базовая настройка с библиотекой requests
import requests
from time import sleep
import random
# Настройка прокси (замените на ваши данные)
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}'
}
# Заголовки для имитации реального браузера
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'
}
# Пример запроса к 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"Content length: {len(response.content)}")
# Добавляем задержку между запросами (обязательно для PubMed)
sleep(random.uniform(1.0, 3.0))
except requests.exceptions.RequestException as e:
print(f"Error: {e}")
Продвинутая настройка с ротацией и 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: список словарей с прокси
[{'http': 'http://user:pass@host:port', 'https': '...'}, ...]
"""
self.proxy_list = proxy_list
self.current_index = 0
def get_next_proxy(self):
"""Получить следующий прокси из списка"""
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():
"""Создать сессию с автоматическими повторами при ошибках"""
session = requests.Session()
# Настройка автоматических повторов
retry_strategy = Retry(
total=3, # максимум 3 попытки
backoff_factor=1, # задержка между попытками: 1, 2, 4 секунды
status_forcelist=[429, 500, 502, 503, 504], # коды для повтора
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):
"""Парсинг списка URL с ротацией прокси"""
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:
# Получаем новый прокси для каждого запроса
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"✓ Success: {url}")
else:
results.append({
'url': url,
'status': 'failed',
'error': f"Status code: {response.status_code}"
})
print(f"✗ Failed: {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})")
# Случайная задержка между запросами (важно!)
sleep(random.uniform(2.0, 5.0))
return results
# Пример использования
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)
Использование Selenium для сайтов с JavaScript
Многие современные медицинские сайты используют JavaScript для загрузки контента. В таких случаях необходим 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):
"""Создать Chrome WebDriver с прокси"""
chrome_options = Options()
# Headless режим (без GUI)
chrome_options.add_argument('--headless')
chrome_options.add_argument('--no-sandbox')
chrome_options.add_argument('--disable-dev-shm-usage')
# Настройка прокси
chrome_options.add_argument(f'--proxy-server=http://{proxy_host}:{proxy_port}')
# Отключение автоматизации (важно для обхода детекции)
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)
# Для прокси с аутентификацией нужно использовать расширение
# или настроить через capabilities (более сложный вариант)
return driver
def scrape_with_selenium(url, driver):
"""Парсинг страницы с ожиданием загрузки JavaScript"""
driver.get(url)
# Ожидание загрузки элемента (например, результатов поиска)
try:
wait = WebDriverWait(driver, 10)
results = wait.until(
EC.presence_of_element_located((By.CLASS_NAME, "results-article"))
)
# Извлечение данных
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 []
# Пример использования
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"Title: {result['title']}")
print(f"Authors: {result['authors']}\n")
finally:
driver.quit()
Контроль скорости запросов и обход rate limiting
Rate limiting — одна из основных защит медицинских сайтов от парсинга. Правильная настройка скорости запросов критически важна для долгосрочного парсинга без блокировок.
Определение безопасной скорости
Первый шаг — определить лимиты конкретного сайта. Это можно сделать экспериментально, постепенно увеличивая скорость запросов до появления ошибок 429 (Too Many Requests) или блокировки. Для большинства медицинских сайтов безопасные значения:
- PubMed — максимум 3 запроса в секунду (официальная рекомендация)
- ClinicalTrials.gov — 20 запросов в минуту безопасно, до 100 в 5 минут допустимо
- Коммерческие издательства — 10-15 запросов в час с одного IP
- Фармацевтические базы — 5-10 запросов в минуту
Реализация rate limiter на Python
import time
from collections import deque
class RateLimiter:
def __init__(self, max_calls, period):
"""
max_calls: максимальное количество вызовов
period: период времени в секундах
Например: RateLimiter(3, 1) = 3 запроса в секунду
"""
self.max_calls = max_calls
self.period = period
self.calls = deque()
def __call__(self, func):
"""Декоратор для ограничения скорости вызова функции"""
def wrapper(*args, **kwargs):
now = time.time()
# Удаляем старые вызовы за пределами периода
while self.calls and self.calls[0] < now - self.period:
self.calls.popleft()
# Если достигли лимита, ждём
if len(self.calls) >= self.max_calls:
sleep_time = self.period - (now - self.calls[0])
if sleep_time > 0:
print(f"Rate limit reached, sleeping {sleep_time:.2f}s")
time.sleep(sleep_time)
# Очищаем после ожидания
self.calls.clear()
# Записываем время вызова
self.calls.append(time.time())
# Выполняем функцию
return func(*args, **kwargs)
return wrapper
# Пример использования
@RateLimiter(max_calls=3, period=1) # 3 запроса в секунду
def fetch_pubmed_page(url):
response = requests.get(url, headers=headers, proxies=proxies)
return response
# Теперь функция автоматически соблюдает rate limit
for i in range(10):
result = fetch_pubmed_page(f"https://pubmed.ncbi.nlm.nih.gov/?term=test&page={i}")
print(f"Page {i} fetched")
Адаптивный rate limiting
Более продвинутый подход — адаптивное изменение скорости в зависимости от ответов сервера. Если получаем ошибки 429 или 503, автоматически снижаем скорость:
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):
"""Ожидание перед следующим запросом"""
# Добавляем случайность для естественности
actual_delay = self.current_delay * random.uniform(0.8, 1.2)
time.sleep(actual_delay)
def on_success(self):
"""Вызывается при успешном запросе"""
self.success_count += 1
# После 10 успешных запросов немного ускоряемся
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):
"""Вызывается при получении 429 или подобных ошибок"""
# Удваиваем задержку, но не больше максимума
self.current_delay = min(
self.current_delay * 2,
self.max_delay
)
self.success_count = 0
print(f"Rate limit hit! Increasing delay to {self.current_delay:.2f}s")
def on_error(self):
"""Вызывается при других ошибках"""
# Немного увеличиваем задержку
self.current_delay = min(
self.current_delay * 1.5,
self.max_delay
)
self.success_count = 0
# Пример использования
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()
# Обработка данных
elif response.status_code == 429:
limiter.on_rate_limit()
# Повторить позже
else:
limiter.on_error()
except requests.exceptions.RequestException:
limiter.on_error()
Правильные заголовки и User-Agent для медицинских сайтов
Медицинские сайты анализируют HTTP-заголовки для детекции ботов. Неправильные или отсутствующие заголовки — частая причина блокировок даже при использовании качественных прокси.
Обязательные заголовки
Минимальный набор заголовков, который должен присутствовать в каждом запросе:
headers = {
# User-Agent — обязательно актуальный браузер
'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 — типы контента, которые принимает браузер
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8',
# Accept-Language — язык пользователя
'Accept-Language': 'en-US,en;q=0.9',
# Accept-Encoding — поддержка сжатия
'Accept-Encoding': 'gzip, deflate, br',
# Connection — поддержание соединения
'Connection': 'keep-alive',
# Upgrade-Insecure-Requests — автоматический переход на HTTPS
'Upgrade-Insecure-Requests': '1',
# DNT — Do Not Track (опционально, но добавляет реалистичности)
'DNT': '1',
# Sec-Fetch-* заголовки (важны для современных браузеров)
'Sec-Fetch-Dest': 'document',
'Sec-Fetch-Mode': 'navigate',
'Sec-Fetch-Site': 'none',
'Sec-Fetch-User': '?1',
# Cache-Control
'Cache-Control': 'max-age=0'
}
Ротация User-Agent
Использование одного и того же User-Agent может быть подозрительным. Рекомендуется ротация между несколькими актуальными браузерами:
import random
USER_AGENTS = [
# Chrome на 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 на 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 на Windows
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:121.0) Gecko/20100101 Firefox/121.0',
# Firefox на Mac
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:121.0) Gecko/20100101 Firefox/121.0',
# Safari на 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 на 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():
"""Получить заголовки со случайным User-Agent"""
return {
'User-Agent': random.choice(USER_AGENTS),
'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',
'Connection': 'keep-alive',
'Upgrade-Insecure-Requests': '1',
'DNT': '1'
}
# Использование
for url in urls:
headers = get_random_headers()
response = requests.get(url, headers=headers, proxies=proxies)
Referer и Origin для форм
При работе с формами поиска или отправке POST-запросов обязательно добавляйте заголовки Referer и Origin:
# Для POST-запросов к форме поиска
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'
}
# POST-запрос с данными формы
data = {
'query': 'diabetes',
'page': '1'
}
response = requests.post(
'https://example.com/search',
headers=headers,
data=data,
proxies=proxies
)
Типичные проблемы и их решение
При парсинге медицинских данных возникают специфические проблемы. Рассмотрим наиболее частые и способы их решения.
Проблема: Cloudflare блокирует все запросы
Симптомы: Получаете страницу с текстом "Checking your browser" или ошибку 403 Forbidden с упоминанием Cloudflare.
Решение:
- Используйте резидентные прокси вместо дата-центров — Cloudflare блокирует IP дата-центров по умолчанию
- Переключитесь на Selenium или Puppeteer — headless-браузеры лучше проходят проверки Cloudflare
- Используйте библиотеку cloudscraper для Python — она автоматически обходит базовую защиту Cloudflare
- Включите cookies и JavaScript — Cloudflare проверяет их наличие
- Добавьте TLS fingerprinting — используйте curl_cffi для имитации настоящего браузера на уровне TLS
Проблема: Получаю ошибку 429 Too Many Requests
Симптомы: После нескольких успешных запросов сервер начинает возвращать 429.
Решение:
- Увеличьте задержку между запросами — попробуйте начать с 3-5 секунд
- Включите ротацию IP — каждый запрос через новый IP снимает rate limiting
- Проверьте заголовок Retry-After в ответе 429 — он указывает, сколько секунд нужно ждать
- Используйте экспоненциальную задержку при повторах — 1s, 2s, 4s, 8s и т.д.
Проблема: Прокси работают медленно или часто отваливаются
Симптомы: Timeout errors, очень долгая загрузка страниц, обрывы соединения.
Решение:
- Увеличьте timeout в запросах до 30-60 секунд — резидентные прокси могут быть медленнее
- Используйте географически близкие прокси — если парсите европейский сайт, используйте европейские IP
- Проверьте качество провайдера прокси — дешёвые прокси часто нестабильны
- Добавьте retry logic — автоматически повторяйте запрос при ошибке соединения
- Используйте connection pooling — переиспользуйте TCP-соединения через requests.Session()
Проблема: Сайт требует авторизацию или подписку
Симптомы: Доступ к полным текстам статей ограничен, требуется логин.
Решение:
- Используйте институциональный доступ — многие университеты и больницы имеют подписки
- Проверьте наличие Open Access версий — многие статьи доступны бесплатно через репозитории
- Используйте API вместо парсинга — некоторые издательства предоставляют API для исследователей
- Парсите только метаданные (заголовки, авторы, аннотации) — они обычно доступны бесплатно
Проблема: JavaScript-контент не загружается
Симптомы: В HTML нет нужных данных, видны только загрузочные спиннеры или пустые контейнеры.
Решение:
- Переключитесь на Selenium/Puppeteer — они выполняют JavaScript
- Найдите API-эндпоинт — откройте DevTools в браузере, вкладка Network, и найдите XHR-запросы с данными
- Используйте requests-html — библиотека с