commit 31b02d9db3eba2e7767257283ae7465b83e682ad Author: fuzhongyun <15339891972@163.com> Date: Fri Mar 27 18:18:06 2026 +0800 first diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..77d10b0 --- /dev/null +++ b/Dockerfile @@ -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"] + diff --git a/capture_fingerprint.py b/capture_fingerprint.py new file mode 100644 index 0000000..ba41fbd --- /dev/null +++ b/capture_fingerprint.py @@ -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()) + diff --git a/deploy.sh b/deploy.sh new file mode 100755 index 0000000..b6f1a1d --- /dev/null +++ b/deploy.sh @@ -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 + diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..2168b19 --- /dev/null +++ b/docker-compose.yml @@ -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 + diff --git a/main.py b/main.py new file mode 100644 index 0000000..2c4d8ef --- /dev/null +++ b/main.py @@ -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) + diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..27954a0 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,3 @@ +playwright>=1.40.0 +fastapi>=0.109.0 +uvicorn>=0.27.0