Repository: alltheplaces/alltheplaces

Issue:
Hallmark
https://stores.hallmark.com/


Discussion:
@iandees I'm working on this
Here's the sample output:

```
{"type": "Feature", "id": "XXb1ClZWWdgERoXuXLexM9uNucs=", "properties": {"ref": "002882_2238809", "@spider": "hallmark", "addr:street": "1716 Main St", "addr:city": "Parsons", "addr:state": "KS", "addr:postcode": "67357-3339", "addr:country": "US", "name": "George's Gifts & Cards", "phone": "(620) 421-5930", "website": "https://stores.hallmark.com/ks/parsons/georges-gifts-cards-parsons-ks-002882.html", "opening_hours": "Mo-Fr 10:00-18:00; Sa 10:00-17:00", "brand": "Hallmark"}, "geometry": {"type": "Point", "coordinates": [-95.261176452041, 37.340449914336]}},
{"type": "Feature", "id": "PifkZNrXKYESMrVuV42IKYr9vs0=", "properties": {"ref": "032776_2238313", "@spider": "hallmark", "addr:street": "12906 E 86Th St N Owasso Town Center", "addr:city": "Owasso", "addr:state": "OK", "addr:postcode": "74055-8701", "addr:country": "US", "name": "J's Hallmark Shop-Curbside Pick Up Available", "phone": "(918) 272-4473", "website": "https://stores.hallmark.com/ok/owasso/js-hallmark-shop-curbside-pick-up-available-owasso-ok-032776.html", "opening_hours": "Mo-Sa 10:00-20:00; Su 12:00-18:00", "brand": "Hallmark"}, "geometry": {"type": "Point", "coordinates": [-95.829423218966, 36.278525143862]}},
{"type": "Feature", "id": "TGBtU4yJVvwek0MpLXj19dB7MZw=", "properties": {"ref": "037440_2232233", "@spider": "hallmark", "addr:street": "1651 W 7Th St Ste 14 Joplin West Plaza", "addr:city": "Joplin", "addr:state": "MO", "addr:postcode": "64801-3018", "addr:country": "US", "name": "Judy's Hallmark Shop", "phone": "(417) 623-1997", "website": "https://stores.hallmark.com/mo/joplin/judys-hallmark-shop-joplin-mo-037440.html", "opening_hours": "Mo-Fr 10:00-18:00; Sa 10:00-17:00", "brand": "Hallmark"}, "geometry": {"type": "Point", "coordinates": [-94.532920837402, 37.085983276367]}},
{"type": "Feature", "id": "onIoS31DHtMXGYUAemjAwUpGTXY=", "properties": {"ref": "054510_2232855", "@spider": "hallmark", "addr:street": "6544 E 51St St The Farm Shopping Center", "addr:city": "Tulsa", "addr:state": "OK", "addr:postcode": "74145-7603", "addr:country": "US", "name": "J's Hallmark Shop-Curbside Pick Up Available", "phone": "(918) 664-2000", "website": "https://stores.hallmark.com/ok/tulsa/js-hallmark-shop-curbside-pick-up-available-tulsa-ok-054510.html", "opening_hours": "Mo-Sa 10:00-19:00; Su 12:00-18:00", "brand": "Hallmark"}, "geometry": {"type": "Point", "coordinates": [-95.903305336833, 36.089825034142]}},
{"type": "Feature", "id": "Kx0psUgc0Vbs89mqGkLIvHqwJC0=", "properties": {"ref": "035116_2238751", "@spider": "hallmark", "addr:street": "708 S Aspen Ave", "addr:city": "Broken Arrow", "addr:state": "OK", "addr:postcode": "74012-4801", "addr:country": "US", "name": "Westlake Ace Hardware", "phone": "(918) 258-1261", "website": "https://stores.hallmark.com/ok/brokenarrow/westlake-ace-hardware-brokenarrow-ok-035116.html", "opening_hours": "Mo-Sa 08:00-21:00; Su 09:00-18:00", "brand": "Hallmark"}, "geometry": {"type": "Point", "coordinates": [-95.81657, 36.04583]}}
```

Resolving patch:
diff --git a/locations/spiders/hallmark.py b/locations/spiders/hallmark.py
new file mode 100644
--- /dev/null
+++ b/locations/spiders/hallmark.py
@@ -0,0 +1,50 @@
+# -*- coding: utf-8 -*-
+import json
+
+import scrapy
+from locations.hours import OpeningHours
+from locations.items import GeojsonPointItem
+from scrapy.selector import Selector
+
+
+class HallmarkSpider(scrapy.Spider):
+    name = 'hallmark'
+    item_attributes = {'brand': 'Hallmark'}
+    allowed_domains = ['www.hallmark.com']
+    start_urls = ['https://maps.hallmark.com/api/getAsyncLocations?template=search&level=search&search=66952&radius=10000&limit=3000']
+
+    def parse(self, response):
+        maplist = json.loads(response.text)['maplist']
+        data = json.loads("[{}]".format(Selector(text=maplist).xpath('//div/text()').extract_first()[:-1]))
+        for location in data:
+            hours = json.loads(location['hours_sets:primary'])
+            properties = {
+                'name': location['location_name'],
+                'ref': location['fid'] + "_" + location['lid'],
+                'street': location['address_1'] + " " + location['address_2'] if location['address_2'] else location['address_1'],
+                'city': location['city'],
+                'postcode': location['post_code'],
+                'state': location['region'],
+                'country': location['country'],
+                'phone': location['local_phone'],
+                'website': location['url'],
+                'lat': float(location['lat']),
+                'lon': float(location['lng']),
+                'opening_hours': self.parse_hours(hours['days']) if hours.get('days') else None
+            }
+            yield GeojsonPointItem(**properties)
+
+    def parse_hours(self, store_hours):
+        opening_hours = OpeningHours()
+
+        for weekday in store_hours:
+            day = weekday.title()
+            for interval in store_hours[weekday]:
+                if isinstance(interval, dict):                   
+                    open_time = str(interval.get("open"))
+                    close_time = str(interval.get("close"))
+                    opening_hours.add_range(day=day[:2],
+                                            open_time=open_time,
+                                            close_time=close_time,
+                                            time_format='%H:%M')
+        return opening_hours.as_opening_hours()


Test patch: