withHeaders(['Accept' => 'application/xml']) ->get(self::RSS_URL); if (! $response->successful()) { Log::warning('TrendingKeywordService: RSS 호출 실패', [ 'status' => $response->status(), ]); return []; } $keywords = $this->parseGoogleTrendsRss($response->body()); return array_slice($keywords, 0, $limit); } catch (\Exception $e) { Log::error('TrendingKeywordService: 예외 발생', [ 'error' => $e->getMessage(), ]); return []; } }); } /** * RSS XML 파싱 */ private function parseGoogleTrendsRss(string $xml): array { $keywords = []; try { // XML namespace 처리를 위해 ht: 접두사 등록 $doc = new \SimpleXMLElement($xml); $namespaces = $doc->getNamespaces(true); $items = $doc->channel->item ?? []; foreach ($items as $item) { $keyword = (string) $item->title; if (empty($keyword)) { continue; } $traffic = ''; $newsTitle = ''; if (isset($namespaces['ht'])) { $htData = $item->children($namespaces['ht']); $traffic = (string) ($htData->approx_traffic ?? ''); if (isset($htData->news_item)) { $newsTitle = (string) ($htData->news_item->news_item_title ?? ''); } } $pubDate = (string) ($item->pubDate ?? ''); $keywords[] = [ 'keyword' => $keyword, 'traffic' => $traffic, 'news_title' => $newsTitle, 'pub_date' => $pubDate ? date('c', strtotime($pubDate)) : null, ]; } } catch (\Exception $e) { Log::error('TrendingKeywordService: XML 파싱 실패', [ 'error' => $e->getMessage(), ]); } return $keywords; } }