|
21 | 21 | const rand = (min, max) => Math.floor(Math.random() * (max - min) + min); |
22 | 22 | const qs = (root, sel) => { try { return root.querySelector(sel); } catch { return null; } }; |
23 | 23 | const qsa = (root, sel) => { try { return Array.from(root.querySelectorAll(sel)); } catch { return []; } }; |
| 24 | + const cleanUrl = (url) => { |
| 25 | + if (!url) return ""; |
| 26 | + try { |
| 27 | + const u = new URL(url); |
| 28 | + if (u.hostname.includes("google.") && u.pathname === "/url") { |
| 29 | + return u.searchParams.get("q") || url; |
| 30 | + } |
| 31 | + } catch (e) {} |
| 32 | + return url; |
| 33 | + }; |
| 34 | + const isUnrelated = (url, label) => { |
| 35 | + if (!url) return true; |
| 36 | + const lowerUrl = url.toLowerCase(); |
| 37 | + const lowerLabel = (label || "").toLowerCase(); |
| 38 | + const unrelatedPatterns = [ |
| 39 | + "google.com/searchviewer", |
| 40 | + "google.com/maps/reserve", |
| 41 | + "eat.chownow.com", |
| 42 | + "opentable.com", |
| 43 | + "allmenus.com", |
| 44 | + "fooddiscoveryapp.com" |
| 45 | + ]; |
| 46 | + if (unrelatedPatterns.some((p) => lowerUrl.includes(p))) return true; |
| 47 | + if (lowerLabel.includes("menu") || lowerLabel.includes("order online") || lowerLabel.includes("reservation")) return true; |
| 48 | + return false; |
| 49 | + }; |
24 | 50 |
|
25 | 51 | function getFeed() { |
26 | 52 | return ( |
|
96 | 122 |
|
97 | 123 | const websiteEl = |
98 | 124 | qs(card, 'a[data-value="Website"]') || |
99 | | - qs(card, 'a[aria-label^="Visit"]') || |
100 | 125 | qs(card, 'a[aria-label*="website" i]'); |
101 | | - const website = websiteEl?.href || ""; |
| 126 | + let website = cleanUrl(websiteEl?.href || ""); |
| 127 | + if (isUnrelated(website, websiteEl?.getAttribute("aria-label"))) website = ""; |
102 | 128 |
|
103 | 129 | if (!name) return null; |
104 | 130 | const { city, country } = parseAddress(address); |
|
132 | 158 | if (!link) return lead; |
133 | 159 |
|
134 | 160 | link.click(); |
135 | | - // Wait for the detail panel to load (heading appears) |
| 161 | + // Wait for the detail panel to load and update to the NEW business (avoid stale data) |
136 | 162 | let panelEl = null; |
137 | | - for (let i = 0; i < 25; i++) { |
138 | | - await sleep(180); |
| 163 | + for (let i = 0; i < 30; i++) { |
| 164 | + await sleep(200); |
139 | 165 | panelEl = |
140 | 166 | document.querySelector('div[role="main"][aria-label]') || |
141 | | - document.querySelector('div.m6QErb.DxyBCb'); |
142 | | - const heading = panelEl && qs(panelEl, "h1"); |
143 | | - if (heading && heading.textContent.trim()) break; |
| 167 | + document.querySelector('div.m6QErb.DxyBCb') || |
| 168 | + document.querySelector('div[role="region"][aria-label]'); |
| 169 | + const heading = panelEl && qs(panelEl, "h1")?.textContent?.trim(); |
| 170 | + if (heading && (heading.includes(lead.name) || lead.name.includes(heading))) break; |
144 | 171 | } |
145 | 172 | if (!panelEl) return lead; |
146 | 173 |
|
|
168 | 195 | } |
169 | 196 |
|
170 | 197 | // Website (authority link) |
171 | | - const siteBtn = qs(panelEl, 'a[data-item-id="authority"]') || qs(panelEl, 'a[aria-label^="Website"]'); |
| 198 | + const siteBtn = |
| 199 | + qs(panelEl, 'a[data-item-id="authority"]') || |
| 200 | + qs(panelEl, 'a[aria-label^="Website:"]') || |
| 201 | + qs(panelEl, 'a[aria-label="Open website"]') || |
| 202 | + qs(panelEl, 'a[aria-label^="Website"]'); |
172 | 203 | if (siteBtn?.href) { |
173 | | - lead.website = siteBtn.href; |
174 | | - lead.hasWebsite = "Yes"; |
| 204 | + const url = cleanUrl(siteBtn.href); |
| 205 | + const label = siteBtn.getAttribute("aria-label"); |
| 206 | + if (url && !url.includes("google.com/maps") && !isUnrelated(url, label)) { |
| 207 | + lead.website = url; |
| 208 | + lead.hasWebsite = "Yes"; |
| 209 | + } |
175 | 210 | } |
176 | 211 |
|
177 | 212 | // Scan all anchors in the panel for socials / whatsapp / mailto |
|
0 commit comments