SPB Git forge

spb/resto-ka

Public

Resto·Ka — tous les restaurants du Québec, menus complets et prix réels (famille ·Ka)

52commits 1branches 0releases
11.6 MBsize
maindefault branch
19 days agolast push
Python 69.3% TypeScript 16.7% CSS 7.9% JavaScript 4.7% HTML 1.4%
4.5 KB · 101 lines python
Raw Blame History
1# ==============================================================================2# Author: Simon-Pierre Boucher <contact@spboucher.ai>3# File:   tests/test_yelp_scrape.py4# Desc:   Connecteur yelp-scrape (avis/notes sans clé API) — parsing HORS5#         LIGNE du cache Apollo embarqué dans une page de recherche yelp.ca6#         (scripts data-apollo-state HTML-échappés) et croisement CONSERVATEUR7#         nom + civique + ville (ambigu ou fermé = ignoré).8# ==============================================================================9import html10import json1112from restoka.connectors.yelp_scrape import (_city_key, match_business,13                                            parse_apollo_businesses)1415# Cache Apollo minimal, encodé comme sur yelp.ca (&quot; dans un commentaire)16_CACHE = {17    "BusinessCategory:cat1": {"__typename": "BusinessCategory",18                              "encid": "cat1", "title": "Poutineries"},19    "BusinessLocation:loc1": {20        "__typename": "BusinessLocation", "encid": "loc1",21        "address": {"__typename": "BusinessAddress",22                    "city": "Quebec City",23                    "addressLine1": "640 Grande Allée E"},24        "neighborhoods": [],25    },26    "Business:biz1": {27        "__typename": "Business", "encid": "biz1",28        "alias": "chez-ashton-québec-2", "name": "Chez Ashton",29        "rating": 3.5, "reviewCount": 42,30        "categories": [{"__ref": "BusinessCategory:cat1"}],31        "priceRange": {"__typename": "PriceRange", "display": "$"},32        "location": {"__ref": "BusinessLocation:loc1"},33        'activeAlert({"deviceType":"WWW"})': None,34    },35    "BusinessLocation:loc2": {36        "__typename": "BusinessLocation", "encid": "loc2",37        "address": {"__typename": "BusinessAddress",38                    "city": "Levis", "addressLine1": "5430 Rue Wilfrid-Hallé"},39        "neighborhoods": [],40    },41    "Business:biz2": {   # fermé définitivement -> jamais croisé42        "__typename": "Business", "encid": "biz2",43        "alias": "chez-ashton-levis", "name": "Chez Ashton",44        "rating": 4.0, "reviewCount": 3,45        "categories": [], "priceRange": None,46        "location": {"__ref": "BusinessLocation:loc2"},47        'activeAlert({"deviceType":"WWW"})': {"__typename": "BusinessAlert",48                                              "type": "permclosed"},49    },50}515253def _page(cache: dict) -> str:54    blob = html.escape(json.dumps(cache, ensure_ascii=False), quote=True)55    return ('<html><body><script data-apollo-state="x" '56            f'type="application/json"><!--{blob}--></script></body></html>')575859def test_parse_apollo_businesses():60    biz = parse_apollo_businesses(_page(_CACHE))61    assert len(biz) == 262    b1 = next(b for b in biz if b["alias"] == "chez-ashton-québec-2")63    assert b1["rating"] == 3.5 and b1["review_count"] == 4264    assert b1["price"] == "$" and b1["categories"] == ["Poutineries"]65    assert b1["city"] == "Quebec City"66    assert b1["address"] == "640 Grande Allée E"67    assert b1["closed"] is False68    b2 = next(b for b in biz if b["alias"] == "chez-ashton-levis")69    assert b2["closed"] is True707172def test_city_key():73    assert _city_key("Quebec City") == "quebec"74    assert _city_key("Québec") == "quebec"75    assert _city_key("Montréal") == "montreal"76    assert _city_key("Saint-Nicolas") == "saint nicolas"777879def test_match_business_conservateur():80    candidates = parse_apollo_businesses(_page(_CACHE))81    resto = {"name": "Chez Ashton", "city": "Québec",82             "address": "640 Grande Allée Est"}83    hit = match_business(resto, candidates)84    assert hit and hit["alias"] == "chez-ashton-québec-2"8586    # mauvais civique -> aucun croisement (voisin de la même rue)87    assert match_business({"name": "Chez Ashton", "city": "Québec",88                           "address": "700 Grande Allée Est"},89                          candidates) is None90    # le permclosed de Lévis n'est jamais retenu, même ville exacte91    assert match_business({"name": "Chez Ashton", "city": "Lévis",92                           "address": "5430 Rue Wilfrid-Hallé"},93                          candidates) is None94    # ambiguïté (deux commerces distincts qui passent) -> None95    cache2 = dict(_CACHE)96    cache2["Business:biz3"] = dict(_CACHE["Business:biz1"],97                                   encid="biz3", alias="ashton-restaurant",98                                   name="Restaurant Ashton")99    cands2 = parse_apollo_businesses(_page(cache2))100    assert match_business(resto, cands2) is None101