diff --git a/backend/app/services/scraper_service.py b/backend/app/services/scraper_service.py index 0b65b51..b0275f1 100644 --- a/backend/app/services/scraper_service.py +++ b/backend/app/services/scraper_service.py @@ -13,57 +13,71 @@ logger = logging.getLogger(__name__) class ScraperService: @staticmethod - def _extract_rating_and_reviews(detail_panel, text_fallback: str = "") -> tuple: + def _extract_card_rating_and_reviews(card) -> tuple: """ - Extrai a nota de avaliação (ex: 4.8) e o total de avaliações (ex: 150) - específicos de cada estabelecimento no Google Maps. + Extrai a nota (rating) e a quantidade total de avaliações estritamente + escopadas dentro do container do próprio card do estabelecimento. + Evita a repetição de dados globais ou de cabeçalho. """ rating = 0.0 total_avaliacoes = 0 - if detail_panel: - # 1. Procurar elemento específico de nota (ex: ou ) - star_elem = detail_panel.query_selector("[aria-label*='estrela'], [aria-label*='star'], span.ceYyJf, div.F7L8d") - if star_elem: - aria_txt = star_elem.get_attribute("aria-label") or star_elem.inner_text() - m = re.search(r'([1-5][.,]\d)', aria_txt) + if not card: + return rating, total_avaliacoes + + try: + # 1. Procurar aria-labels contendo informações de estrelas/avaliações no próprio card ou em seus filhos + aria_elems = card.query_selector_all("[aria-label*='estrela'], [aria-label*='star'], [aria-label*='avaliaç']") + card_label = card.get_attribute("aria-label") or "" + combined_aria = " ".join([e.get_attribute("aria-label") or "" for e in aria_elems] + [card_label]) + + r_match = re.search(r'([1-5][.,]\d)\s*(?:estrelas?|stars?)', combined_aria, re.IGNORECASE) + if r_match: + try: + rating = float(r_match.group(1).replace(',', '.')) + except ValueError: + pass + + rev_match = re.search(r'([\d.,]+)\s*avaliaç', combined_aria, re.IGNORECASE) + if rev_match: + try: + total_avaliacoes = int(re.sub(r'\D', '', rev_match.group(1))) + except ValueError: + pass + + # 2. Extrair do texto bruto (inner_text) exclusivo do card do estabelecimento + card_text = card.inner_text() or "" + + if rating == 0.0: + # No Google Maps a nota no card vem em formatos como "4,8 (120)" ou "4.8" + m = re.search(r'([1-5][.,]\d)\s*(?:\(|\s*★|\s*estrelas?)', card_text, re.IGNORECASE) + if not m: + m = re.search(r'([1-5][.,]\d)', card_text) if m: try: - rating = float(m.group(1).replace(',', '.')) + val = float(m.group(1).replace(',', '.')) + if 1.0 <= val <= 5.0: + rating = val except ValueError: pass - # 2. Procurar elemento específico de total de avaliações (ex: