登录任务增加代理切换次数设置
- 后端: LoginBatchRequest 增加 max_proxy_retries 字段,默认10,0=无限 - 核心: DouyuLogin 极验验证循环根据 max_proxy_retries 控制重试 - 前端: 筛选栏增加代理切换次数输入框,Tooltip 提示0=无限切换直到成功 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
bc40d334b9
commit
2b8716cf72
+13
-3
@@ -61,11 +61,13 @@ class DouyuLogin:
|
|||||||
proxy_api_url: Optional[str] = None,
|
proxy_api_url: Optional[str] = None,
|
||||||
timeout: tuple[float, float] = REQUEST_TIMEOUT,
|
timeout: tuple[float, float] = REQUEST_TIMEOUT,
|
||||||
max_geetest_retries: int = 5,
|
max_geetest_retries: int = 5,
|
||||||
|
max_proxy_retries: int = 10,
|
||||||
):
|
):
|
||||||
self.account = account
|
self.account = account
|
||||||
self.proxy = proxy
|
self.proxy = proxy
|
||||||
self.timeout = timeout
|
self.timeout = timeout
|
||||||
self.max_geetest_retries = max_geetest_retries
|
self.max_geetest_retries = max_geetest_retries
|
||||||
|
self.max_proxy_retries = max_proxy_retries # 0=无限切换直到成功
|
||||||
self.session = requests.Session()
|
self.session = requests.Session()
|
||||||
|
|
||||||
# 初始化代理管理器
|
# 初始化代理管理器
|
||||||
@@ -317,9 +319,15 @@ class DouyuLogin:
|
|||||||
"""
|
"""
|
||||||
logger.info("开始极验 fullpage 验证...")
|
logger.info("开始极验 fullpage 验证...")
|
||||||
|
|
||||||
for attempt in range(self.max_geetest_retries):
|
# max_proxy_retries=0 表示无限重试直到成功
|
||||||
|
max_attempts = self.max_proxy_retries if self.max_proxy_retries > 0 else 999999
|
||||||
|
|
||||||
|
for attempt in range(max_attempts):
|
||||||
try:
|
try:
|
||||||
logger.info(f"极验验证尝试 {attempt + 1}/{self.max_geetest_retries}")
|
if self.max_proxy_retries > 0:
|
||||||
|
logger.info(f"极验验证尝试 {attempt + 1}/{max_attempts}")
|
||||||
|
else:
|
||||||
|
logger.info(f"极验验证尝试 {attempt + 1} (无限重试)")
|
||||||
|
|
||||||
# 按斗鱼登录页 HAR:fullpage 智能检测流程,不进入图片滑块。
|
# 按斗鱼登录页 HAR:fullpage 智能检测流程,不进入图片滑块。
|
||||||
str_16 = _generate_seed()
|
str_16 = _generate_seed()
|
||||||
@@ -372,7 +380,9 @@ class DouyuLogin:
|
|||||||
time.sleep(2)
|
time.sleep(2)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
raise ValueError(f"极验验证失败,已重试 {self.max_geetest_retries} 次")
|
if self.max_proxy_retries > 0:
|
||||||
|
raise ValueError(f"极验验证失败,已重试 {max_attempts} 次")
|
||||||
|
raise ValueError("极验验证失败(无限重试模式仍未能通过)")
|
||||||
|
|
||||||
def _second_login(self, gt: str, challenge: str, validate: str,
|
def _second_login(self, gt: str, challenge: str, validate: str,
|
||||||
seccode: str, code_token: str) -> str:
|
seccode: str, code_token: str) -> str:
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ async def create_batch(
|
|||||||
created_by=current.id,
|
created_by=current.id,
|
||||||
creator_role=current.role,
|
creator_role=current.role,
|
||||||
max_geetest_retries=req.max_geetest_retries,
|
max_geetest_retries=req.max_geetest_retries,
|
||||||
|
max_proxy_retries=req.max_proxy_retries,
|
||||||
proxy_config=proxy,
|
proxy_config=proxy,
|
||||||
log_queue=log_queue,
|
log_queue=log_queue,
|
||||||
loop=loop,
|
loop=loop,
|
||||||
|
|||||||
@@ -125,6 +125,7 @@ class AccountOut(BaseModel):
|
|||||||
class LoginBatchRequest(BaseModel):
|
class LoginBatchRequest(BaseModel):
|
||||||
account_ids: list[int]
|
account_ids: list[int]
|
||||||
max_geetest_retries: int = 5
|
max_geetest_retries: int = 5
|
||||||
|
max_proxy_retries: int = 10 # 代理切换次数,0=无限切换直到成功
|
||||||
concurrency: int = 3 # 并发数,1-10
|
concurrency: int = 3 # 并发数,1-10
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ class LoginBatchRunner:
|
|||||||
created_by: int,
|
created_by: int,
|
||||||
creator_role: str,
|
creator_role: str,
|
||||||
max_geetest_retries: int = 5,
|
max_geetest_retries: int = 5,
|
||||||
|
max_proxy_retries: int = 10,
|
||||||
proxy_config: Optional[ProxyConfigModel] = None,
|
proxy_config: Optional[ProxyConfigModel] = None,
|
||||||
log_queue: Optional[asyncio.Queue] = None,
|
log_queue: Optional[asyncio.Queue] = None,
|
||||||
loop: Optional[asyncio.AbstractEventLoop] = None,
|
loop: Optional[asyncio.AbstractEventLoop] = None,
|
||||||
@@ -36,6 +37,7 @@ class LoginBatchRunner:
|
|||||||
self.created_by = created_by
|
self.created_by = created_by
|
||||||
self.creator_role = creator_role
|
self.creator_role = creator_role
|
||||||
self.max_geetest_retries = max_geetest_retries
|
self.max_geetest_retries = max_geetest_retries
|
||||||
|
self.max_proxy_retries = max_proxy_retries
|
||||||
self.proxy_config = proxy_config
|
self.proxy_config = proxy_config
|
||||||
self.log_queue = log_queue
|
self.log_queue = log_queue
|
||||||
self.loop = loop
|
self.loop = loop
|
||||||
@@ -126,6 +128,7 @@ class LoginBatchRunner:
|
|||||||
account,
|
account,
|
||||||
proxy=proxy_dict,
|
proxy=proxy_dict,
|
||||||
max_geetest_retries=self.max_geetest_retries,
|
max_geetest_retries=self.max_geetest_retries,
|
||||||
|
max_proxy_retries=self.max_proxy_retries,
|
||||||
)
|
)
|
||||||
result = loginer.login()
|
result = loginer.login()
|
||||||
|
|
||||||
|
|||||||
@@ -56,8 +56,8 @@ export const accountApi = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const loginApi = {
|
export const loginApi = {
|
||||||
createBatch: (account_ids: number[], max_geetest_retries?: number, concurrency?: number) =>
|
createBatch: (account_ids: number[], max_geetest_retries?: number, concurrency?: number, max_proxy_retries?: number) =>
|
||||||
api.post<any, any>('/login/batch', { account_ids, max_geetest_retries, concurrency }),
|
api.post<any, any>('/login/batch', { account_ids, max_geetest_retries, concurrency, max_proxy_retries }),
|
||||||
listTasks: (batch_id?: string) =>
|
listTasks: (batch_id?: string) =>
|
||||||
api.get<any, any[]>('/login/tasks', { params: batch_id ? { batch_id } : {} }),
|
api.get<any, any[]>('/login/tasks', { params: batch_id ? { batch_id } : {} }),
|
||||||
stop: (batch_id: string) => api.post<any, any>(`/login/stop/${batch_id}`),
|
stop: (batch_id: string) => api.post<any, any>(`/login/stop/${batch_id}`),
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { useEffect, useState, useRef, useMemo, useCallback } from 'react';
|
|||||||
import {
|
import {
|
||||||
Table, Button, Select, message, Tag, Space, Spin, InputNumber, Tooltip, Popconfirm, theme,
|
Table, Button, Select, message, Tag, Space, Spin, InputNumber, Tooltip, Popconfirm, theme,
|
||||||
} from 'antd';
|
} from 'antd';
|
||||||
import { PlayCircleOutlined, StopOutlined, FilterOutlined, ThunderboltOutlined, ReloadOutlined, DownOutlined, UpOutlined, DeleteOutlined } from '@ant-design/icons';
|
import { PlayCircleOutlined, StopOutlined, FilterOutlined, ThunderboltOutlined, ReloadOutlined, DownOutlined, UpOutlined, DeleteOutlined, SwapOutlined } from '@ant-design/icons';
|
||||||
import { accountApi, loginApi } from '../api/modules';
|
import { accountApi, loginApi } from '../api/modules';
|
||||||
import { getUser, hasPerm } from '../store/auth';
|
import { getUser, hasPerm } from '../store/auth';
|
||||||
import { formatTime } from '../utils/time';
|
import { formatTime } from '../utils/time';
|
||||||
@@ -33,6 +33,7 @@ export default function LoginTasksPage() {
|
|||||||
const [wsConnected, setWsConnected] = useState(false);
|
const [wsConnected, setWsConnected] = useState(false);
|
||||||
const [selectedTags, setSelectedTags] = useState<string[]>([]);
|
const [selectedTags, setSelectedTags] = useState<string[]>([]);
|
||||||
const [concurrency, setConcurrency] = useState(3);
|
const [concurrency, setConcurrency] = useState(3);
|
||||||
|
const [maxProxyRetries, setMaxProxyRetries] = useState(10);
|
||||||
const [logVisible, setLogVisible] = useState(true);
|
const [logVisible, setLogVisible] = useState(true);
|
||||||
const [selectedRowKeys, setSelectedRowKeys] = useState<number[]>([]);
|
const [selectedRowKeys, setSelectedRowKeys] = useState<number[]>([]);
|
||||||
const wsRef = useRef<WebSocket | null>(null);
|
const wsRef = useRef<WebSocket | null>(null);
|
||||||
@@ -134,7 +135,7 @@ export default function LoginTasksPage() {
|
|||||||
setLoading(true);
|
setLoading(true);
|
||||||
setLogs([]);
|
setLogs([]);
|
||||||
try {
|
try {
|
||||||
const result = await loginApi.createBatch(accountIds, 5, concurrency);
|
const result = await loginApi.createBatch(accountIds, 5, concurrency, maxProxyRetries);
|
||||||
setBatchId(result.batch_id);
|
setBatchId(result.batch_id);
|
||||||
message.success(`已创建登录任务,共 ${result.count} 个账号`);
|
message.success(`已创建登录任务,共 ${result.count} 个账号`);
|
||||||
|
|
||||||
@@ -346,6 +347,19 @@ export default function LoginTasksPage() {
|
|||||||
/>
|
/>
|
||||||
</Space>
|
</Space>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
<Tooltip title="代理切换次数,0=无限切换直到成功">
|
||||||
|
<Space size={4}>
|
||||||
|
<SwapOutlined style={{ color: token.colorTextSecondary }} />
|
||||||
|
<InputNumber
|
||||||
|
min={0}
|
||||||
|
max={999}
|
||||||
|
value={maxProxyRetries}
|
||||||
|
onChange={(v) => setMaxProxyRetries(v ?? 10)}
|
||||||
|
style={{ width: 55 }}
|
||||||
|
size="small"
|
||||||
|
/>
|
||||||
|
</Space>
|
||||||
|
</Tooltip>
|
||||||
<Button
|
<Button
|
||||||
type="primary"
|
type="primary"
|
||||||
icon={<PlayCircleOutlined />}
|
icon={<PlayCircleOutlined />}
|
||||||
|
|||||||
Reference in New Issue
Block a user