init server python để điều khiển adb
This commit is contained in:
@@ -0,0 +1,75 @@
|
|||||||
|
import uiautomator2 as u2
|
||||||
|
import time
|
||||||
|
import logging
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.INFO)
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
class ShopeeBot:
|
||||||
|
def __init__(self, device_ip: str = ""):
|
||||||
|
"""
|
||||||
|
Khởi tạo kết nối qua Wireless Debugging
|
||||||
|
:param device_ip: IP và Port của điện thoại. Nếu để trống, u2 sẽ tự kết nối thiết bị mặc định
|
||||||
|
"""
|
||||||
|
self.device_ip = device_ip
|
||||||
|
try:
|
||||||
|
if self.device_ip:
|
||||||
|
logger.info(f"Đang kết nối tới thiết bị {self.device_ip}...")
|
||||||
|
self.d = u2.connect(self.device_ip)
|
||||||
|
else:
|
||||||
|
logger.info("Đang tự động dò tìm thiết bị ADB đang kết nối...")
|
||||||
|
self.d = u2.connect()
|
||||||
|
|
||||||
|
logger.info(f"Kết nối thành công: {self.d.info}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Lỗi kết nối ADB: {e}")
|
||||||
|
raise
|
||||||
|
|
||||||
|
def get_commission(self, product_link: str) -> str:
|
||||||
|
"""
|
||||||
|
Mở Shopee, dán link và lấy phần trăm hoa hồng
|
||||||
|
"""
|
||||||
|
# 1. Khởi động app Shopee
|
||||||
|
logger.info("Mở ứng dụng Shopee...")
|
||||||
|
self.d.app_start("com.shopee.vn")
|
||||||
|
time.sleep(3) # Đợi app load, có thể tuỳ chỉnh
|
||||||
|
|
||||||
|
# 2. Bấm vào thanh tìm kiếm (Ví dụ thao tác cơ bản)
|
||||||
|
logger.info("Tìm thanh tìm kiếm...")
|
||||||
|
# Ở đây tôi dùng textContains, bạn cần dùng công cụ Weditor để điều chỉnh lại theo đúng giao diện
|
||||||
|
search_box = self.d(textContains="Tìm kiếm", className="android.widget.TextView")
|
||||||
|
if search_box.exists:
|
||||||
|
search_box.click()
|
||||||
|
time.sleep(1)
|
||||||
|
else:
|
||||||
|
logger.warning("Không tìm thấy thanh tìm kiếm ở trang hiện tại.")
|
||||||
|
|
||||||
|
# 3. Dán link và enter
|
||||||
|
logger.info("Đang dán link sản phẩm...")
|
||||||
|
# Ở màn hình nhập liệu, giả sử có một ô đang focus
|
||||||
|
try:
|
||||||
|
self.d(focused=True).set_text(product_link)
|
||||||
|
self.d.press("enter")
|
||||||
|
# Đợi Shopee load trang sản phẩm (mạng chậm cần chờ lâu hơn)
|
||||||
|
time.sleep(6)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Lỗi dán link: {e}")
|
||||||
|
|
||||||
|
# 4. Tìm và đọc text phần trăm hoa hồng
|
||||||
|
logger.info("Đang quét màn hình lấy hoa hồng...")
|
||||||
|
# LƯU Ý: Phần text/ID này phụ thuộc vào giao diện tài khoản Affiliate Shopee của bạn.
|
||||||
|
try:
|
||||||
|
# Ví dụ giả định Element chứa chữ hoa hồng:
|
||||||
|
commission_element = self.d(textContains="Hoa hồng")
|
||||||
|
|
||||||
|
if commission_element.exists:
|
||||||
|
# Lấy tất cả text của element đó (ví dụ "Hoa hồng: 15%")
|
||||||
|
commission_text = commission_element.get_text()
|
||||||
|
logger.info(f"Lấy thành công: {commission_text}")
|
||||||
|
return commission_text
|
||||||
|
else:
|
||||||
|
logger.error("Không tìm thấy thông tin hoa hồng trên màn hình.")
|
||||||
|
return "Không tìm thấy thông tin"
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Lỗi khi đọc dữ liệu màn hình: {e}")
|
||||||
|
return "Lỗi quét dữ liệu"
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
# Hướng dẫn đưa API lên Armbian (Sử dụng Wireless ADB)
|
||||||
|
|
||||||
|
Vì bạn sử dụng Wireless ADB, **server Armbian và điện thoại phải kết nối cùng chung một mạng nội bộ** (cùng kết nối vào một bộ định tuyến/WiFi).
|
||||||
|
|
||||||
|
### Bước 1: Cài đặt công cụ trên Armbian
|
||||||
|
Mở Terminal (hoặc SSH) vào Armbian và chạy lệnh:
|
||||||
|
```bash
|
||||||
|
sudo apt update
|
||||||
|
# Cài đặt Python 3, pip và công cụ nền tảng ADB
|
||||||
|
sudo apt install python3 python3-pip adb -y
|
||||||
|
```
|
||||||
|
|
||||||
|
### Bước 2: Bật và Kết nối ADB không dây
|
||||||
|
1. Trên điện thoại: Bật "Gỡ lỗi không dây" (Wireless Debugging) trong mục Tùy chọn nhà phát triển. Ghi lại IP và Port (ví dụ `192.168.1.55:5555`).
|
||||||
|
2. Trên Armbian, kiểm tra kết nối mạng:
|
||||||
|
```bash
|
||||||
|
ping -c 3 192.168.1.55
|
||||||
|
```
|
||||||
|
3. Kết nối ADB từ Armbian tới điện thoại:
|
||||||
|
```bash
|
||||||
|
adb connect 192.168.1.55:5555
|
||||||
|
```
|
||||||
|
*(Bạn có thể phải nhìn vào màn hình điện thoại để bấm "Cho phép" cho lần kết nối đầu tiên).*
|
||||||
|
|
||||||
|
### Bước 3: Triển khai Code
|
||||||
|
Copy toàn bộ thư mục `botAffilate` từ Windows sang Armbian (có thể dùng FileZilla, WinSCP). Di chuyển vào thư mục đó:
|
||||||
|
```bash
|
||||||
|
cd /path/to/botAffilate
|
||||||
|
pip3 install -r requirements.txt
|
||||||
|
```
|
||||||
|
*Lưu ý: Đừng quên cập nhật biến `DEVICE_IP` trong file `main.py` thành IP chính xác của điện thoại.*
|
||||||
|
|
||||||
|
### Bước 4: Chạy API ngầm bằng Systemd
|
||||||
|
Để API luôn chạy kể cả khi khởi động lại server Armbian, tạo một file cấu hình service:
|
||||||
|
```bash
|
||||||
|
sudo nano /etc/systemd/system/bot_shopee.service
|
||||||
|
```
|
||||||
|
|
||||||
|
Dán nội dung sau vào (Nhớ sửa lại `WorkingDirectory` bằng đường dẫn thực tế):
|
||||||
|
```ini
|
||||||
|
[Unit]
|
||||||
|
Description=Shopee Affiliate API cho n8n
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
User=root
|
||||||
|
# Thay đổi đường dẫn tới thư mục code của bạn
|
||||||
|
WorkingDirectory=/root/botAffilate
|
||||||
|
ExecStart=/usr/local/bin/uvicorn main:app --host 0.0.0.0 --port 8000
|
||||||
|
Restart=always
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
```
|
||||||
|
|
||||||
|
Kích hoạt và khởi động service:
|
||||||
|
```bash
|
||||||
|
sudo systemctl daemon-reload
|
||||||
|
sudo systemctl enable bot_shopee
|
||||||
|
sudo systemctl start bot_shopee
|
||||||
|
```
|
||||||
|
Để xem log xem có lỗi không, bạn dùng lệnh: `sudo journalctl -u bot_shopee -f`
|
||||||
|
|
||||||
|
Bây giờ từ n8n, bạn chỉ cần tạo Webhook/HTTP Request bắn tới địa chỉ `http://<IP_Armbian>:8000/get_commission` là xong!
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
from fastapi import FastAPI, HTTPException
|
||||||
|
from pydantic import BaseModel, Field
|
||||||
|
from automation import ShopeeBot
|
||||||
|
from typing import Optional
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
|
||||||
|
app = FastAPI(title="n8n Shopee Bridge API")
|
||||||
|
|
||||||
|
class CommissionRequest(BaseModel):
|
||||||
|
link: str
|
||||||
|
# Cho phép truyền IP linh hoạt từ n8n.
|
||||||
|
device_ip: Optional[str] = Field(default=None, description="IP:Port của điện thoại, ví dụ 192.168.1.100:5555 (WiFi) hoặc 10.8.0.5:5555 (VPN)")
|
||||||
|
|
||||||
|
@app.post("/get_commission")
|
||||||
|
async def get_commission_endpoint(req: CommissionRequest):
|
||||||
|
if not req.link:
|
||||||
|
raise HTTPException(status_code=400, detail="Thiếu link sản phẩm")
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Lấy IP theo độ ưu tiên:
|
||||||
|
# 1. Truyền từ Request Body của n8n
|
||||||
|
# 2. Truyền từ biến môi trường DEVICE_IP của Armbian/Windows
|
||||||
|
# 3. Để rỗng "" (Thư viện u2 sẽ tự tìm thiết bị ADB đang cắm/connect)
|
||||||
|
target_ip = req.device_ip or os.environ.get("DEVICE_IP") or ""
|
||||||
|
|
||||||
|
bot = ShopeeBot(device_ip=target_ip)
|
||||||
|
|
||||||
|
result = bot.get_commission(req.link)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"status": "success",
|
||||||
|
"link": req.link,
|
||||||
|
"commission": result,
|
||||||
|
"connected_ip": target_ip if target_ip else "auto-detect"
|
||||||
|
}
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(f"Lỗi API: {str(e)}")
|
||||||
|
raise HTTPException(status_code=500, detail=str(e))
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import uvicorn
|
||||||
|
# Chạy server API ở cổng 8000
|
||||||
|
uvicorn.run(app, host="0.0.0.0", port=8000)
|
||||||
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user