Spaces:
BG5
/
Running

BG5 commited on
Commit
409623d
·
verified ·
1 Parent(s): a9a7f50

Delete unibo_jetbrains_activation.py

Browse files
Files changed (1) hide show
  1. unibo_jetbrains_activation.py +0 -725
unibo_jetbrains_activation.py DELETED
@@ -1,725 +0,0 @@
1
- #!/usr/bin/env python
2
- # -*- coding: utf-8 -*-
3
-
4
- import os
5
- import re
6
- import time
7
- import random
8
- import sqlite3
9
- import threading
10
- import concurrent.futures
11
- from datetime import datetime
12
- from typing import Optional, Tuple, List, Dict, Any
13
-
14
- from loguru import logger
15
- from jetbrains import CaptchaSolver
16
- from 收发邮件 import EmailClient
17
-
18
- # 定义数据库状态常量
19
- STATUS_PENDING = 0 # 未提交
20
- STATUS_SUBMITTED = 1 # 已提交成功
21
- STATUS_FAILED = 2 # 提交失败
22
- STATUS_LINK_EXTRACTED = 3 # 已提取激活链接
23
-
24
- class DatabaseManager:
25
- """数据库操作类,处理SQLite数据库的所有操作"""
26
-
27
- def __init__(self, db_path: str = "unibo_jetbrains.db"):
28
- """初始化数据库连接和表结构
29
-
30
- Args:
31
- db_path: 数据库文件路径
32
- """
33
- self.db_path = db_path
34
- self.conn = None
35
- self.lock = threading.Lock() # 用于线程安全的数据库操作
36
- self._initialize_db()
37
-
38
- def _initialize_db(self) -> None:
39
- """初始化数据库,创建必要的表结构"""
40
- self.conn = sqlite3.connect(self.db_path, check_same_thread=False)
41
- cursor = self.conn.cursor()
42
-
43
- # 创建邮箱数据表
44
- cursor.execute('''
45
- CREATE TABLE IF NOT EXISTS accounts (
46
- id INTEGER PRIMARY KEY AUTOINCREMENT,
47
- register_time TEXT NOT NULL,
48
- username TEXT NOT NULL UNIQUE,
49
- password TEXT NOT NULL,
50
- security_email TEXT,
51
- status INTEGER DEFAULT 0,
52
- activation_link TEXT,
53
- updated_at TEXT,
54
- notes TEXT,
55
- used INTEGER DEFAULT 0 -- 新增字段,0未使用,1已使用
56
- )
57
- ''')
58
-
59
- # 创建日志表
60
- cursor.execute('''
61
- CREATE TABLE IF NOT EXISTS operation_logs (
62
- id INTEGER PRIMARY KEY AUTOINCREMENT,
63
- username TEXT NOT NULL,
64
- operation TEXT NOT NULL,
65
- status TEXT NOT NULL,
66
- message TEXT,
67
- created_at TEXT NOT NULL
68
- )
69
- ''')
70
-
71
- self.conn.commit()
72
- logger.info(f"数据库初始化完成: {self.db_path}")
73
-
74
- def __del__(self):
75
- """析构函数,确保数据库连接正确关闭"""
76
- if self.conn:
77
- self.conn.close()
78
-
79
- def import_from_file(self, filepath: str) -> int:
80
- """从文件导入账号数据
81
-
82
- Args:
83
- filepath: 包含账号数据的文件路径
84
-
85
- Returns:
86
- 导入的账号数量
87
- """
88
- count = 0
89
- try:
90
- with self.lock, open(filepath, 'r', encoding='utf-8') as file:
91
- cursor = self.conn.cursor()
92
-
93
- for line in file:
94
- parts = line.strip().split('---')
95
- if len(parts) >= 3: # 至少需要时间、用户名和密码
96
- register_time = parts[0]
97
- username = parts[1]
98
- password = parts[2]
99
- security_email = parts[3] if len(parts) > 3 else ""
100
- status = 0 # 默认为未提交状态
101
- activation_link = ""
102
-
103
- # 检查更多部分以确定状态和激活链接
104
- if len(parts) > 4 and "success" in parts[4].lower():
105
- status = STATUS_SUBMITTED
106
-
107
- if len(parts) > 5 and "http" in parts[5].lower():
108
- activation_link = parts[5]
109
- status = STATUS_LINK_EXTRACTED
110
-
111
- # 插入或更新数据库
112
- try:
113
- cursor.execute('''
114
- INSERT OR IGNORE INTO accounts
115
- (register_time, username, password, security_email, status, activation_link, updated_at)
116
- VALUES (?, ?, ?, ?, ?, ?, datetime('now', 'localtime'))
117
- ''', (register_time, username, password, security_email, status, activation_link))
118
-
119
- if cursor.rowcount > 0:
120
- count += 1
121
- except sqlite3.IntegrityError:
122
- logger.warning(f"账号已存在,跳过: {username}")
123
-
124
- self.conn.commit()
125
- logger.info(f"成功从{filepath}导入了{count}个账号")
126
- return count
127
- except Exception as e:
128
- logger.error(f"从文件导入账号时出错: {str(e)}")
129
- return 0
130
-
131
- def get_pending_accounts(self, limit: int = 10) -> List[Dict[str, Any]]:
132
- """获取待处理的账号(未提交状态)
133
-
134
- Args:
135
- limit: 返回账号的最大数量
136
-
137
- Returns:
138
- 账号列表,每个账号是一个字典
139
- """
140
- with self.lock:
141
- cursor = self.conn.cursor()
142
- cursor.execute('''
143
- SELECT id, register_time, username, password, security_email, status, activation_link
144
- FROM accounts
145
- WHERE status = ?
146
- LIMIT ?
147
- ''', (STATUS_PENDING, limit))
148
-
149
- accounts = []
150
- for row in cursor.fetchall():
151
- accounts.append({
152
- 'id': row[0],
153
- 'register_time': row[1],
154
- 'username': row[2],
155
- 'password': row[3],
156
- 'security_email': row[4],
157
- 'status': row[5],
158
- 'activation_link': row[6]
159
- })
160
-
161
- return accounts
162
-
163
- def get_submitted_accounts(self, limit: int = 10) -> List[Dict[str, Any]]:
164
- """获取已提交但未提取链接的账号
165
-
166
- Args:
167
- limit: 返回账号的最大数量
168
-
169
- Returns:
170
- 账号列表,每个账号是一个字典
171
- """
172
- with self.lock:
173
- cursor = self.conn.cursor()
174
- cursor.execute('''
175
- SELECT id, register_time, username, password, security_email, status, activation_link
176
- FROM accounts
177
- WHERE status = ? AND (activation_link IS NULL OR activation_link = '')
178
- LIMIT ?
179
- ''', (STATUS_SUBMITTED, limit))
180
-
181
- accounts = []
182
- for row in cursor.fetchall():
183
- accounts.append({
184
- 'id': row[0],
185
- 'register_time': row[1],
186
- 'username': row[2],
187
- 'password': row[3],
188
- 'security_email': row[4],
189
- 'status': row[5],
190
- 'activation_link': row[6]
191
- })
192
-
193
- return accounts
194
-
195
- def update_account_status(self, id: int, status: int, activation_link: str = None, notes: str = None) -> bool:
196
- """更新账号状态
197
-
198
- Args:
199
- id: 账号ID
200
- status: 新状态
201
- activation_link: 激活链接(可选)
202
- notes: 备注信息(可选)
203
-
204
- Returns:
205
- 更新成功返回True,否则返回False
206
- """
207
- try:
208
- with self.lock:
209
- cursor = self.conn.cursor()
210
-
211
- if activation_link and notes:
212
- cursor.execute('''
213
- UPDATE accounts
214
- SET status = ?, activation_link = ?, notes = ?, updated_at = datetime('now', 'localtime')
215
- WHERE id = ?
216
- ''', (status, activation_link, notes, id))
217
- elif activation_link:
218
- cursor.execute('''
219
- UPDATE accounts
220
- SET status = ?, activation_link = ?, updated_at = datetime('now', 'localtime')
221
- WHERE id = ?
222
- ''', (status, activation_link, id))
223
- elif notes:
224
- cursor.execute('''
225
- UPDATE accounts
226
- SET status = ?, notes = ?, updated_at = datetime('now', 'localtime')
227
- WHERE id = ?
228
- ''', (status, notes, id))
229
- else:
230
- cursor.execute('''
231
- UPDATE accounts
232
- SET status = ?, updated_at = datetime('now', 'localtime')
233
- WHERE id = ?
234
- ''', (status, id))
235
-
236
- self.conn.commit()
237
- return cursor.rowcount > 0
238
- except Exception as e:
239
- logger.error(f"更新账号状态时出错: {str(e)}")
240
- return False
241
-
242
- def log_operation(self, username: str, operation: str, status: str, message: str = None) -> None:
243
- """记录操作日志
244
-
245
- Args:
246
- username: 相关的用户名
247
- operation: 操作类型
248
- status: 操作状态
249
- message: 附加信息
250
- """
251
- try:
252
- with self.lock:
253
- cursor = self.conn.cursor()
254
- cursor.execute('''
255
- INSERT INTO operation_logs
256
- (username, operation, status, message, created_at)
257
- VALUES (?, ?, ?, ?, datetime('now', 'localtime'))
258
- ''', (username, operation, status, message))
259
- self.conn.commit()
260
- except Exception as e:
261
- logger.error(f"记录操作日志时出错: {str(e)}")
262
-
263
- def export_results_to_file(self, filepath: str, status: int = None) -> int:
264
- """将结果导出到文件
265
-
266
- Args:
267
- filepath: 输出文件路径
268
- status: 筛选的状态(可选)
269
-
270
- Returns:
271
- 导出的记录数量
272
- """
273
- try:
274
- with self.lock, open(filepath, 'w', encoding='utf-8') as file:
275
- cursor = self.conn.cursor()
276
-
277
- if status is not None:
278
- cursor.execute('''
279
- SELECT register_time, username, password, security_email, status, activation_link
280
- FROM accounts
281
- WHERE status = ?
282
- ''', (status,))
283
- else:
284
- cursor.execute('''
285
- SELECT register_time, username, password, security_email, status, activation_link
286
- FROM accounts
287
- ''')
288
-
289
- count = 0
290
- for row in cursor.fetchall():
291
- # 将状态码转换为文本
292
- status_text = ""
293
- if row[4] == STATUS_SUBMITTED:
294
- status_text = "success"
295
- elif row[4] == STATUS_FAILED:
296
- status_text = "failed"
297
- elif row[4] == STATUS_LINK_EXTRACTED:
298
- status_text = "successed"
299
-
300
- # 构建输出行
301
- if row[5]: # 如果有激活链接
302
- line = f"{row[0]}---{row[1]}---{row[2]}---{row[3]}---{status_text}---{row[5]}\n"
303
- elif status_text:
304
- line = f"{row[0]}---{row[1]}---{row[2]}---{row[3]}---{status_text}\n"
305
- else:
306
- line = f"{row[0]}---{row[1]}---{row[2]}---{row[3]}\n"
307
-
308
- file.write(line)
309
- count += 1
310
-
311
- return count
312
- except Exception as e:
313
- logger.error(f"导出结果到文件时出错: {str(e)}")
314
- return 0
315
-
316
-
317
- class JetbrainsSubmitter:
318
- """提交邮箱到JetBrains获取激活链接的类"""
319
-
320
- def __init__(self, db_manager: DatabaseManager, proxy: str = None):
321
- """初始化提交器
322
-
323
- Args:
324
- db_manager: 数据库管理器实例
325
- proxy: 代理服务器地址
326
- """
327
- self.db_manager = db_manager
328
- self.proxy = proxy
329
- logger.info("JetbrainsSubmitter 初始化完成")
330
-
331
- def random_name(self) -> Tuple[str, str]:
332
- """生成随机的意大利名字和姓氏
333
-
334
- Returns:
335
- (名字, 姓氏)元组
336
- """
337
- first_names = [
338
- "Marco", "Giuseppe", "Antonio", "Giovanni", "Mario", "Luigi", "Paolo", "Francesco", "Roberto", "Stefano",
339
- "Alessandro", "Andrea", "Giorgio", "Bruno", "Carlo", "Enrico", "Fabio", "Davide", "Claudio", "Massimo",
340
- "Sofia", "Giulia", "Isabella", "Valentina", "Chiara", "Laura", "Maria", "Anna", "Francesca", "Elena",
341
- "Alessandra", "Martina", "Giovanna", "Rosa", "Angela", "Lucia", "Paola", "Silvia", "Monica", "Cristina"
342
- ]
343
- last_names = [
344
- "Rossi", "Ferrari", "Russo", "Bianchi", "Romano", "Gallo", "Costa", "Fontana", "Conti", "Esposito",
345
- "Ricci", "Bruno", "De Luca", "Moretti", "Marino", "Greco", "Barbieri", "Lombardi", "Giordano", "Colombo",
346
- "Mancini", "Longo", "Leone", "Martinelli", "Santoro", "Mariani", "Vitale", "Ferraro", "Rinaldi", "Villa"
347
- ]
348
- return random.choice(first_names), random.choice(last_names)
349
-
350
- def submit_email(self, account: Dict[str, Any]) -> bool:
351
- """提交邮箱到JetBrains获取激活链接
352
-
353
- Args:
354
- account: 账号信息字典
355
-
356
- Returns:
357
- 提交成功返回True,否则返回False
358
- """
359
- username = account['username']
360
- logger.info(f"正在尝试提交邮箱: {username} 到JetBrains...")
361
-
362
- try:
363
- firstname, lastname = self.random_name()
364
-
365
- # 使用CaptchaSolver提交邮箱
366
- with CaptchaSolver(
367
- email=username,
368
- firstname=firstname,
369
- lastname=lastname,
370
- is_teacher=False,
371
- proxy=self.proxy
372
- ) as solver:
373
- success = solver.solve_audio_captcha()
374
-
375
- if success:
376
- logger.info(f"邮箱 {username} 提交成功")
377
- self.db_manager.update_account_status(account['id'], STATUS_SUBMITTED)
378
- self.db_manager.log_operation(username, "submit_email", "success")
379
- return True
380
- else:
381
- logger.warning(f"邮箱 {username} 提交失败 (CaptchaSolver返回False)")
382
- self.db_manager.update_account_status(account['id'], STATUS_FAILED, notes="提交失败请手动检查")
383
- self.db_manager.log_operation(username, "submit_email", "failed", "CaptchaSolver返回False")
384
- return False
385
- except Exception as e:
386
- error_msg = str(e)
387
- logger.error(f"提交邮箱 {username} 时发生错误: {error_msg}")
388
- self.db_manager.update_account_status(account['id'], STATUS_FAILED, notes=f"认证失败: {error_msg[:100]}")
389
- self.db_manager.log_operation(username, "submit_email", "error", error_msg[:200])
390
- return False
391
-
392
- def submit_batch(self, max_accounts: int = 5, max_workers: int = 3) -> Tuple[int, int]:
393
- """批量提交邮箱
394
-
395
- Args:
396
- max_accounts: 最大处理账号数量
397
- max_workers: 最大并发线程数
398
-
399
- Returns:
400
- (成功数量, 失败数量)元组
401
- """
402
- accounts = self.db_manager.get_pending_accounts(limit=max_accounts)
403
- if not accounts:
404
- logger.info("没有待处理的账号")
405
- return 0, 0
406
-
407
- success_count = 0
408
- error_count = 0
409
- logger.info(f"开始批量处理 {len(accounts)} 个账号,最大并发数: {max_workers}")
410
-
411
- # 使用线程池并发处理账号
412
- with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor:
413
- future_to_account = {executor.submit(self.submit_email, account): account for account in accounts}
414
-
415
- for future in concurrent.futures.as_completed(future_to_account):
416
- account = future_to_account[future]
417
- try:
418
- success = future.result()
419
- if success:
420
- success_count += 1
421
- else:
422
- error_count += 1
423
- except Exception as e:
424
- logger.error(f"执行任务时发生异常: {str(e)}")
425
- error_count += 1
426
- # 更新数据库状态
427
- self.db_manager.update_account_status(account['id'], STATUS_FAILED, notes=f"执行异常: {str(e)[:100]}")
428
-
429
- logger.info(f"批量处理完成,成功: {success_count},失败: {error_count}")
430
- return success_count, error_count
431
-
432
-
433
- class LinkExtractor:
434
- """从邮箱中提取JetBrains激活链接的类"""
435
-
436
- def __init__(self, db_manager: DatabaseManager):
437
- """初始化链接提取器
438
-
439
- Args:
440
- db_manager: 数据库管理器实例
441
- """
442
- self.db_manager = db_manager
443
- logger.info("LinkExtractor 初始化完成")
444
-
445
- def _find_activation_link(self, text_content: str) -> Optional[str]:
446
- """在文本内容中查找JetBrains激活链接
447
-
448
- Args:
449
- text_content: 邮件文本内容
450
-
451
- Returns:
452
- 找到的激活链接,未找到返回None
453
- """
454
- if not text_content:
455
- return None
456
-
457
- # 使用正则表达式查找JetBrains激活链接
458
- match = re.search(r'https?://(?:account\.jetbrains\.com/login|www\.jetbrains\.com/shop/(?:account|eform)|jetbrains\.com/activate)[?\S]+', text_content)
459
- if match:
460
- link = match.group(0)
461
- # 基本验证:确认是有效的JetBrains激活链接
462
- if "jetbrains.com" in link and ("activate" in link or "account" in link or "login" in link or "eform" in link):
463
- # 清理链接:移除可能的尾随字符
464
- link = link.split('<')[0].split('>')[0].split('"')[0].split("'")[0].strip()
465
- logger.info(f"找到可能的激活链接: {link}")
466
- return link
467
- return None
468
-
469
- def extract_link(self, account: Dict[str, Any]) -> Optional[str]:
470
- """登录邮箱并提取JetBrains激活链接
471
-
472
- Args:
473
- account: 账号信息字典
474
-
475
- Returns:
476
- 提取到的激活链接,未找到返回None
477
- """
478
- username = account['username']
479
- password = account['password']
480
- logger.info(f"正在尝试登录邮箱: {username} 并提取激活链接...")
481
-
482
- try:
483
- # 创建邮件客户端实例
484
- client = EmailClient(
485
- username=username,
486
- password=password,
487
- email_address=username
488
- )
489
-
490
- # 认证
491
- logger.info(f"为 {username} 执行OAuth认证...")
492
- client.authenticate_oauth()
493
- logger.info(f"为 {username} OAuth认证成功")
494
-
495
- # 搜索邮件
496
- logger.info(f"为 {username} 搜索JetBrains相关邮件...")
497
- search_keywords = [
498
- 'BODY "jetbrain"',
499
- 'SUBJECT "JetBrains Account"',
500
- 'SUBJECT "Activate JetBrains"',
501
- 'BODY "jetbrains.com/activate"',
502
- 'BODY "account.jetbrains.com"',
503
- 'FROM "jetbrains.com"'
504
- ]
505
-
506
- emails = []
507
- for keyword in search_keywords:
508
- logger.info(f"使用关键词 '{keyword}' 搜索...")
509
- try:
510
- fetched_emails = client.read_emails(mailbox="INBOX", limit=5, keyword=keyword)
511
- emails.extend(fetched_emails)
512
- if emails: # 找到邮件后停止搜索
513
- logger.info(f"使用关键词 '{keyword}' 找到 {len(fetched_emails)} 封邮件")
514
- break
515
- except Exception as read_err:
516
- logger.warning(f"使用关键词 '{keyword}' 读取邮件时出错: {read_err}")
517
- time.sleep(1) # 每次搜索之间短暂延迟
518
-
519
- if not emails:
520
- logger.warning(f"邮箱 {username} 中未找到相关的JetBrains邮件")
521
- self.db_manager.update_account_status(account['id'], STATUS_SUBMITTED, notes="没有找到包含关键字的邮件")
522
- self.db_manager.log_operation(username, "extract_link", "failed", "没有找到包含关键字的邮件")
523
- return None
524
-
525
- logger.info(f"在 {username} 中找到 {len(emails)} 封相关邮件,开始解析...")
526
-
527
- # 解析邮件内容
528
- for email_content in emails:
529
- html_body = email_content.get('html')
530
- text_body = email_content.get('text')
531
-
532
- link = None
533
- if html_body:
534
- link = self._find_activation_link(html_body)
535
- if not link and text_body:
536
- link = self._find_activation_link(text_body)
537
-
538
- if link:
539
- logger.success(f"为邮箱 {username} 成功提取到激活链接: {link}")
540
- self.db_manager.update_account_status(account['id'], STATUS_LINK_EXTRACTED, activation_link=link)
541
- self.db_manager.log_operation(username, "extract_link", "success", link)
542
- return link
543
-
544
- logger.warning(f"在找到的邮件中未能为邮箱 {username} 提取到激活链接")
545
- self.db_manager.update_account_status(account['id'], STATUS_SUBMITTED, notes="没有找到激活链接")
546
- self.db_manager.log_operation(username, "extract_link", "failed", "在邮件中未找到链接")
547
- return None
548
-
549
- except Exception as e:
550
- error_msg = str(e)
551
- # 捕获特定认证错误
552
- if "Authentication failed" in error_msg or "认证失败" in error_msg:
553
- logger.error(f"邮箱 {username} 认证失败: {error_msg}")
554
- error_type = "认证失败"
555
- elif "invalid_grant" in error_msg:
556
- logger.error(f"邮箱 {username} OAuth Token无效或过期: {error_msg}")
557
- error_type = "OAuth Token无效"
558
- else:
559
- logger.error(f"为邮箱 {username} 提取链接时发生未预料的错误: {error_msg}")
560
- error_type = "未知错误"
561
-
562
- self.db_manager.update_account_status(account['id'], STATUS_SUBMITTED, notes=f"{error_type}: {error_msg[:100]}")
563
- self.db_manager.log_operation(username, "extract_link", "error", error_msg[:200])
564
- return None
565
-
566
- def extract_batch(self, max_accounts: int = 5, max_workers: int = 1) -> Tuple[int, int]:
567
- """批量提取激活链接
568
-
569
- Args:
570
- max_accounts: 最大处理账号数量
571
- max_workers: 最大并发线程数
572
-
573
- Returns:
574
- (成功数量, 失败数量)元组
575
- """
576
- accounts = self.db_manager.get_submitted_accounts(limit=max_accounts)
577
- if not accounts:
578
- logger.info("没有待提取链接的账号")
579
- return 0, 0
580
-
581
- success_count = 0
582
- error_count = 0
583
- logger.info(f"开始批量提取链接,处理 {len(accounts)} 个账号,最大并发数: {max_workers}")
584
-
585
- # 使用线程池并发处理账号
586
- with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor:
587
- future_to_account = {executor.submit(self.extract_link, account): account for account in accounts}
588
-
589
- for future in concurrent.futures.as_completed(future_to_account):
590
- account = future_to_account[future]
591
- try:
592
- link = future.result()
593
- if link:
594
- success_count += 1
595
- else:
596
- error_count += 1
597
- except Exception as e:
598
- logger.error(f"执行提取任务时发生异常: {str(e)}")
599
- error_count += 1
600
- # 更新数据库状态
601
- self.db_manager.update_account_status(account['id'], STATUS_SUBMITTED, notes=f"执行异常: {str(e)[:100]}")
602
-
603
- logger.info(f"批量提取完成,成功: {success_count},失败: {error_count}")
604
- return success_count, error_count
605
-
606
-
607
- class ProcessController:
608
- """流程控制类,协调整个处理流程"""
609
-
610
- def __init__(self, db_path: str = "unibo_jetbrains.db", proxy: str = ''):
611
- """初始化流程控制器
612
-
613
- Args:
614
- db_path: 数据库文件路径
615
- proxy: 代理服务器地址
616
- """
617
- self.db_manager = DatabaseManager(db_path)
618
- self.submitter = JetbrainsSubmitter(self.db_manager, proxy)
619
- self.extractor = LinkExtractor(self.db_manager)
620
- logger.info("ProcessController 初始化完成")
621
-
622
- def import_data(self, filepath: str) -> int:
623
- """从文件导入账号数据
624
-
625
- Args:
626
- filepath: 账号数据文件路径
627
-
628
- Returns:
629
- 导入的账号数量
630
- """
631
- return self.db_manager.import_from_file(filepath)
632
-
633
- def export_data(self, filepath: str, status: int = None) -> int:
634
- """导出账号数据到文件
635
-
636
- Args:
637
- filepath: 输出文件路径
638
- status: 筛选状态(可选)
639
-
640
- Returns:
641
- 导出的记录数量
642
- """
643
- return self.db_manager.export_results_to_file(filepath, status)
644
-
645
- def run_submission_process(self, max_accounts: int = 5, max_workers: int = 3) -> Tuple[int, int]:
646
- """运行邮箱提交流程
647
-
648
- Args:
649
- max_accounts: 最大处理账号数量
650
- max_workers: 最大并发线程数
651
-
652
- Returns:
653
- (成功数量, 失败数量)元组
654
- """
655
- return self.submitter.submit_batch(max_accounts, max_workers)
656
-
657
- def run_extraction_process(self, max_accounts: int = 5, max_workers: int = 1) -> Tuple[int, int]:
658
- """运行链接提取流程
659
-
660
- Args:
661
- max_accounts: 最大处理账号数量
662
- max_workers: 最大并发线程数
663
-
664
- Returns:
665
- (成功数量, 失败数量)元组
666
- """
667
- return self.extractor.extract_batch(max_accounts, max_workers)
668
-
669
- def run_full_process(self, max_submission: int = 5, max_extraction: int = 5,
670
- submission_workers: int = 3, extraction_workers: int = 1) -> Dict[str, int]:
671
- """运行完整流程:提交邮箱并提取链接
672
-
673
- Args:
674
- max_submission: 提交流程最大处理账号数量
675
- max_extraction: 提取流程最大处理账号数量
676
- submission_workers: 提交流程最大并发线程数
677
- extraction_workers: 提取流程最大并发线程数
678
-
679
- Returns:
680
- 包含各步骤统计信息的字典
681
- """
682
- # 运行提交流程
683
- sub_success, sub_fail = self.run_submission_process(max_submission, submission_workers)
684
-
685
- # 运行提取流程
686
- ext_success, ext_fail = self.run_extraction_process(max_extraction, extraction_workers)
687
-
688
- return {
689
- 'submission_success': sub_success,
690
- 'submission_fail': sub_fail,
691
- 'extraction_success': ext_success,
692
- 'extraction_fail': ext_fail,
693
- 'total_processed': sub_success + sub_fail + ext_success + ext_fail
694
- }
695
-
696
-
697
- # 示例用法
698
- if __name__ == "__main__":
699
- # 设置日志级别
700
- logger.remove()
701
- logger.add(lambda msg: print(msg, end=""), level="INFO")
702
- logger.add("unibo_process.log", rotation="500 KB", level="DEBUG")
703
-
704
- # 初始化流程控制器
705
- controller = ProcessController()
706
-
707
- # 导入数据
708
- print("\n=== 从文件导入数据 ===")
709
- imported = controller.import_data("user-4-21-success.txt")
710
- print(f"导入了 {imported} 个账号")
711
-
712
- # 运行提交流程
713
- print("\n=== 运行提交邮箱流程 ===")
714
- sub_success, sub_fail = controller.run_submission_process(max_accounts=3, max_workers=1)
715
- print(f"提交结果: 成功 {sub_success} 个, 失败 {sub_fail} 个")
716
-
717
- # 运行提取链接流程
718
- print("\n=== 运行提取链接流程 ===")
719
- ext_success, ext_fail = controller.run_extraction_process(max_accounts=2, max_workers=1)
720
- print(f"提取结果: 成功 {ext_success} 个, 失败 {ext_fail} 个")
721
-
722
- # 导出结果
723
- print("\n=== 导出链接提取成功的账号 ===")
724
- exported = controller.export_data("export_results.txt", STATUS_LINK_EXTRACTED)
725
- print(f"导出了 {exported} 个记录")