Скринер акций возвращает reCAPTCHA вместо таблицы котировок, SEC EDGAR обрывает сессию кодом 403 при частых запросах, а Bloomberg заворачивает весь автоматический трафик за Cloudflare Turnstile. Для любого, кто парсит биржевые данные скриптом, это не исключение, а норма: финансовые площадки одними из первых внедряют строгую защиту от ботов. CaptchaAI решает эти проверки через API — ниже показано, на каких сервисах они встречаются и как встроить решение CAPTCHA в парсер, не превращая его в набор костылей.
На каких финансовых сервисах вы встретите CAPTCHA
| Источник | Тип CAPTCHA | Что запускает проверку | Ценность данных |
|---|---|---|---|
| SEC EDGAR | reCAPTCHA v2 | Большой объём запросов | Отчётность компаний |
| Yahoo Finance | reCAPTCHA v2 | Обнаружение парсинга | Котировки акций, история |
| Bloomberg | Cloudflare Turnstile | Весь автоматический трафик | Рыночные данные |
| Finviz | reCAPTCHA v2 | Доступ к скринеру акций | Результаты скрининга |
| TradingView | Cloudflare Challenge | Ограничение частоты запросов | Графики, индикаторы |
| Morningstar | reCAPTCHA v3 | Страницы экспорта данных | Аналитика фондов |
Если вы снимаете котировки по 500–1000 тикерам в день, пяти потоков плана BASIC ($15/мес) обычно достаточно: один поток занят одной CAPTCHA, а число решений на поток не ограничено, поэтому весь список проходит без доплат за объём. Когда нужно опрашивать несколько бирж параллельно и расписание становится плотнее, есть смысл перейти на STANDARD ($30/мес, 15 потоков).
Прежде чем писать парсер: правила частоты запросов для финансовых сайтов
Финансовые площадки строже относятся к автоматическому доступу, чем большинство сайтов, поэтому эти правила стоит заложить в код скрейпера с самого начала, а не добавлять после первой блокировки:
- Задержка между запросами — 2–5 секунд между страницами.
- Параллельные соединения — максимум 3–5 на домен.
- Тип прокси — резидентный или ISP.
- Длительность сессии — закреплённые (sticky) сессии по 5–10 минут.
- User-Agent — реалистичный, единый в рамках сессии.
- SEC EDGAR — указывайте контактный email в User-Agent (обязательно).
- Часы торгов — по возможности парсите вне пиковых часов.
С этими вводными переходим к коду.
Парсинг скринера акций: где сработает CAPTCHA
Ниже — рабочий класс на Python, который парсит скринер акций и решает reCAPTCHA v2, если она появляется в ответе:
import requests
import time
from bs4 import BeautifulSoup
import re
CAPTCHAAI_KEY = "YOUR_API_KEY"
CAPTCHAAI_URL = "https://ocr.captchaai.com"
def solve_captcha(method, sitekey, pageurl, **kwargs):
data = {
"key": CAPTCHAAI_KEY,
"method": method,
"googlekey": sitekey,
"pageurl": pageurl,
"json": 1,
}
data.update(kwargs)
resp = requests.post(f"{CAPTCHAAI_URL}/in.php", data=data)
task_id = resp.json()["request"]
for _ in range(60):
time.sleep(5)
result = requests.get(f"{CAPTCHAAI_URL}/res.php", params={
"key": CAPTCHAAI_KEY, "action": "get",
"id": task_id, "json": 1,
})
r = result.json()
if r["request"] != "CAPCHA_NOT_READY":
return r["request"]
raise TimeoutError("Solve timeout")
class FinancialScraper:
def __init__(self, proxy=None):
self.session = requests.Session()
if proxy:
self.session.proxies = {"http": proxy, "https": proxy}
self.session.headers.update({
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 Chrome/126.0.0.0 Safari/537.36",
"Accept-Language": "en-US,en;q=0.9",
})
def scrape_screener(self, url):
"""Scrape stock screener, handling CAPTCHA if triggered."""
resp = self.session.get(url, timeout=30)
# Check for CAPTCHA
sitekey_match = re.search(r'data-sitekey="([^"]+)"', resp.text)
if sitekey_match:
sitekey = sitekey_match.group(1)
token = solve_captcha("userrecaptcha", sitekey, url)
# Resubmit with token
resp = self.session.post(url, data={
"g-recaptcha-response": token,
})
return self._parse_stocks(resp.text)
def _parse_stocks(self, html):
soup = BeautifulSoup(html, "html.parser")
stocks = []
for row in soup.select("table.screener-table tr")[1:]:
cols = row.select("td")
if len(cols) >= 8:
stocks.append({
"ticker": cols[1].get_text(strip=True),
"company": cols[2].get_text(strip=True),
"sector": cols[3].get_text(strip=True),
"price": cols[6].get_text(strip=True),
"change": cols[7].get_text(strip=True),
})
return stocks
# Usage
scraper = FinancialScraper(
proxy="http://user:[email protected]:5000"
)
stocks = scraper.scrape_screener("https://screener.example.com/screener.ashx?v=111")
for stock in stocks[:5]:
print(f"{stock['ticker']}: {stock['price']} ({stock['change']})")
Выгрузка документов из SEC EDGAR
SEC EDGAR ограничивает частоту запросов и подключает CAPTCHA при аномально высоком трафике:
Прежде чем автоматизировать выгрузку из EDGAR в промышленных масштабах, стоит свериться и с требованиями к обработке данных на своей стороне — например, 152-ФЗ «О персональных данных» для читателей из РФ или GDPR-совместимая осмотрительность для остальных: собирайте только то, что вправе обрабатывать, и не путайте публичные рыночные данные с персональными данными инвесторов.
import json
class SECFilingScraper:
BASE_URL = "https://efts.sec.gov/LATEST"
def __init__(self, user_agent_email, proxy=None):
self.session = requests.Session()
if proxy:
self.session.proxies = {"http": proxy, "https": proxy}
# SEC requires identifying User-Agent
self.session.headers.update({
"User-Agent": f"CompanyName admin@{user_agent_email}",
"Accept": "application/json",
})
def search_filings(self, company, filing_type="10-K"):
"""Search EDGAR for specific filing types."""
url = f"{self.BASE_URL}/search-index"
params = {
"q": company,
"dateRange": "custom",
"forms": filing_type,
}
resp = self.session.get(url, params=params, timeout=30)
# Handle CAPTCHA if triggered
if "captcha" in resp.text.lower() or resp.status_code == 403:
sitekey = self._extract_sitekey(resp.text)
if sitekey:
token = solve_captcha("userrecaptcha", sitekey, url)
resp = self.session.post(url, data={
**params,
"g-recaptcha-response": token,
})
return resp.json() if resp.status_code == 200 else {}
def download_filing(self, filing_url):
"""Download individual filing document."""
resp = self.session.get(filing_url, timeout=60)
if resp.status_code == 200:
return resp.text
return None
def _extract_sitekey(self, html):
match = re.search(r'data-sitekey="([^"]+)"', html)
return match.group(1) if match else None
# Usage
sec = SECFilingScraper(
user_agent_email="example.com",
proxy="http://user:[email protected]:5000",
)
filings = sec.search_filings("Apple Inc", "10-K")
Рыночные данные за Cloudflare Turnstile
Cloudflare Turnstile обычно решается быстрее чем за 10 секунд — заметно быстрее, чем reCAPTCHA v2 (до 60 секунд при высокой конкурентности запросов), поэтому для сайтов вроде Bloomberg он меньше сказывается на общей скорости парсинга:
def scrape_turnstile_market_data(url, sitekey):
"""Handle Cloudflare Turnstile on financial data sites."""
token = solve_captcha("turnstile", sitekey, url)
session = requests.Session()
session.headers.update({
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 Chrome/126.0.0.0 Safari/537.36",
})
resp = session.post(url, data={
"cf-turnstile-response": token,
}, timeout=30)
return resp.json() if resp.status_code == 200 else None
Регулярный сбор данных по расписанию
Для ежедневного среза по списку тикеров используйте обёртку с паузами между запросами — так CAPTCHA срабатывает реже:
import csv
from datetime import datetime
def daily_market_snapshot(tickers, output_dir="data"):
"""Collect daily stock data, handling CAPTCHAs automatically."""
scraper = FinancialScraper(
proxy="http://user:[email protected]:5000"
)
date_str = datetime.now().strftime("%Y-%m-%d")
results = []
for ticker in tickers:
url = f"https://screener.example.com/quote.ashx?t={ticker}"
try:
data = scraper.scrape_screener(url)
if data:
results.extend(data)
time.sleep(2) # Rate limit
except Exception as e:
print(f"Error on {ticker}: {e}")
# Save to CSV
filepath = f"{output_dir}/market_{date_str}.csv"
with open(filepath, "w", newline="") as f:
writer = csv.DictWriter(f, fieldnames=["ticker", "company", "sector", "price", "change"])
writer.writeheader()
writer.writerows(results)
print(f"Saved {len(results)} records to {filepath}")
return results
# Run daily
tickers = ["AAPL", "GOOGL", "MSFT", "AMZN", "TSLA"]
daily_market_snapshot(tickers)
Диагностика типичных ошибок
| Проблема | Причина | Решение |
|---|---|---|
| 403 на SEC EDGAR | Нет User-Agent с email | Добавьте заголовок вида CompanyName email@domain |
| CAPTCHA на каждый запрос | Превышен лимит частоты запросов | Добавьте задержку 3–5 секунд между запросами |
| Устаревшие цены в ответе | Закэшированный ответ | Добавьте параметр запроса для сброса кеша |
| Ошибка парсинга JSON | Вместо данных вернулась страница с CAPTCHA | Проверяйте наличие CAPTCHA до парсинга ответа |
| IP заблокирован | Слишком много запросов с одного IP | Переключитесь на ротацию резидентных прокси |
Часто задаваемые вопросы
Сколько потоков нужно для сбора данных по одной бирже в реальном времени?
Для одного тикера в минуту обычно хватает 1–2 занятых потоков — reCAPTCHA v2 решается в пределах минуты, Cloudflare Turnstile заметно быстрее. Для параллельного опроса 20–30 тикеров закладывайте план STANDARD (15 потоков) или ADVANCE ($90/мес, 50 потоков) — с запасом на пиковые часы торгов.
Что делать, если ответ вместо JSON возвращает HTML-страницу с CAPTCHA?
Значит, защита сайта сработала раньше, чем вы ожидали. Проверяйте Content-Type и наличие data-sitekey в ответе до того, как передавать тело в JSON-парсер, — так вы отличите настоящий ответ API от страницы проверки и сразу отправите её на решение через CaptchaAI, вместо того чтобы ловить исключение парсинга.
Разрешено ли автоматически собирать данные SEC EDGAR и биржевые котировки?
Публичные данные — отчётность SEC, рыночные котировки — как правило, можно собирать, если вы соблюдаете условия обслуживания сайта и лимиты частоты запросов. SEC EDGAR прямо разрешает автоматический доступ для исследовательских целей при условии корректного User-Agent с контактным email.
Как часто можно опрашивать скринер акций, не вызывая CAPTCHA на каждый запрос?
Для цен акций — не чаще одного запроса в минуту в часы торгов. Для отчётности обычно достаточно раз в день. Более частый опрос заметно повышает шанс получить CAPTCHA на каждой странице.
Связанные руководства
- Почему браузерная автоматизация спотыкается там, где API работает
- Ротация резидентных прокси при решении CAPTCHA
Собирайте финансовые данные без остановок на CAPTCHA — оформите API-ключ CaptchaAI и автоматизируйте сбор рыночных данных.