serpapi_search_rust/
serp_api_search.rs

1#![allow(warnings)]
2#![allow(dead_code)]
3
4//! SerpApiSearch represents a search
5//!
6//!
7
8use std::collections::HashMap;
9
10// search engine supported by Serp Api
11static GOOGLE_ENGINE: &'static str = "google";
12static BAIDU_ENGINE: &'static str = "baidu";
13static BING_ENGINE: &'static str = "bing";
14static DUCKDUCKGO_ENGINE: &'static str = "duckduckgo";
15static YAHOO_ENGINE: &'static str = "yahoo";
16static YANDEX_ENGINE: &'static str = "yandex";
17static EBAY_ENGINE: &'static str = "ebay";
18static YOUTUBE_ENGINE: &'static str = "youtube";
19static WALMART_ENGINE: &'static str = "walmart";
20static HOMEDEPOT_ENGINE: &'static str = "home_depot";
21static APPLE_STORE_ENGINE: &'static str = "apple_app_store";
22static NAVER_ENGINE: &'static str = "naver";
23
24// model serp api search
25//  because of Rust designed we propose to create a new search everytime
26//   as opose of modifying the same search object over and over.
27//  I noticed thar updating a HashMap is difficult in Rust. (I know).
28//  I guess it's cheaper to create a new object in the stack
29//   than updating a mutable object in the heap.
30pub struct SerpApiSearch {
31    // search engine like: google, youtube, bing...
32    pub engine: String,
33    // search parameter like: q=coffee for google
34    pub params: HashMap<String, String>,
35    // private for security reason
36    key: String,
37}
38
39impl SerpApiSearch {
40    pub fn new(engine: String, params: HashMap<String, String>, key: String) -> SerpApiSearch {
41        SerpApiSearch {
42            engine: engine,
43            params: params,
44            key: key,
45        }
46    }
47
48    pub fn google(params: HashMap<String, String>, key: String) -> SerpApiSearch {
49        SerpApiSearch {
50            engine: GOOGLE_ENGINE.to_string(),
51            params: params,
52            key: key,
53        }
54    }
55
56    pub fn baidu(params: HashMap<String, String>, key: String) -> SerpApiSearch {
57        SerpApiSearch {
58            engine: BAIDU_ENGINE.to_string(),
59            params: params,
60            key: key,
61        }
62    }
63
64    pub fn bing(params: HashMap<String, String>, key: String) -> SerpApiSearch {
65        SerpApiSearch {
66            engine: BING_ENGINE.to_string(),
67            params: params,
68            key: key,
69        }
70    }
71
72    pub fn duckduckgo(params: HashMap<String, String>, key: String) -> SerpApiSearch {
73        SerpApiSearch {
74            engine: DUCKDUCKGO_ENGINE.to_string(),
75            params: params,
76            key: key,
77        }
78    }
79
80    pub fn yahoo(params: HashMap<String, String>, key: String) -> SerpApiSearch {
81        SerpApiSearch {
82            engine: YAHOO_ENGINE.to_string(),
83            params: params,
84            key: key,
85        }
86    }
87
88    pub fn yandex(params: HashMap<String, String>, key: String) -> SerpApiSearch {
89        SerpApiSearch {
90            engine: YANDEX_ENGINE.to_string(),
91            params: params,
92            key: key,
93        }
94    }
95
96    pub fn ebay(params: HashMap<String, String>, key: String) -> SerpApiSearch {
97        SerpApiSearch {
98            engine: EBAY_ENGINE.to_string(),
99            params: params,
100            key: key,
101        }
102    }
103
104    pub fn youtube(params: HashMap<String, String>, key: String) -> SerpApiSearch {
105        SerpApiSearch {
106            engine: YOUTUBE_ENGINE.to_string(),
107            params: params,
108            key: key,
109        }
110    }
111
112    pub fn walmart(params: HashMap<String, String>, key: String) -> SerpApiSearch {
113        SerpApiSearch {
114            engine: WALMART_ENGINE.to_string(),
115            params: params,
116            key: key,
117        }
118    }
119
120    pub fn homedepot(params: HashMap<String, String>, key: String) -> SerpApiSearch {
121        SerpApiSearch {
122            engine: HOMEDEPOT_ENGINE.to_string(),
123            params: params,
124            key: key,
125        }
126    }
127
128    pub fn naver(params: HashMap<String, String>, key: String) -> SerpApiSearch {
129        SerpApiSearch {
130            engine: NAVER_ENGINE.to_string(),
131            params: params,
132            key: key,
133        }
134    }
135
136    pub fn apple(params: HashMap<String, String>, key: String) -> SerpApiSearch {
137        SerpApiSearch {
138            engine: APPLE_STORE_ENGINE.to_string(),
139            params: params,
140            key: key,
141        }
142    }
143
144    pub async fn getResults(&self, endpoint: &str) -> Result<String, Box<dyn std::error::Error>> {
145        let host = "http://serpapi.com".to_string();
146
147        // concatenate the argument
148        let mut arg = "&source=rust&engine=".to_string();
149        arg.push_str(&self.engine);
150        arg.push_str("&api_key=");
151        arg.push_str(&self.key);
152        for (k, v) in self.params.iter() {
153            arg.push_str("&");
154            arg.push_str(k);
155            arg.push_str("=");
156            arg.push_str(v);
157        }
158        let mut url = host;
159        url.push_str(endpoint);
160        url.push_str("?");
161        url.push_str(&arg);
162
163        // Await the response...
164        let res = reqwest::get(url).await?;
165        //TODO error handling if status != 200
166        // println!("Status: {}", res.status());
167        // println!("Headers:\n{:#?}", res.headers());
168        let body = res.text().await?;
169        Ok(body)
170    }
171
172    pub async fn getJson(
173        &self,
174        endpoint: &str,
175    ) -> Result<serde_json::Value, Box<dyn std::error::Error>> {
176        let body = self.getResults(endpoint).await?;
177        //println!("Body:\n{}", body);
178        let value: serde_json::Value = serde_json::from_str(&body).unwrap();
179        Ok(value)
180    }
181
182    pub async fn json(&self) -> Result<serde_json::Value, Box<dyn std::error::Error>> {
183        let results = self.getJson("/search").await?;
184        Ok(results)
185    }
186
187    pub async fn html(&self) -> Result<String, Box<dyn std::error::Error>> {
188        let body = self.getResults("/html").await?;
189        Ok(body)
190    }
191
192    // Get location using Location API
193    pub async fn location(&self) -> Result<serde_json::Value, Box<dyn std::error::Error>> {
194        let results = self.getJson("/locations.json").await?;
195        Ok(results)
196    }
197
198    // Retrieve search result from the Search Archive API
199    pub async fn search_archive(
200        &self,
201        search_id: &str,
202    ) -> Result<serde_json::Value, Box<dyn std::error::Error>> {
203        let mut endpoint = "/searches/".to_string();
204        endpoint.push_str(search_id);
205        endpoint.push_str(".json");
206        println!(">> {}", endpoint);
207        let results = self.getJson(&endpoint).await?;
208        Ok(results)
209    }
210
211    // Get account information using Account API
212    pub async fn account(&self) -> Result<serde_json::Value, Box<dyn std::error::Error>> {
213        let results = self.getJson("/account").await?;
214        Ok(results)
215    }
216}