Repository: alltheplaces/alltheplaces

Issue:
RONA
https://www.rona.ca/en/find-a-store


Discussion:

Resolving patch:
diff --git a/locations/spiders/rona.py b/locations/spiders/rona.py
new file mode 100644
--- /dev/null
+++ b/locations/spiders/rona.py
@@ -0,0 +1,68 @@
+# -*- coding: utf-8 -*-
+import re
+
+import scrapy
+
+from locations.items import GeojsonPointItem
+from locations.hours import OpeningHours
+
+
+class RonaSpider(scrapy.Spider):
+    name = "rona"
+    item_attributes = {'brand': 'RONA'}
+    allowed_domains = ['www.rona.ca']
+    start_urls = [
+        'https://www.rona.ca/sitemap-stores-en.xml',
+    ]
+    custom_settings = {
+        'USER_AGENT': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36',
+    }
+    download_delay = 30
+
+    def parse(self, response):
+        response.selector.remove_namespaces()
+        locations = response.xpath('//url/loc/text()').extract()
+        for location in locations:
+            yield scrapy.Request(location, callback=self.parse_store)
+
+    def parse_hours(self, hours):
+        opening_hours = OpeningHours()
+        day_hours = hours.xpath('.//li/time[@itemprop="openingHours"]/@datetime').extract()
+
+        for open_hours in day_hours:
+            day, open_close = open_hours.split(' ')
+            open_time, close_time = open_close.split('-')
+            opening_hours.add_range(day=day,
+                                    open_time=open_time,
+                                    close_time=close_time,
+                                    time_format='%H:%M'
+                                    )
+
+        return opening_hours.as_opening_hours()
+
+    def parse_store(self, response):
+        phone_text = response.xpath('normalize-space(//div[@itemprop="telephone"]//text())').extract_first()
+        if phone_text:
+            phone = ''.join(re.findall(r'([0-9]+)', phone_text))
+        else:
+            phone = None
+
+        properties = {
+            'ref': re.search(r'.+/(.+?)/?(?:\.html|$)', response.url).group(1),
+            'name': response.xpath('normalize-space(//*[@itemprop="name"]//text())').extract_first(),
+            'addr_full': response.xpath('normalize-space(//span[@itemprop="streetAddress"]//text())').extract_first(),
+            'city': response.xpath('normalize-space(//span[@itemprop="addressLocality"]//text())').extract_first(),
+            'state': response.xpath('normalize-space(//span[@itemprop="addressRegion"]//text())').extract_first(),
+            'postcode': response.xpath('normalize-space(//span[@itemprop="postalCode"]//text())').extract_first(),
+            'country': 'CA',
+            'phone': phone,
+            'website': response.url,
+            'lat': float(response.xpath('normalize-space(//meta[@itemprop="latitude"]/@content)').extract_first()),
+            'lon': float(response.xpath('normalize-space(//meta[@itemprop="longitude"]/@content)').extract_first()),
+        }
+
+        hours = response.xpath('(//ul[@class="storedetails__list storedetails__list-hours"])[1]')
+        if hours:
+            properties['opening_hours'] = self.parse_hours(hours)
+
+        yield GeojsonPointItem(**properties)


Test patch: