Repository: alltheplaces/alltheplaces

Issue:
Houlihan's
http://www.houlihans.com/find-a-location


Discussion:
* POSTing `{'storeNumber': '623'}` to http://www.houlihans.com/DataHelper.aspx/GetStoreLocationsByNumber gives stores near the given store
* POSTing `{'lat': '40.71', 'lon': '-74'}` to http://www.houlihans.com/DataHelper.aspx/GetStoreLocations gives stores near that point
* Must include a `Content-Type: application/json` request header
* Search radius unknown
* Like [Disco](90), it returns a JSON object with a "d" key with a string with more JSON; it might be a generic .NET thing.
No progress for 2 days, re-opening this for others.

Resolving patch:
diff --git a/locations/spiders/houlihans.py b/locations/spiders/houlihans.py
new file mode 100644
--- /dev/null
+++ b/locations/spiders/houlihans.py
@@ -0,0 +1,49 @@
+# -*- coding: utf-8 -*-
+import scrapy
+import re
+
+from locations.items import GeojsonPointItem
+
+
+class HoulihansSpider(scrapy.Spider):
+    name = "houlihans"
+    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 GeojsonPointItem(**properties)
+
+        else:
+            pass
\ No newline at end of file


Test patch: