368 lines
7.9 KiB
Markdown
368 lines
7.9 KiB
Markdown
|
|
# 🕷️ Universal Parser API
|
|||
|
|
|
|||
|
|
Универсальный API для парсинга любых сайтов с обходом защит (Cloudflare, WAF, антибот систем).
|
|||
|
|
|
|||
|
|
## 🚀 Возможности
|
|||
|
|
|
|||
|
|
- ✅ Обход Cloudflare, WAF, антибот систем
|
|||
|
|
- ✅ Рендеринг JavaScript (React, Vue, Angular)
|
|||
|
|
- ✅ Извлечение текста и HTML
|
|||
|
|
- ✅ Парсинг ссылок
|
|||
|
|
- ✅ Скриншоты страниц
|
|||
|
|
- ✅ API ключ для безопасности
|
|||
|
|
- ✅ Асинхронная обработка
|
|||
|
|
|
|||
|
|
## 📦 Установка
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# Установка зависимостей
|
|||
|
|
pip3 install --break-system-packages fastapi uvicorn playwright playwright-stealth
|
|||
|
|
|
|||
|
|
# Установка браузеров Playwright
|
|||
|
|
playwright install chromium
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 🔧 Запуск
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# Запуск API сервера
|
|||
|
|
python3 universal_parser_api.py
|
|||
|
|
|
|||
|
|
# Сервер запустится на http://localhost:8003
|
|||
|
|
# Документация: http://localhost:8003/docs
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 🔑 API Ключ
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
X-API-Key: parser_2025_secret_key_a8f3d9c1b4e7
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
⚠️ **В продакшене:** храни ключ в `.env` файле!
|
|||
|
|
|
|||
|
|
## 📡 Endpoints
|
|||
|
|
|
|||
|
|
### 1. POST /parse
|
|||
|
|
|
|||
|
|
Парсинг страницы с обходом защит.
|
|||
|
|
|
|||
|
|
**Параметры запроса:**
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"url": "https://example.com",
|
|||
|
|
"wait_seconds": 3, // Время ожидания после загрузки
|
|||
|
|
"extract_links": false, // Извлечь все ссылки
|
|||
|
|
"screenshot": false, // Сделать скриншот
|
|||
|
|
"javascript_enabled": true, // Включить JS
|
|||
|
|
"user_agent": null // Кастомный User-Agent (опционально)
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**Ответ:**
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"success": true,
|
|||
|
|
"url": "https://example.com",
|
|||
|
|
"status_code": 200,
|
|||
|
|
"title": "Example Domain",
|
|||
|
|
"html": "<html>...</html>",
|
|||
|
|
"text": "Example Domain\nThis domain is for...",
|
|||
|
|
"text_length": 1234,
|
|||
|
|
"links": ["https://...", "..."],
|
|||
|
|
"screenshot_base64": null,
|
|||
|
|
"parsing_time": 2.45,
|
|||
|
|
"timestamp": "2025-10-17T16:30:00",
|
|||
|
|
"error": null
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2. GET /health
|
|||
|
|
|
|||
|
|
Проверка статуса API.
|
|||
|
|
|
|||
|
|
**Ответ:**
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"status": "healthy",
|
|||
|
|
"version": "1.0.0",
|
|||
|
|
"timestamp": "2025-10-17T16:30:00"
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 💻 Примеры использования
|
|||
|
|
|
|||
|
|
### Python
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
import requests
|
|||
|
|
|
|||
|
|
API_URL = "http://localhost:8003"
|
|||
|
|
API_KEY = "parser_2025_secret_key_a8f3d9c1b4e7"
|
|||
|
|
|
|||
|
|
def parse_page(url):
|
|||
|
|
headers = {
|
|||
|
|
"X-API-Key": API_KEY,
|
|||
|
|
"Content-Type": "application/json"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
payload = {
|
|||
|
|
"url": url,
|
|||
|
|
"wait_seconds": 5,
|
|||
|
|
"extract_links": True
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
response = requests.post(
|
|||
|
|
f"{API_URL}/parse",
|
|||
|
|
headers=headers,
|
|||
|
|
json=payload
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
if response.status_code == 200:
|
|||
|
|
data = response.json()
|
|||
|
|
print(f"Статус: {data['status_code']}")
|
|||
|
|
print(f"Title: {data['title']}")
|
|||
|
|
print(f"Текст: {data['text'][:500]}")
|
|||
|
|
|
|||
|
|
return response.json()
|
|||
|
|
|
|||
|
|
# Использование
|
|||
|
|
result = parse_page("https://mos-sud.ru/...")
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### cURL
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
curl -X POST "http://localhost:8003/parse" \
|
|||
|
|
-H "X-API-Key: parser_2025_secret_key_a8f3d9c1b4e7" \
|
|||
|
|
-H "Content-Type: application/json" \
|
|||
|
|
-d '{
|
|||
|
|
"url": "https://example.com",
|
|||
|
|
"wait_seconds": 3,
|
|||
|
|
"extract_links": true
|
|||
|
|
}'
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### JavaScript
|
|||
|
|
|
|||
|
|
```javascript
|
|||
|
|
const parseUrl = async (url) => {
|
|||
|
|
const response = await fetch('http://localhost:8003/parse', {
|
|||
|
|
method: 'POST',
|
|||
|
|
headers: {
|
|||
|
|
'X-API-Key': 'parser_2025_secret_key_a8f3d9c1b4e7',
|
|||
|
|
'Content-Type': 'application/json'
|
|||
|
|
},
|
|||
|
|
body: JSON.stringify({
|
|||
|
|
url: url,
|
|||
|
|
wait_seconds: 3,
|
|||
|
|
extract_links: true
|
|||
|
|
})
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
const data = await response.json();
|
|||
|
|
console.log('Статус:', data.status_code);
|
|||
|
|
console.log('Title:', data.title);
|
|||
|
|
console.log('Текст:', data.text.substring(0, 500));
|
|||
|
|
|
|||
|
|
return data;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// Использование
|
|||
|
|
parseUrl('https://example.com');
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### PHP
|
|||
|
|
|
|||
|
|
```php
|
|||
|
|
<?php
|
|||
|
|
$url = "http://localhost:8003/parse";
|
|||
|
|
$api_key = "parser_2025_secret_key_a8f3d9c1b4e7";
|
|||
|
|
|
|||
|
|
$data = [
|
|||
|
|
"url" => "https://example.com",
|
|||
|
|
"wait_seconds" => 3,
|
|||
|
|
"extract_links" => true
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
$ch = curl_init($url);
|
|||
|
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
|||
|
|
curl_setopt($ch, CURLOPT_POST, true);
|
|||
|
|
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
|
|||
|
|
curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
|||
|
|
"X-API-Key: $api_key",
|
|||
|
|
"Content-Type: application/json"
|
|||
|
|
]);
|
|||
|
|
|
|||
|
|
$response = curl_exec($ch);
|
|||
|
|
$result = json_decode($response, true);
|
|||
|
|
|
|||
|
|
echo "Статус: " . $result['status_code'] . "\n";
|
|||
|
|
echo "Title: " . $result['title'] . "\n";
|
|||
|
|
|
|||
|
|
curl_close($ch);
|
|||
|
|
?>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 🧪 Тестирование
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# Запустить тестовый скрипт
|
|||
|
|
python3 test_parser_api.py
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 🔒 Безопасность
|
|||
|
|
|
|||
|
|
1. **API ключ в .env:**
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# .env
|
|||
|
|
PARSER_API_KEY=parser_2025_secret_key_a8f3d9c1b4e7
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
# В коде
|
|||
|
|
import os
|
|||
|
|
from dotenv import load_dotenv
|
|||
|
|
|
|||
|
|
load_dotenv()
|
|||
|
|
API_KEY = os.getenv("PARSER_API_KEY")
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
2. **Rate limiting** (добавить если нужно):
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
pip install slowapi
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
3. **HTTPS** (для продакшена):
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
uvicorn universal_parser_api:app --host 0.0.0.0 --port 8003 --ssl-keyfile key.pem --ssl-certfile cert.pem
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 🎯 Use Cases
|
|||
|
|
|
|||
|
|
### 1. Парсинг судебных сайтов
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
result = parse_page("https://mos-sud.ru/312/cases/...")
|
|||
|
|
case_number = extract_case_number(result['text'])
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2. Мониторинг сайтов
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
# Проверка изменений на сайте каждые 5 минут
|
|||
|
|
import schedule
|
|||
|
|
|
|||
|
|
def check_website():
|
|||
|
|
result = parse_page("https://target-site.com")
|
|||
|
|
if "ВАЖНОЕ ОБНОВЛЕНИЕ" in result['text']:
|
|||
|
|
send_notification()
|
|||
|
|
|
|||
|
|
schedule.every(5).minutes.do(check_website)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3. Сбор данных
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
# Парсинг списка отелей
|
|||
|
|
result = parse_page("https://booking-site.com", extract_links=True)
|
|||
|
|
hotel_links = [link for link in result['links'] if '/hotel/' in link]
|
|||
|
|
|
|||
|
|
for link in hotel_links:
|
|||
|
|
hotel_data = parse_page(link)
|
|||
|
|
save_to_database(hotel_data)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 📊 Производительность
|
|||
|
|
|
|||
|
|
- ⚡ Скорость: 2-5 секунд на страницу
|
|||
|
|
- 🔄 Параллельность: Поддерживает множественные запросы
|
|||
|
|
- 💾 Память: ~200MB на один браузер
|
|||
|
|
|
|||
|
|
## 🐛 Отладка
|
|||
|
|
|
|||
|
|
Логи сохраняются в `parser_api.log`:
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
tail -f parser_api.log
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 🚀 Production
|
|||
|
|
|
|||
|
|
### Запуск через systemd
|
|||
|
|
|
|||
|
|
```ini
|
|||
|
|
# /etc/systemd/system/parser-api.service
|
|||
|
|
[Unit]
|
|||
|
|
Description=Universal Parser API
|
|||
|
|
After=network.target
|
|||
|
|
|
|||
|
|
[Service]
|
|||
|
|
Type=simple
|
|||
|
|
User=www-data
|
|||
|
|
WorkingDirectory=/path/to/project
|
|||
|
|
ExecStart=/usr/bin/python3 universal_parser_api.py
|
|||
|
|
Restart=always
|
|||
|
|
|
|||
|
|
[Install]
|
|||
|
|
WantedBy=multi-user.target
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
sudo systemctl enable parser-api
|
|||
|
|
sudo systemctl start parser-api
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Docker
|
|||
|
|
|
|||
|
|
```dockerfile
|
|||
|
|
FROM python:3.12-slim
|
|||
|
|
|
|||
|
|
RUN apt-get update && apt-get install -y \
|
|||
|
|
wget \
|
|||
|
|
gnupg \
|
|||
|
|
&& rm -rf /var/lib/apt/lists/*
|
|||
|
|
|
|||
|
|
WORKDIR /app
|
|||
|
|
|
|||
|
|
COPY requirements.txt .
|
|||
|
|
RUN pip install --no-cache-dir -r requirements.txt
|
|||
|
|
RUN playwright install --with-deps chromium
|
|||
|
|
|
|||
|
|
COPY universal_parser_api.py .
|
|||
|
|
|
|||
|
|
EXPOSE 8003
|
|||
|
|
|
|||
|
|
CMD ["python3", "universal_parser_api.py"]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 📝 Примечания
|
|||
|
|
|
|||
|
|
- ⚠️ Соблюдай robots.txt и ToS сайтов
|
|||
|
|
- ⚠️ Используй rate limiting для больших объёмов
|
|||
|
|
- ⚠️ Некоторые сайты могут всё равно блокировать (требуется прокси)
|
|||
|
|
|
|||
|
|
## 🆘 Поддержка
|
|||
|
|
|
|||
|
|
Если API не работает:
|
|||
|
|
|
|||
|
|
1. Проверь логи: `tail -f parser_api.log`
|
|||
|
|
2. Проверь статус: `curl http://localhost:8003/health`
|
|||
|
|
3. Проверь API ключ
|
|||
|
|
4. Проверь порт 8003 (не занят ли)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
**Версия:** 1.0.0
|
|||
|
|
**Дата:** 17.10.2025
|
|||
|
|
**Автор:** Your Team
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
|