Repository: alltheplaces/alltheplaces

Issue:
Sobeys (CA) (supermarkets) (241 locations)
### Brand name

Sobeys

### Wikidata ID

Q1143340

### Store finder url(s)

https://www.sobeys.com/store-locator/


Discussion:

Resolving patch:
diff --git a/locations/hours.py b/locations/hours.py
--- a/locations/hours.py
+++ b/locations/hours.py
@@ -777,12 +777,12 @@ def time_of_day_regex(time_24h: bool = True) -> str:
         """
         if time_24h is True:
             # Regular expression for extracting 24h times (e.g. 15:45)
-            time_regex = r"(?<!\d)(\d(?!\d)|[01]\d|2[0-4])(?:(?:[:\.]?([0-5]\d))(?:[:\.]?[0-5]\d)?)?(?!(?:\d|:|[AP]M))"
-        else:
-            # Regular expression for extracting 12h times (e.g. 9:30AM)
             time_regex = (
-                r"(?<!\d)(\d(?!\d)|0\d|1[012])(?:(?:[:\.]?([0-5]\d))(?:[:\.]?[0-5]\d)?)?\s*([AP]M)?(?!(?:\d|:|[AP]M))"
+                r"(?<!\d)(\d(?!\d)|[01]\d|2[0-4])(?:(?:[:\.]?([0-5]\d))(?:[:\.]?[0-5]\d)?)?(?!(?:\d|:|[AP]\.?M\.?))"
             )
+        else:
+            # Regular expression for extracting 12h times (e.g. 9:30AM)
+            time_regex = r"(?<!\d)(\d(?!\d)|0\d|1[012])(?:(?:[:\.]?([0-5]\d))(?:[:\.]?[0-5]\d)?)?\s*([AP]\.?M\.?)?(?!(?:\d|:|[AP]\.?M\.?))"
         return time_regex
 
     @staticmethod
@@ -955,7 +955,7 @@ def extract_hours_from_string(
                     else:
                         time_start = f"{time_start_hour}:00"
                     if time_range[2]:
-                        time_start = f"{time_start}{time_range[2].upper()}"
+                        time_start = f"{time_start}{time_range[2].upper()}".replace(".", "")
                     else:
                         # If AM/PM is not specified, it is almost always going to be AM for start times.
                         time_start = f"{time_start}AM"
@@ -969,7 +969,7 @@ def extract_hours_from_string(
                     else:
                         time_end = f"{time_end_hour}:00"
                     if time_range[5]:
-                        time_end = f"{time_end}{time_range[5].upper()}"
+                        time_end = f"{time_end}{time_range[5].upper()}".replace(".", "")
                     else:
                         # If AM/PM is not specified, it is almost always going to be PM for end times.
                         time_end = f"{time_end}PM"
diff --git a/locations/spiders/sobeys_ca.py b/locations/spiders/sobeys_ca.py
new file mode 100644
--- /dev/null
+++ b/locations/spiders/sobeys_ca.py
@@ -0,0 +1,35 @@
+from json import loads
+
+from scrapy import Spider
+
+from locations.hours import OpeningHours
+from locations.items import Feature
+
+
+class SobeysCASpider(Spider):
+    name = "sobeys_ca"
+    item_attributes = {"brand": "Sobeys", "brand_wikidata": "Q1143340"}
+    allowed_domains = ["www.sobeys.com"]
+    start_urls = ["https://www.sobeys.com/store-locator/"]
+
+    def parse(self, response):
+        for store in response.xpath('//div[@class="store-result "]'):
+            properties = {
+                "ref": store.xpath(".//@data-id").get(),
+                "name": store.xpath('.//span[@class="name"]/text()').get(),
+                "lat": store.xpath(".//@data-lat").get(),
+                "lon": store.xpath(".//@data-lng").get(),
+                "street_address": store.xpath('.//span[@class="location_address_address_1"]/text()').get(),
+                "city": store.xpath('.//span[@class="city"]/text()').get(),
+                "state": store.xpath('.//span[@class="province"]/text()').get().upper(),
+                "postcode": store.xpath('.//span[@class="postal_code"]/text()').get(),
+                "phone": store.xpath('.//span[@class="phone"]/a/text()').get(),
+                "website": store.xpath('.//a[@class="store-title"]/@href').get(),
+                "opening_hours": OpeningHours(),
+            }
+            hours_json = loads(store.xpath(".//@data-hours").get())
+            hours_string = " ".join(
+                ["{}: {}".format(day_name, hours_range) for day_name, hours_range in hours_json.items()]
+            )
+            properties["opening_hours"].add_ranges_from_string(hours_string)
+            yield Feature(**properties)


Test patch:
diff --git a/tests/test_opening_hours.py b/tests/test_opening_hours.py
--- a/tests/test_opening_hours.py
+++ b/tests/test_opening_hours.py
@@ -350,8 +350,8 @@ def test_add_ranges_from_string():
     o.add_ranges_from_string("Monday-Wednesday: 5pm - 7pm")
     o.add_ranges_from_string("Monday-Wednesday 08:00-14:00")
     o.add_ranges_from_string("Monday to Tuesday: 15:00:01 to 16:35")
-    o.add_ranges_from_string("Thurs 2PM-6:30PM")
-    o.add_ranges_from_string(" Fri    9am  -  11am ")
+    o.add_ranges_from_string("Thurs 2PM-6:30P.M.")
+    o.add_ranges_from_string(" Fri    9 a.m.  -  11am ")
     o.add_ranges_from_string("Weekends: 8:00 AM to 6:00 PM")
     assert (
         o.as_opening_hours()