From 90e9e06e10d8d0f76b5d2652cf35f34f8efe4bd1 Mon Sep 17 00:00:00 2001 From: cody <648753004@qq.com> Date: Sat, 9 Aug 2025 14:37:35 +0800 Subject: [PATCH] update --- app/Console/Commands/UpdateBookIsbnData.php | 120 +++++++++++++----- ...720250.jpg => book_cover_1_1754721429.jpg} | Bin 2 files changed, 90 insertions(+), 30 deletions(-) rename public/uploads/book_covers/{book_cover_1_1754720250.jpg => book_cover_1_1754721429.jpg} (100%) diff --git a/app/Console/Commands/UpdateBookIsbnData.php b/app/Console/Commands/UpdateBookIsbnData.php index 74875aa..1be6427 100644 --- a/app/Console/Commands/UpdateBookIsbnData.php +++ b/app/Console/Commands/UpdateBookIsbnData.php @@ -58,16 +58,39 @@ class UpdateBookIsbnData extends Command } $this->info("找到 {$books->count()} 本书需要处理"); + $this->info("API限制:每秒最多10次请求,预计耗时约 " . ceil($books->count() / 10) . " 秒"); $bar = $this->output->createProgressBar($books->count()); $bar->start(); $successCount = 0; $failCount = 0; + $requestCount = 0; + $startTime = microtime(true); + $lastResetTime = $startTime; foreach ($books as $book) { try { + // 每秒重置请求计数器 + $currentTime = microtime(true); + if ($currentTime - $lastResetTime >= 1.0) { + $requestCount = 0; + $lastResetTime = $currentTime; + } + + // API频率限制控制:每秒最多10次请求 + if ($requestCount >= 10) { + $waitTime = 1.0 - ($currentTime - $lastResetTime); + if ($waitTime > 0) { + usleep(intval($waitTime * 1000000)); + $requestCount = 0; + $lastResetTime = microtime(true); + } + } + $result = $this->processBook($book, $apiKey); + $requestCount++; + if ($result) { $successCount++; $this->line("\n✓ 成功处理书籍: {$book->title} (ISBN: {$book->isbn})"); @@ -78,18 +101,31 @@ class UpdateBookIsbnData extends Command } catch (\Exception $e) { $failCount++; $this->line("\n✗ 处理异常: {$book->title} - {$e->getMessage()}"); + + // 如果是API相关错误,增加等待时间 + if (strpos($e->getMessage(), 'API') !== false || strpos($e->getMessage(), 'HTTP') !== false) { + $this->line("检测到API错误,等待2秒后继续..."); + sleep(2); + $requestCount = 0; + $lastResetTime = microtime(true); + } } $bar->advance(); - - // 添加延迟避免API请求过快 - sleep(1); } $bar->finish(); + $totalTime = microtime(true) - $startTime; + $avgTimePerBook = $totalTime / $books->count(); + $actualRequestsPerSecond = $books->count() / $totalTime; + $this->line(''); - $this->info("处理完成!成功: {$successCount}, 失败: {$failCount}"); + $this->info("处理完成!"); + $this->info("成功: {$successCount}, 失败: {$failCount}"); + $this->info("总耗时: " . round($totalTime, 2) . " 秒"); + $this->info("平均每本书耗时: " . round($avgTimePerBook, 2) . " 秒"); + $this->info("实际请求频率: " . round($actualRequestsPerSecond, 2) . " 次/秒"); return 0; } @@ -103,40 +139,64 @@ class UpdateBookIsbnData extends Command */ private function processBook(Book $book, string $apiKey): bool { - // 调用ISBN接口 - $response = Http::timeout(30)->get('https://api.tanshuapi.com/api/isbn/v2/index', [ - 'key' => $apiKey, - 'isbn' => $book->isbn - ]); - - if (!$response->successful()) { - $this->error("API请求失败: HTTP {$response->status()}"); - return false; - } + $attempt = 0; + $maxRetries = 3; - $data = $response->json(); + while ($attempt < $maxRetries) { + try { + $attempt++; - if (!$data || $data['code'] !== 1) { - $this->error("API返回错误: " . ($data['msg'] ?? '未知错误')); - return false; - } + // 调用ISBN接口 + $response = Http::timeout(30)->get('https://api.tanshuapi.com/api/isbn/v2/index', [ + 'key' => $apiKey, + 'isbn' => $book->isbn + ]); - $bookData = $data['data']; + if (!$response->successful()) { + throw new \Exception("API请求失败: HTTP {$response->status()}"); + } + + $data = $response->json(); + + if (!$data || $data['code'] !== 1) { + // 如果是API密钥错误或其他不可重试的错误,直接返回失败 + if (isset($data['code']) && in_array($data['code'], [10001, 10002, 10003])) { + $this->error("API返回不可重试错误: " . ($data['msg'] ?? '未知错误')); + return false; + } + throw new \Exception("API返回错误: " . ($data['msg'] ?? '未知错误')); + } + + $bookData = $data['data']; + + // 更新书籍的other_data字段 + $book->other_data = $bookData; - // 更新书籍的other_data字段 - $book->other_data = $bookData; + // 如果有图片URL,下载图片 + if (!empty($bookData['img'])) { + $coverId = $this->downloadAndSaveImage($bookData['img'], $book); + if ($coverId) { + $book->cover_id = $coverId; + } + } + + $book->save(); + return true; + + } catch (\Exception $e) { + if ($attempt >= $maxRetries) { + $this->error("重试 {$maxRetries} 次后仍然失败: {$e->getMessage()}"); + return false; + } - // 如果有图片URL,下载图片 - if (!empty($bookData['img'])) { - $coverId = $this->downloadAndSaveImage($bookData['img'], $book); - if ($coverId) { - $book->cover_id = $coverId; + // 指数退避:第1次重试等待1秒,第2次等待2秒,第3次等待4秒 + $waitTime = pow(2, $attempt - 1); + $this->line("第 {$attempt} 次尝试失败,{$waitTime} 秒后重试: {$e->getMessage()}"); + sleep($waitTime); } } - $book->save(); - - return true; + return false; } /** diff --git a/public/uploads/book_covers/book_cover_1_1754720250.jpg b/public/uploads/book_covers/book_cover_1_1754721429.jpg similarity index 100% rename from public/uploads/book_covers/book_cover_1_1754720250.jpg rename to public/uploads/book_covers/book_cover_1_1754721429.jpg