Repository: alltheplaces/alltheplaces

Issue:
Wiener Feinbäckerei Heberer GmbH (DE) (shop/bakery) (Wordpress) - 50+ locations
### Brand name

Wiener Feinbäckerei Heberer GmbH

German bakery retail chain

### Wikidata ID

Q15854357
https://www.wikidata.org/wiki/Q15854357
https://www.wikidata.org/wiki/Special:EntityData/Q15854357.json

### Store finder url(s)

Official Url(s): https://heberer.de
- [x] I have run the below and if anything in generated, added it.
- [x] I have manually checked for a storefinder
- [x] This is not a manufacturer listing outlets operating under their own brands / this will not create duplicates
`pipenv run scrapy sf --brand-wikidata=Q15854357 https://heberer.de`
```
from locations.storefinders.wp_store_locator import WPStoreLocatorSpider


class NewBrandZZSpider(WPStoreLocatorSpider):
        name = "new_brand_zz"
        allowed_domains = [
                "heberer.de",
        ]
```


Discussion:

Resolving patch:
diff --git a/locations/spiders/hit_de.py b/locations/spiders/hit_de.py
new file mode 100644
--- /dev/null
+++ b/locations/spiders/hit_de.py
@@ -0,0 +1,31 @@
+from html import unescape
+
+from chompjs import parse_js_object
+from scrapy import Spider
+
+from locations.categories import Categories
+from locations.dict_parser import DictParser
+from locations.hours import DAYS_DE, OpeningHours
+
+
+class HITDESpider(Spider):
+    name = "hit_de"
+    item_attributes = {"brand": "HIT", "brand_wikidata": "Q1548713", "extras": Categories.SHOP_SUPERMARKET.value}
+    allowed_domains = ["www.hit.de"]
+    start_urls = ["https://www.hit.de/maerkte?ajax=1"]
+
+    def parse(self, response):
+        js_blob = unescape(response.xpath("//div/@data-stores").get())
+        for location in parse_js_object(js_blob):
+            item = DictParser.parse(location)
+            item["ref"] = location["url"].split("/")[-1]
+            item["street_address"] = item.pop("street")
+
+            item["opening_hours"] = OpeningHours()
+            for day_hours in location.get("openings", []):
+                for day_of_week in day_hours["daysOfWeek"]:
+                    item["opening_hours"].add_range(
+                        DAYS_DE[day_of_week], day_hours["openedFrom"], day_hours["openedTo"]
+                    )
+
+            yield item
diff --git a/locations/spiders/wiener_feinbacker_heberer_de.py b/locations/spiders/wiener_feinbacker_heberer_de.py
new file mode 100644
--- /dev/null
+++ b/locations/spiders/wiener_feinbacker_heberer_de.py
@@ -0,0 +1,52 @@
+import re
+from html import unescape
+
+from scrapy import Selector
+
+from locations.categories import Categories
+from locations.hours import DAYS_DE, OpeningHours
+from locations.spiders.hit_de import HITDESpider
+from locations.spiders.karstadt_de import KarstadtDESpider
+from locations.spiders.kaufland import KauflandSpider
+from locations.spiders.rewe_de import REWEDESpider
+from locations.storefinders.wp_store_locator import WPStoreLocatorSpider
+
+
+class WienerFeinbackerHebererDESpider(WPStoreLocatorSpider):
+    name = "wiener_feinbacker_heberer_de"
+    item_attributes = {
+        "brand": "Wiener Feinbäcker Heberer",
+        "brand_wikidata": "Q15854357",
+        "extras": Categories.SHOP_BAKERY.value,
+    }
+    allowed_domains = ["heberer.de"]
+
+    def parse_item(self, item, location):
+        item.pop("addr_full", None)
+
+        item["name"] = unescape(item["name"])
+        if len(item["name"].split(" (")) > 1:
+            old_name = item["name"]
+            item["name"], located_in_tag = old_name.split(" (", 1)
+            if re.search(r"\WRewe\W", located_in_tag, flags=re.IGNORECASE):
+                item["located_in"] = REWEDESpider.item_attributes["brand"]
+                item["located_in_wikidata"] = REWEDESpider.item_attributes["brand_wikidata"]
+            elif re.search(r"\WHIT\W", located_in_tag, flags=re.IGNORECASE):
+                item["located_in"] = HITDESpider.item_attributes["brand"]
+                item["located_in_wikidata"] = HITDESpider.item_attributes["brand_wikidata"]
+            elif re.search(r"\WKarstadt\W", located_in_tag, flags=re.IGNORECASE):
+                item["located_in"] = KarstadtDESpider.item_attributes["brand"]
+                item["located_in_wikidata"] = KarstadtDESpider.item_attributes["brand_wikidata"]
+            elif re.search(r"\WKaufland\W", located_in_tag, flags=re.IGNORECASE):
+                item["located_in"] = KauflandSpider.item_attributes["brand"]
+                item["located_in_wikidata"] = KauflandSpider.item_attributes["brand_wikidata"]
+            else:
+                item["name"] = old_name
+
+        hours_string = " ".join(
+            filter(None, map(str.strip, Selector(text=location["description"]).xpath("//text()").getall()))
+        )
+        item["opening_hours"] = OpeningHours()
+        item["opening_hours"].add_ranges_from_string(hours_string, days=DAYS_DE)
+
+        yield item


Test patch: