v0.6.14: Ubuntu Docker performance optimization for Ohli24
This commit is contained in:
@@ -9,6 +9,7 @@ import sys
|
||||
import json
|
||||
import os
|
||||
import time
|
||||
import traceback
|
||||
from typing import Dict, Any, Optional
|
||||
|
||||
# 봇사우루스 디버깅 일시정지 방지 및 자동 종료 설정
|
||||
@@ -16,19 +17,22 @@ os.environ["BOTASAURUS_ENV"] = "production"
|
||||
|
||||
def fetch_html(url: str, headers: Optional[Dict[str, str]] = None, proxy: Optional[str] = None) -> Dict[str, Any]:
|
||||
result: Dict[str, Any] = {"success": False, "html": "", "elapsed": 0}
|
||||
start_time: float = time.time()
|
||||
max_retries = 2
|
||||
|
||||
try:
|
||||
from botasaurus.request import request as b_request
|
||||
|
||||
# raise_exception=True는 에러 시 exception을 발생시키게 함
|
||||
# close_on_crash=True는 에러 발생 시 대기하지 않고 즉시 종료 (배포 환경용)
|
||||
@b_request(proxy=proxy, raise_exception=True, close_on_crash=True)
|
||||
# use_stealth=True 추가하여 탐지 회피 강화
|
||||
@b_request(
|
||||
proxy=proxy,
|
||||
raise_exception=True,
|
||||
close_on_crash=True
|
||||
)
|
||||
def fetch_url(request: Any, data: Dict[str, Any]) -> str:
|
||||
target_url = data.get('url')
|
||||
headers = data.get('headers') or {}
|
||||
|
||||
# 기본적인 헤더 보강 (Ohli24 대응 - Cloudflare 우회 시도)
|
||||
# 기본적인 헤더 보강 (Ohli24 대응 - Cloudflare/TLS Fingerprinting 대응)
|
||||
default_headers = {
|
||||
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
|
||||
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
|
||||
@@ -50,37 +54,69 @@ def fetch_html(url: str, headers: Optional[Dict[str, str]] = None, proxy: Option
|
||||
if k not in headers and k.lower() not in [hk.lower() for hk in headers]:
|
||||
headers[k] = v
|
||||
|
||||
return request.get(target_url, headers=headers, timeout=30)
|
||||
return request.get(target_url, headers=headers, timeout=20)
|
||||
|
||||
# 봇사우루스는 실패 시 자동 재시도 등을 하기도 함.
|
||||
# 여기서는 단발성 요청이므로 직접 호출.
|
||||
b_resp: str = fetch_url({'url': url, 'headers': headers})
|
||||
elapsed: float = time.time() - start_time
|
||||
|
||||
if b_resp and len(b_resp) > 10:
|
||||
result.update({
|
||||
"success": True,
|
||||
"html": b_resp,
|
||||
"elapsed": round(elapsed, 2)
|
||||
})
|
||||
else:
|
||||
result["error"] = f"Short response: {len(b_resp) if b_resp else 0} bytes"
|
||||
result["elapsed"] = round(elapsed, 2)
|
||||
|
||||
for attempt in range(max_retries + 1):
|
||||
start_time = time.time()
|
||||
try:
|
||||
b_resp: str = fetch_url({'url': url, 'headers': headers})
|
||||
elapsed = time.time() - start_time
|
||||
|
||||
# 리스트 페이지는 보통 수백KB 이상 (최소 500바이트 체크)
|
||||
if b_resp and len(b_resp) > 500:
|
||||
result.update({
|
||||
"success": True,
|
||||
"html": b_resp,
|
||||
"elapsed": round(elapsed, 2),
|
||||
"attempt": attempt + 1
|
||||
})
|
||||
return result
|
||||
else:
|
||||
reason = f"Short response ({len(b_resp) if b_resp else 0} bytes)"
|
||||
if attempt < max_retries:
|
||||
time.sleep(1)
|
||||
continue
|
||||
result["error"] = reason
|
||||
result["elapsed"] = round(time.time() - start_time, 2)
|
||||
except Exception as inner_e:
|
||||
if attempt < max_retries:
|
||||
time.sleep(1)
|
||||
continue
|
||||
result["error"] = str(inner_e)
|
||||
result["elapsed"] = round(time.time() - start_time, 2)
|
||||
|
||||
except Exception as e:
|
||||
result["error"] = str(e)
|
||||
result["elapsed"] = round(time.time() - start_time, 2)
|
||||
result["error"] = f"Botasaurus init/import error: {str(e)}"
|
||||
result["elapsed"] = 0
|
||||
|
||||
return result
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) < 2:
|
||||
print(json.dumps({"success": False, "error": "Usage: python botasaurus_ohli24.py <url> [headers_json] [proxy]"}))
|
||||
sys.exit(1)
|
||||
# 모든 stdout을 stderr로 리다이렉트 (라이브러리 로그가 stdout을 오염시키는 것 방지)
|
||||
original_stdout = sys.stdout
|
||||
sys.stdout = sys.stderr
|
||||
|
||||
target_url: str = sys.argv[1]
|
||||
headers_arg: Optional[Dict[str, str]] = json.loads(sys.argv[2]) if len(sys.argv) > 2 and sys.argv[2] else None
|
||||
proxy_arg: Optional[str] = sys.argv[3] if len(sys.argv) > 3 and sys.argv[3] else None
|
||||
|
||||
res: Dict[str, Any] = fetch_html(target_url, headers_arg, proxy_arg)
|
||||
print(json.dumps(res, ensure_ascii=False))
|
||||
try:
|
||||
if len(sys.argv) < 2:
|
||||
# 에러 메시지는 출력해야 하므로 다시 복구 후 출력
|
||||
sys.stdout = original_stdout
|
||||
print(json.dumps({"success": False, "error": "Usage: script.py <url> [headers] [proxy]"}))
|
||||
sys.exit(1)
|
||||
|
||||
target_url: str = sys.argv[1]
|
||||
headers_arg: Optional[Dict[str, str]] = json.loads(sys.argv[2]) if len(sys.argv) > 2 and sys.argv[2] else None
|
||||
proxy_arg: Optional[str] = sys.argv[3] if len(sys.argv) > 3 and sys.argv[3] else None
|
||||
|
||||
res: Dict[str, Any] = fetch_html(target_url, headers_arg, proxy_arg)
|
||||
|
||||
# 최종 결과 출력 전에만 stdout 복구
|
||||
sys.stdout = original_stdout
|
||||
print(json.dumps(res, ensure_ascii=False))
|
||||
except Exception as fatal_e:
|
||||
# 에러 발생 시에도 JSON 형태로 출력하도록 보장
|
||||
sys.stdout = original_stdout
|
||||
print(json.dumps({
|
||||
"success": False,
|
||||
"error": f"Fatal execution error: {str(fatal_e)}",
|
||||
"traceback": traceback.format_exc()
|
||||
}, ensure_ascii=False))
|
||||
|
||||
Reference in New Issue
Block a user