Skip to main content

data_for_seo/api/ai_optimization/
llm_scraper.rs

1//! LLM Scraper sub-API (ChatGPT, Gemini).
2//!
3//! See <https://docs.dataforseo.com/v3/ai_optimization/chat_gpt/llm_scraper/overview/>.
4
5use crate::entity::{
6    AiOptimizationLanguage, AiOptimizationLlmScraper, AiOptimizationLlmScraperHtml,
7    AiOptimizationScraperLocation, AiOptimizationTaskReady,
8};
9use crate::{DataForSeoApiResponse, DataForSeoClient};
10use serde::{Deserialize, Serialize};
11
12/// LLM Scraper endpoints for a single provider (`chat_gpt`, `gemini`).
13pub struct AiOptimizationApiLlmScraper<'a> {
14    pub(crate) client: &'a DataForSeoClient,
15    pub(crate) provider: &'static str,
16}
17
18impl AiOptimizationApiLlmScraper<'_> {
19    /// Lists the locations supported by this provider's scraper.
20    ///
21    /// `GET /v3/ai_optimization/{provider}/llm_scraper/locations`
22    /// See <https://docs.dataforseo.com/v3/ai_optimization/chat_gpt/llm_scraper/locations/>.
23    pub async fn locations(&self) -> DataForSeoApiResponse<AiOptimizationScraperLocation> {
24        self.client
25            .http_get(&format!(
26                "/v3/ai_optimization/{}/llm_scraper/locations",
27                self.provider
28            ))
29            .await
30    }
31
32    /// Lists the languages supported by this provider's scraper.
33    ///
34    /// `GET /v3/ai_optimization/{provider}/llm_scraper/languages`
35    /// See <https://docs.dataforseo.com/v3/ai_optimization/chat_gpt/llm_scraper/languages/>.
36    pub async fn languages(&self) -> DataForSeoApiResponse<AiOptimizationLanguage> {
37        self.client
38            .http_get(&format!(
39                "/v3/ai_optimization/{}/llm_scraper/languages",
40                self.provider
41            ))
42            .await
43    }
44
45    /// Queues a scraper task (Standard method).
46    ///
47    /// `POST /v3/ai_optimization/{provider}/llm_scraper/task_post`
48    /// See <https://docs.dataforseo.com/v3/ai_optimization/chat_gpt/llm_scraper/task_post/>.
49    pub async fn task_post(
50        &self,
51        data: Vec<AiOptimizationLlmScraperPost>,
52    ) -> DataForSeoApiResponse<AiOptimizationLlmScraper> {
53        self.client
54            .http_post(
55                &format!(
56                    "/v3/ai_optimization/{}/llm_scraper/task_post",
57                    self.provider
58                ),
59                &data,
60            )
61            .await
62    }
63
64    /// Lists scraper tasks that have completed and are ready to collect.
65    ///
66    /// `GET /v3/ai_optimization/{provider}/llm_scraper/tasks_ready`
67    /// See <https://docs.dataforseo.com/v3/ai_optimization/chat_gpt/llm_scraper/tasks_ready/>.
68    pub async fn tasks_ready(&self) -> DataForSeoApiResponse<AiOptimizationTaskReady> {
69        self.client
70            .http_get(&format!(
71                "/v3/ai_optimization/{}/llm_scraper/tasks_ready",
72                self.provider
73            ))
74            .await
75    }
76
77    /// Collects a completed task's parsed result by its `id`.
78    ///
79    /// `GET /v3/ai_optimization/{provider}/llm_scraper/task_get/advanced/{id}`
80    /// See <https://docs.dataforseo.com/v3/ai_optimization/chat_gpt/llm_scraper/task_get/advanced/>.
81    pub async fn task_get_advanced(
82        &self,
83        id: &str,
84    ) -> DataForSeoApiResponse<AiOptimizationLlmScraper> {
85        self.client
86            .http_get(&format!(
87                "/v3/ai_optimization/{}/llm_scraper/task_get/advanced/{}",
88                self.provider, id
89            ))
90            .await
91    }
92
93    /// Collects a completed task's raw HTML by its `id`.
94    ///
95    /// `GET /v3/ai_optimization/{provider}/llm_scraper/task_get/html/{id}`
96    /// See <https://docs.dataforseo.com/v3/ai_optimization/chat_gpt/llm_scraper/task_get/html/>.
97    pub async fn task_get_html(
98        &self,
99        id: &str,
100    ) -> DataForSeoApiResponse<AiOptimizationLlmScraperHtml> {
101        self.client
102            .http_get(&format!(
103                "/v3/ai_optimization/{}/llm_scraper/task_get/html/{}",
104                self.provider, id
105            ))
106            .await
107    }
108
109    /// Scrapes and parses a result synchronously.
110    ///
111    /// `POST /v3/ai_optimization/{provider}/llm_scraper/live/advanced`
112    /// See <https://docs.dataforseo.com/v3/ai_optimization/chat_gpt/llm_scraper/live/advanced/>.
113    pub async fn live_advanced(
114        &self,
115        data: Vec<AiOptimizationLlmScraperPost>,
116    ) -> DataForSeoApiResponse<AiOptimizationLlmScraper> {
117        self.client
118            .http_post(
119                &format!(
120                    "/v3/ai_optimization/{}/llm_scraper/live/advanced",
121                    self.provider
122                ),
123                &data,
124            )
125            .await
126    }
127
128    /// Scrapes and returns the raw HTML synchronously.
129    ///
130    /// `POST /v3/ai_optimization/{provider}/llm_scraper/live/html`
131    /// See <https://docs.dataforseo.com/v3/ai_optimization/chat_gpt/llm_scraper/live/html/>.
132    pub async fn live_html(
133        &self,
134        data: Vec<AiOptimizationLlmScraperPost>,
135    ) -> DataForSeoApiResponse<AiOptimizationLlmScraperHtml> {
136        self.client
137            .http_post(
138                &format!(
139                    "/v3/ai_optimization/{}/llm_scraper/live/html",
140                    self.provider
141                ),
142                &data,
143            )
144            .await
145    }
146}
147
148/// Request body for the LLM Scraper `live/*` and `task_post` endpoints.
149///
150/// `postback_url` and `pingback_url` apply only to `task_post`.
151#[derive(Debug, Default, Serialize, Deserialize, Clone)]
152pub struct AiOptimizationLlmScraperPost {
153    /// Keyword to scrape (max 2000 characters).
154    pub keyword: String,
155    /// Full name of the search location (alternative to `location_code`).
156    #[serde(skip_serializing_if = "Option::is_none")]
157    pub location_name: Option<String>,
158    /// Search location code (alternative to `location_name`).
159    #[serde(skip_serializing_if = "Option::is_none")]
160    pub location_code: Option<i32>,
161    /// Full name of the search language (alternative to `language_code`).
162    #[serde(skip_serializing_if = "Option::is_none")]
163    pub language_name: Option<String>,
164    /// Search language code (alternative to `language_name`).
165    #[serde(skip_serializing_if = "Option::is_none")]
166    pub language_code: Option<String>,
167    /// Whether to force the model to access and cite current web information.
168    #[serde(skip_serializing_if = "Option::is_none")]
169    pub force_web_search: Option<bool>,
170    /// URL to POST the result to when the task completes (`task_post` only).
171    #[serde(skip_serializing_if = "Option::is_none")]
172    pub postback_url: Option<String>,
173    /// URL to ping when the task completes (`task_post` only).
174    #[serde(skip_serializing_if = "Option::is_none")]
175    pub pingback_url: Option<String>,
176    /// User-defined task identifier (max 255 characters).
177    #[serde(skip_serializing_if = "Option::is_none")]
178    pub tag: Option<String>,
179}
180
181impl AiOptimizationLlmScraperPost {
182    /// Creates a request for the given keyword.
183    pub fn new(keyword: &str) -> AiOptimizationLlmScraperPost {
184        AiOptimizationLlmScraperPost {
185            keyword: keyword.to_string(),
186            ..Default::default()
187        }
188    }
189}