Cổng tài chính bảo vệ báo giá cổ phiếu, dữ liệu thu nhập và báo cáo phân tích bằng Cloudflare Turnstile và reCAPTCHA. CAPTCHA kích hoạt trong quá trình tra cứu ký hiệu nhanh chóng, tải xuống dữ liệu lịch sử và truy vấn sàng lọc. Đây là cách duy trì việc thu thập dữ liệu đáng tin cậy trên các trang web tài chính.
Các mẫu CAPTCHA trên cổng tài chính
| Kiểu dữ liệu | Ví dụ về cổng thông tin | loại CAPTCHA | Trình kích hoạt |
|---|---|---|---|
| Báo giá thời gian thực | Cổng thông tin tài chính | Cloudflare Turnstile | Tra cứu biểu tượng nhanh chóng |
| Giá lịch sử | Nhà cung cấp dữ liệu | reCAPTCHA v2 | Tải xuống CSV hàng loạt |
| Báo cáo tài chính | Địa điểm nộp hồ sơ của SEC | CAPTCHA hình ảnh | Truy vấn EDGAR lặp đi lặp lại |
| Kết quả sàng lọc | Máy sàng lọc cổ phiếu | Cloudflare Challenge | Truy vấn bộ lọc phức tạp |
| Xếp hạng của nhà phân tích | Cổng nghiên cứu | reCAPTCHA v3 | Nhiều lượt xem trang |
Người thu thập dữ liệu chứng khoán
import requests
import time
import re
from datetime import datetime, timedelta
class StockDataCollector:
def __init__(self, api_key):
self.api_key = api_key
self.session = requests.Session()
self.session.headers.update({
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
})
def get_quote(self, portal_url, symbol):
"""Get current stock quote, solving CAPTCHAs if needed."""
url = f"{portal_url}/quote/{symbol}"
response = self.session.get(url)
if self._is_captcha_page(response):
response = self._solve_and_retry(response, url)
return self._parse_quote(response.text, symbol)
def get_historical(self, portal_url, symbol, days=365):
"""Download historical price data."""
url = f"{portal_url}/history/{symbol}"
params = {
"period": f"{days}d",
"interval": "1d"
}
response = self.session.get(url, params=params)
if self._is_captcha_page(response):
response = self._solve_and_retry(response, url)
return self._parse_historical(response.text)
def scan_symbols(self, portal_url, symbols, delay=2):
"""Collect quotes for multiple symbols."""
results = {}
for symbol in symbols:
try:
results[symbol] = self.get_quote(portal_url, symbol)
time.sleep(delay)
except Exception as e:
results[symbol] = {"error": str(e)}
return results
def _is_captcha_page(self, response):
return (
response.status_code == 403 or
"cf-turnstile" in response.text or
"challenges.cloudflare.com" in response.text
)
def _solve_and_retry(self, response, url):
match = re.search(r'data-sitekey="(0x[^"]+)"', response.text)
if not match:
# Fall back to reCAPTCHA detection
match = re.search(r'data-sitekey="([^"]+)"', response.text)
if match:
return self._solve_recaptcha_and_retry(match.group(1), url)
raise ValueError("No CAPTCHA sitekey found")
resp = requests.post("https://ocr.captchaai.com/in.php", data={
"key": self.api_key,
"method": "turnstile",
"sitekey": match.group(1),
"pageurl": url,
"json": 1
})
task_id = resp.json()["request"]
for _ in range(60):
time.sleep(3)
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": self.api_key,
"action": "get",
"id": task_id,
"json": 1
})
data = result.json()
if data["status"] == 1:
return self.session.post(url, data={
"cf-turnstile-response": data["request"]
})
raise TimeoutError("CAPTCHA solve timed out")
def _solve_recaptcha_and_retry(self, site_key, url):
resp = requests.post("https://ocr.captchaai.com/in.php", data={
"key": self.api_key,
"method": "userrecaptcha",
"googlekey": site_key,
"pageurl": url,
"json": 1
})
task_id = resp.json()["request"]
for _ in range(60):
time.sleep(3)
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": self.api_key,
"action": "get",
"id": task_id,
"json": 1
})
data = result.json()
if data["status"] == 1:
return self.session.post(url, data={
"g-recaptcha-response": data["request"]
})
raise TimeoutError("reCAPTCHA solve timed out")
def _parse_quote(self, html, symbol):
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, "html.parser")
def text_or_none(node):
return node.text.strip() if node and node.text else None
return {
"symbol": symbol,
"price": text_or_none(soup.select_one("[data-field='regularMarketPrice'], .price")),
"change": text_or_none(soup.select_one("[data-field='regularMarketChange'], .change")),
"volume": text_or_none(soup.select_one("[data-field='regularMarketVolume'], .volume")),
"market_cap": text_or_none(soup.select_one("[data-field='marketCap'], .market-cap")),
"timestamp": datetime.now().isoformat()
}
def _parse_historical(self, html):
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, "html.parser")
rows = []
for row in soup.select("table tr")[1:]: # Skip header
cells = [td.text.strip() for td in row.select("td")]
if len(cells) >= 6:
rows.append({
"date": cells[0],
"open": cells[1],
"high": cells[2],
"low": cells[3],
"close": cells[4],
"volume": cells[5]
})
return rows
# Usage
collector = StockDataCollector("YOUR_API_KEY")
# Single quote
quote = collector.get_quote("https://finance.example.com", "AAPL")
print(f"AAPL: ${quote['price']} ({quote['change']})")
# Scan multiple symbols
portfolio = collector.scan_symbols(
"https://finance.example.com",
["AAPL", "GOOGL", "MSFT", "AMZN", "TSLA"]
)
Trình sàng lọc thị trường bằng cách xử lý CAPTCHA (JavaScript)
class MarketScreener {
constructor(apiKey) {
this.apiKey = apiKey;
}
async screenStocks(portalUrl, filters) {
const params = new URLSearchParams(filters);
const response = await fetch(`${portalUrl}/screener?${params}`);
const html = await response.text();
if (html.includes('cf-turnstile') || response.status === 403) {
return this.solveAndScreen(portalUrl, filters, html);
}
return this.parseScreenerResults(html);
}
async solveAndScreen(portalUrl, filters, html) {
const match = html.match(/data-sitekey="(0x[^"]+)"/);
if (!match) throw new Error('Turnstile sitekey not found');
const submitResp = await fetch('https://ocr.captchaai.com/in.php', {
method: 'POST',
body: new URLSearchParams({
key: this.apiKey,
method: 'turnstile',
sitekey: match[1],
pageurl: portalUrl,
json: '1'
})
});
const { request: taskId } = await submitResp.json();
for (let i = 0; i < 60; i++) {
await new Promise(r => setTimeout(r, 3000));
const result = await fetch(
`https://ocr.captchaai.com/res.php?key=${this.apiKey}&action=get&id=${taskId}&json=1`
);
const data = await result.json();
if (data.status === 1) {
const response = await fetch(`${portalUrl}/screener`, {
method: 'POST',
body: new URLSearchParams({
...filters,
'cf-turnstile-response': data.request
})
});
return this.parseScreenerResults(await response.text());
}
}
throw new Error('Turnstile solve timed out');
}
parseScreenerResults(html) {
const rows = [];
const tableMatch = html.match(/<table[^>]*>[\s\S]*?<\/table>/i);
if (!tableMatch) return rows;
const rowMatches = tableMatch[0].matchAll(/<tr[^>]*>([\s\S]*?)<\/tr>/gi);
for (const row of rowMatches) {
const cells = [...row[1].matchAll(/<td[^>]*>([\s\S]*?)<\/td>/gi)]
.map(m => m[1].replace(/<[^>]+>/g, '').trim());
if (cells.length >= 4) {
rows.push({
symbol: cells[0],
price: cells[1],
change: cells[2],
volume: cells[3]
});
}
}
return rows;
}
}
// Usage
const screener = new MarketScreener('YOUR_API_KEY');
const results = await screener.screenStocks('https://finance.example.com', {
sector: 'technology',
marketCap: 'large',
peRatio: '<25'
});
Tần suất thu thập theo loại dữ liệu
| Kiểu dữ liệu | Khoảng thời gian được đề xuất | tần số CAPTCHA |
|---|---|---|
| Báo giá thời gian thực | 1–5 phút | Cao – sử dụng API nếu có |
| Giá cuối ngày | Mỗi ngày một lần sau khi đóng cửa | Thấp |
| Báo cáo tài chính | Hàng quý | Tối thiểu |
| Kết quả sàng lọc | hàng ngày | Trung bình |
| Xếp hạng của nhà phân tích | hàng tuần | Thấp |
Khắc phục sự cố
| Vấn đề | Nguyên nhân | Cách xử lý |
|---|---|---|
| Cloudflare Turnstile theo mọi yêu cầu | Phiên mới mỗi lần | Cookie liên tục theo yêu cầu |
| Dữ liệu lịch sử không đầy đủ | Phân trang đằng sau CAPTCHA | Giải quyết trên mỗi trang, theo các liên kết được phân trang |
| Trích dẫn dữ liệu cũ | Đã phân phối phản hồi được lưu vào bộ nhớ đệm | Thêm tham số truy vấn chặn truy xuất bộ nhớ đệm |
| Giới hạn tỷ lệ 429 | Quá nhiều yêu cầu | Tăng độ trễ, xoay proxy |
Câu hỏi thường gặp
API tài chính có tốt hơn việc tìm kiếm bằng CAPTCHA không?
API miễn phí (như các cấp cơ bản của một số nhà cung cấp) bao gồm dữ liệu phổ biến nhưng có giới hạn tốc độ. Quét web bằng CaptchaAI cho phép truy cập vào dữ liệu không có sẵn thông qua API - bộ lọc sàng lọc, bình luận của nhà phân tích và dữ liệu tài chính thích hợp.
Làm cách nào để xử lý CAPTCHA trích dẫn theo thời gian thực mà không bị chậm trễ?
Xác thực trước phiên của bạn trong giờ thị trường. Cookie <staging-session-cookie> của Cloudflare tồn tại trong 15–30 phút, vì vậy hãy giải quyết một lần và thực hiện nhiều yêu cầu trong khoảng thời gian đó.
Tôi có thể thu thập dữ liệu từ nhiều cổng tài chính cùng một lúc không?
Vâng. Sử dụng các phiên riêng biệt cho mỗi cổng thông tin với các lần gửi tác vụ CaptchaAI độc lập. CaptchaAI xử lý việc giải quyết đồng thời trên các trang web khác nhau.
bài viết liên quan
- Thu thập dữ liệu nghiên cứu thị trường
- So sánh Geetest và Cloudflare Turnstile
- Cloudflare Turnstile 403 Sau khi sửa mã thông báo
Các bước tiếp theo
Thu thập dữ liệu thị trường một cách đáng tin cậy —lấy khóa API CaptchaAI của bạnvà tự động xử lý CAPTCHA của cổng tài chính.