Repository: alltheplaces/alltheplaces

Issue:
Spider houlihans is broken
During the global build at 2021-10-13-14-42-23, spider **houlihans** failed with **0 features** and **0 errors**.

Here's [the log](https://data.alltheplaces.xyz/runs/2021-10-13-14-42-23/logs/houlihans.txt) and [the output](https://data.alltheplaces.xyz/runs/2021-10-13-14-42-23/output/houlihans.geojson) ([on a map](https://data.alltheplaces.xyz/map.html?show=https://data.alltheplaces.xyz/runs/2021-10-13-14-42-23/output/houlihans.geojson))


Discussion:

Resolving patch:
diff --git a/locations/spiders/houlihans.py b/locations/spiders/houlihans.py
deleted file mode 100644
--- a/locations/spiders/houlihans.py
+++ /dev/null
@@ -1,71 +0,0 @@
-import re
-
-import scrapy
-
-from locations.items import Feature
-
-
-class HoulihansSpider(scrapy.Spider):
-    name = "houlihans"
-    item_attributes = {"brand": "Houlihan's", "brand_wikidata": "Q5913100s"}
-    allowed_domains = ["houlihans.com"]
-    start_urls = ("http://www.houlihans.com/sitemap.xml",)
-
-    def parse(self, response):
-        response.selector.remove_namespaces()
-        city_urls = response.xpath("//url/loc/text()").extract()
-        regex = re.compile(r"http(s://|://www.)houlihans.com/my-houlihans/\S+")
-        for path in city_urls:
-            if re.search(regex, path):
-                yield scrapy.Request(
-                    path.strip(),
-                    callback=self.parse_store,
-                )
-            else:
-                pass
-
-    def parse_store(self, response):
-        regex = re.compile(r"http(s://|://www.)houlihans.com/my-houlihans/\S+")
-        if re.search(regex, response.request.url):
-            properties = {
-                "name": response.xpath('//span[@itemprop="name"]/text()').extract_first(),
-                "ref": response.xpath('//span[@itemprop="name"]/text()').extract_first(),
-                "addr_full": response.xpath('//span[@itemprop="streetAddress"]/text()').extract_first(),
-                "city": response.xpath('//span[@itemprop="addressLocality"]/text()').extract_first(),
-                "state": response.xpath('//span[@itemprop="addressRegion"]/text()').extract_first(),
-                "postcode": response.xpath('//span[@itemprop="postalCode"]/text()').extract_first(),
-                "phone": response.xpath('//span[@itemprop="telephone"]/a/text()').extract_first(),
-                "website": response.request.url,
-                "opening_hours": " ".join(
-                    str(
-                        response.xpath(
-                            '//div[@id="header"]/div/div/div/div/div[@class="location-hours"]/p/span/text()'
-                        ).extract()
-                    )
-                    .replace("\\r", "")
-                    .replace(",", " -")
-                    .split()
-                )
-                .replace("[", "")
-                .replace("]", "")
-                .replace("'", ""),
-                "lat": float(
-                    response.xpath('//div/div[@class="location-actions"]/a[@href]')
-                    .extract_first()
-                    .split("q=")[1]
-                    .split("%")[0]
-                    .split(",")[0]
-                ),
-                "lon": float(
-                    response.xpath('//div/div[@class="location-actions"]/a[@href]')
-                    .extract_first()
-                    .split("q=")[1]
-                    .split("%")[0]
-                    .split(",")[1]
-                ),
-            }
-
-            yield Feature(**properties)
-
-        else:
-            pass
diff --git a/locations/spiders/houlihans_us.py b/locations/spiders/houlihans_us.py
new file mode 100644
--- /dev/null
+++ b/locations/spiders/houlihans_us.py
@@ -0,0 +1,40 @@
+import re
+
+from scrapy import Request, Spider
+
+from locations.hours import OpeningHours
+from locations.items import Feature
+
+
+class HoulihansUSSpider(Spider):
+    name = "houlihans_us"
+    item_attributes = {"brand": "Houlihan's", "brand_wikidata": "Q5913100s"}
+    allowed_domains = ["houlihans.com"]
+    start_urls = ["https://houlihans.com/Locations"]
+    # Some location pages were observed to redirect back to the location list page.
+    custom_settings = {"REDIRECT_ENABLED": False}
+
+    def start_requests(self):
+        for url in self.start_urls:
+            yield Request(url=url, callback=self.parse_location_urls)
+
+    def parse_location_urls(self, response):
+        for location_url in response.xpath('//li[@class="locations"]/a[not(@id="mars")]/@href').getall():
+            yield Request(url="https://houlihans.com" + location_url)
+
+    def parse(self, response):
+        properties = {
+            "ref": response.url,
+            "name": re.sub(r"\s+", " ", response.xpath('//h1[@class="loc-name"]/text()').get()).strip(),
+            "addr_full": re.sub(
+                r"\s+", " ", " ".join(response.xpath('//p[@class="loc-address"]/a/text()').getall())
+            ).strip(),
+            "phone": response.xpath('//p[@class="loc-phone"]/a/text()').get().strip(),
+            "website": response.url,
+        }
+        hours_string = " ".join(
+            filter(None, response.xpath('//p[@class="loc-hours"]/following-sibling::p[not(@*)]').getall())
+        )
+        properties["opening_hours"] = OpeningHours()
+        properties["opening_hours"].add_ranges_from_string(hours_string)
+        yield Feature(**properties)


Test patch: