Skip to main content

headless_engine/google/
parser.rs

1use crate::dom::DomTree;
2use crate::google::types::{
3    GenericGoogleResult, GoogleAutocompleteResult, GoogleSearchResult, OrganicResult,
4};
5use serde_json::Value;
6
7pub struct GoogleParser;
8
9impl GoogleParser {
10    pub fn parse_search_results(html: &str, url: &str) -> GoogleSearchResult {
11        let dom = match DomTree::parse(html) {
12            Ok(d) => d,
13            Err(_) => {
14                return GoogleSearchResult {
15                    query: url.to_string(),
16                    title: "Google Search (Parse Error)".to_string(),
17                    ..Default::default()
18                }
19            }
20        };
21
22        let title = dom
23            .extract(Some("title"))
24            .unwrap_or_else(|| "Google Search".to_string());
25
26        // This leverages the existing SearchResults logic implicitly or we build it explicitly.
27        let search_results = dom.parse_google_search_results();
28
29        let mut organic = Vec::new();
30        for res in search_results.organic_results {
31            organic.push(OrganicResult {
32                title: res.title,
33                link: res.link,
34                snippet: res.snippet,
35            });
36        }
37
38        GoogleSearchResult {
39            query: url.to_string(), // In a real app we'd parse the URL q= param
40            title,
41            ai_overview: search_results.ai_overview.map(|a| a.summary),
42            knowledge_panel: search_results.knowledge_panel.map(|k| k.description),
43            organic_results: organic,
44            related_questions: search_results.related_questions,
45        }
46    }
47
48    pub fn parse_autocomplete(json: &str) -> GoogleAutocompleteResult {
49        if let Ok(val) = serde_json::from_str::<Value>(json) {
50            if let Some(arr) = val.as_array() {
51                if arr.len() >= 2 {
52                    if let Some(query) = arr[0].as_str() {
53                        if let Some(suggestions) = arr[1].as_array() {
54                            let mut suggs = Vec::new();
55                            for s in suggestions {
56                                if let Some(s_str) = s.as_str() {
57                                    suggs.push(s_str.to_string());
58                                }
59                            }
60                            return GoogleAutocompleteResult {
61                                query: query.to_string(),
62                                suggestions: suggs,
63                            };
64                        }
65                    }
66                }
67            }
68        }
69        GoogleAutocompleteResult::default()
70    }
71
72    pub fn parse_generic(html: &str, url: &str) -> GenericGoogleResult {
73        let dom = match DomTree::parse(html) {
74            Ok(d) => d,
75            Err(_) => {
76                return GenericGoogleResult {
77                    query: url.to_string(),
78                    title: "Parse Error".to_string(),
79                    raw_markdown: "Error parsing HTML".to_string(),
80                }
81            }
82        };
83        let title = dom
84            .extract(Some("title"))
85            .unwrap_or_else(|| "Google Result".to_string());
86        let md = dom.extract_markdown(None, Some(url));
87        GenericGoogleResult {
88            query: url.to_string(),
89            title,
90            raw_markdown: md,
91        }
92    }
93}