first
This commit is contained in:
commit
31b02d9db3
|
|
@ -0,0 +1,13 @@
|
||||||
|
FROM mcr.microsoft.com/playwright/python:v1.51.0-jammy
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY requirements.txt .
|
||||||
|
RUN pip install --no-cache-dir -r requirements.txt
|
||||||
|
|
||||||
|
COPY main.py .
|
||||||
|
|
||||||
|
EXPOSE 8000
|
||||||
|
|
||||||
|
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
|
||||||
|
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
import asyncio
|
||||||
|
from playwright.async_api import async_playwright
|
||||||
|
|
||||||
|
TARGET_PAGE = "https://gd.10086.cn/gdshop/qdxsd/index.html#/gd-fls/marketingActivity/index?id=1956241557401346048"
|
||||||
|
TARGET_API = "https://gd.10086.cn/gdshop/apigw/adv/ad/getInsertCode"
|
||||||
|
FINGERPRINT_HEADER = "x-device-fingerprint"
|
||||||
|
|
||||||
|
|
||||||
|
async def capture_fingerprint():
|
||||||
|
async with async_playwright() as p:
|
||||||
|
browser = await p.chromium.launch(headless=True)
|
||||||
|
page = await browser.new_page()
|
||||||
|
|
||||||
|
fingerprint_future = asyncio.Future()
|
||||||
|
|
||||||
|
async def handle_request(request):
|
||||||
|
if TARGET_API in request.url and not fingerprint_future.done():
|
||||||
|
headers = request.headers
|
||||||
|
if FINGERPRINT_HEADER in headers:
|
||||||
|
fingerprint = headers[FINGERPRINT_HEADER]
|
||||||
|
fingerprint_future.set_result(fingerprint)
|
||||||
|
|
||||||
|
page.on("request", handle_request)
|
||||||
|
|
||||||
|
print(f"[信息] 正在打开页面...")
|
||||||
|
await page.goto(TARGET_PAGE, wait_until="networkidle")
|
||||||
|
|
||||||
|
try:
|
||||||
|
print(f"[信息] 等待指纹参数...")
|
||||||
|
fingerprint = await asyncio.wait_for(fingerprint_future, timeout=15)
|
||||||
|
print(f"\n{'='*60}")
|
||||||
|
print(f"[成功] 指纹参数捕获成功:")
|
||||||
|
print(f" {FINGERPRINT_HEADER}: {fingerprint}")
|
||||||
|
print(f"{'='*60}\n")
|
||||||
|
return fingerprint
|
||||||
|
except asyncio.TimeoutError:
|
||||||
|
print(f"\n{'='*60}")
|
||||||
|
print(f"[错误] 等待超时,未能捕获到 {FINGERPRINT_HEADER} 参数")
|
||||||
|
print(f"{'='*60}\n")
|
||||||
|
return None
|
||||||
|
finally:
|
||||||
|
await browser.close()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
asyncio.run(capture_fingerprint())
|
||||||
|
|
||||||
|
|
@ -0,0 +1,71 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
echo "========================================="
|
||||||
|
echo "广东移动指纹获取服务 - 部署脚本"
|
||||||
|
echo "========================================="
|
||||||
|
|
||||||
|
cd "$(dirname "$0")"
|
||||||
|
|
||||||
|
case "${1:-up}" in
|
||||||
|
up)
|
||||||
|
echo ""
|
||||||
|
echo "[1/3] 构建 Docker 镜像..."
|
||||||
|
docker-compose build
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "[2/3] 启动服务..."
|
||||||
|
docker-compose up -d
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "[3/3] 等待服务启动..."
|
||||||
|
sleep 5
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "========================================="
|
||||||
|
echo "部署完成!"
|
||||||
|
echo ""
|
||||||
|
echo "服务地址: http://localhost:8000"
|
||||||
|
echo "API 文档: http://localhost:8000/docs"
|
||||||
|
echo "健康检查: http://localhost:8000/health"
|
||||||
|
echo "获取指纹: http://localhost:8000/fingerprint"
|
||||||
|
echo ""
|
||||||
|
echo "查看日志: docker-compose logs -f"
|
||||||
|
echo "停止服务: docker-compose down"
|
||||||
|
echo "========================================="
|
||||||
|
;;
|
||||||
|
|
||||||
|
down)
|
||||||
|
echo ""
|
||||||
|
echo "停止服务..."
|
||||||
|
docker-compose down
|
||||||
|
echo "服务已停止"
|
||||||
|
;;
|
||||||
|
|
||||||
|
logs)
|
||||||
|
echo ""
|
||||||
|
echo "查看日志..."
|
||||||
|
docker-compose logs -f
|
||||||
|
;;
|
||||||
|
|
||||||
|
restart)
|
||||||
|
echo ""
|
||||||
|
echo "重启服务..."
|
||||||
|
docker-compose restart
|
||||||
|
echo "服务已重启"
|
||||||
|
;;
|
||||||
|
|
||||||
|
*)
|
||||||
|
echo ""
|
||||||
|
echo "用法: $0 [命令]"
|
||||||
|
echo ""
|
||||||
|
echo "命令:"
|
||||||
|
echo " up - 构建并启动服务(默认)"
|
||||||
|
echo " down - 停止服务"
|
||||||
|
echo " logs - 查看日志"
|
||||||
|
echo " restart - 重启服务"
|
||||||
|
echo ""
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
fingerprint-service:
|
||||||
|
build: .
|
||||||
|
container_name: gd10086-fingerprint-service
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "8000:8000"
|
||||||
|
environment:
|
||||||
|
- TZ=Asia/Shanghai
|
||||||
|
volumes:
|
||||||
|
- /dev/shm:/dev/shm
|
||||||
|
security_opt:
|
||||||
|
- seccomp=unconfined
|
||||||
|
|
||||||
|
|
@ -0,0 +1,94 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
import asyncio
|
||||||
|
from typing import Optional
|
||||||
|
from contextlib import asynccontextmanager
|
||||||
|
from fastapi import FastAPI, HTTPException
|
||||||
|
from playwright.async_api import async_playwright
|
||||||
|
|
||||||
|
TARGET_PAGE = "https://gd.10086.cn/gdshop/qdxsd/index.html#/gd-fls/marketingActivity/index?id=1956241557401346048"
|
||||||
|
TARGET_API = "https://gd.10086.cn/gdshop/apigw/adv/ad/getInsertCode"
|
||||||
|
FINGERPRINT_HEADER = "x-device-fingerprint"
|
||||||
|
|
||||||
|
playwright_instance = None
|
||||||
|
browser = None
|
||||||
|
|
||||||
|
|
||||||
|
@asynccontextmanager
|
||||||
|
async def lifespan(app: FastAPI):
|
||||||
|
global playwright_instance, browser
|
||||||
|
playwright_instance = await async_playwright().start()
|
||||||
|
browser = await playwright_instance.chromium.launch(
|
||||||
|
headless=True,
|
||||||
|
args=[
|
||||||
|
"--no-sandbox",
|
||||||
|
"--disable-setuid-sandbox",
|
||||||
|
"--disable-dev-shm-usage",
|
||||||
|
"--disable-software-rasterizer",
|
||||||
|
]
|
||||||
|
)
|
||||||
|
yield
|
||||||
|
await browser.close()
|
||||||
|
await playwright_instance.stop()
|
||||||
|
|
||||||
|
|
||||||
|
app = FastAPI(
|
||||||
|
title="广东移动指纹获取服务",
|
||||||
|
description="获取 x-device-fingerprint 参数的 API 服务",
|
||||||
|
version="1.0.0",
|
||||||
|
lifespan=lifespan
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def get_fingerprint() -> Optional[str]:
|
||||||
|
page = await browser.new_page()
|
||||||
|
try:
|
||||||
|
fingerprint_future = asyncio.Future()
|
||||||
|
|
||||||
|
async def handle_request(request):
|
||||||
|
if TARGET_API in request.url and not fingerprint_future.done():
|
||||||
|
headers = request.headers
|
||||||
|
if FINGERPRINT_HEADER in headers:
|
||||||
|
fingerprint_future.set_result(headers[FINGERPRINT_HEADER])
|
||||||
|
|
||||||
|
page.on("request", handle_request)
|
||||||
|
await page.goto(TARGET_PAGE, wait_until="networkidle")
|
||||||
|
fingerprint = await asyncio.wait_for(fingerprint_future, timeout=15)
|
||||||
|
return fingerprint
|
||||||
|
except asyncio.TimeoutError:
|
||||||
|
return None
|
||||||
|
finally:
|
||||||
|
await page.close()
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/")
|
||||||
|
async def root():
|
||||||
|
return {"status": "ok", "message": "广东移动指纹获取服务"}
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/health")
|
||||||
|
async def health():
|
||||||
|
return {"status": "healthy"}
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/fingerprint")
|
||||||
|
async def get_fingerprint_endpoint():
|
||||||
|
try:
|
||||||
|
fingerprint = await get_fingerprint()
|
||||||
|
if fingerprint:
|
||||||
|
return {
|
||||||
|
"status": "success",
|
||||||
|
"data": {
|
||||||
|
FINGERPRINT_HEADER: fingerprint
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
raise HTTPException(status_code=500, detail="获取指纹失败")
|
||||||
|
except Exception as e:
|
||||||
|
raise HTTPException(status_code=500, detail=f"服务错误: {str(e)}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import uvicorn
|
||||||
|
uvicorn.run(app, host="0.0.0.0", port=8000)
|
||||||
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
playwright>=1.40.0
|
||||||
|
fastapi>=0.109.0
|
||||||
|
uvicorn>=0.27.0
|
||||||
Loading…
Reference in New Issue