prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Caffe Nero GB spider using outdated JSON file
  The caffe_nero_gb.py spider gets its data from JSON file that the Store Finder page at https://caffenero.com/uk/stores/ uses to display its map. However, it looks like that URL of that JSON file has changed, and ATP is still referencing the old (and no longer updated one).
  
  The ATP code currently has
  `allowed_domains = ["caffenero-webassets-production.s3.eu-west-2.amazonaws.com"]`
  `start_urls = ["https://caffenero-webassets-production.s3.eu-west-2.amazonaws.com/stores/stores_gb.json"]`
  But the URL referenced by https://caffenero.com/uk/stores/ is now
  https://caffenerowebsite.blob.core.windows.net/production/data/stores/stores-gb.json
  
  I think the format of the JSON file has remained the same, so it should just be a matter of swapping the URLs over.
  
  To help issues like this be picked up sooner in the future, I wonder if there's a way of checking that the JSON URL used is still included in the https://caffenero.com/uk/stores/ page, and producing a warning to anyone running ATP if not?
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `locations/spiders/caffe_nero_gb.py`
  Content:
  ```
  1 from scrapy import Spider
  2 from scrapy.http import JsonRequest
  3 
  4 from locations.categories import Categories, Extras, apply_category, apply_yes_no
  5 from locations.dict_parser import DictParser
  6 from locations.hours import OpeningHours
  7 
  8 
  9 class CaffeNeroGBSpider(Spider):
  10     name = "caffe_nero_gb"
  11     item_attributes = {"brand": "Caffe Nero", "brand_wikidata": "Q675808"}
  12     allowed_domains = ["caffenero-webassets-production.s3.eu-west-2.amazonaws.com"]
  13     start_urls = ["https://caffenero-webassets-production.s3.eu-west-2.amazonaws.com/stores/stores_gb.json"]
  14 
  15     def start_requests(self):
  16         for url in self.start_urls:
  17             yield JsonRequest(url=url)
  18 
  19     def parse(self, response):
  20         for location in response.json()["features"]:
  21             if (
  22                 not location["properties"]["status"]["open"]
  23                 or location["properties"]["status"]["opening_soon"]
  24                 or location["properties"]["status"]["temp_closed"]
  25             ):
  26                 continue
  27 
  28             item = DictParser.parse(location["properties"])
  29             item["geometry"] = location["geometry"]
  30             if location["properties"]["status"]["express"]:
  31                 item["brand"] = "Nero Express"
  32 
  33             item["opening_hours"] = OpeningHours()
  34             for day_name, day_hours in location["properties"]["hoursRegular"].items():
  35                 if day_hours["open"] == "closed" or day_hours["close"] == "closed":
  36                     continue
  37                 if day_name == "holiday":
  38                     continue
  39                 item["opening_hours"].add_range(day_name.title(), day_hours["open"], day_hours["close"])
  40 
  41             apply_yes_no(Extras.TAKEAWAY, item, location["properties"]["status"]["takeaway"], False)
  42             apply_yes_no(Extras.DELIVERY, item, location["properties"]["status"]["delivery"], False)
  43             apply_yes_no(Extras.WIFI, item, location["properties"]["amenities"]["wifi"], False)
  44             apply_yes_no(Extras.TOILETS, item, location["properties"]["amenities"]["toilet"], False)
  45             apply_yes_no(Extras.BABY_CHANGING_TABLE, item, location["properties"]["amenities"]["baby_change"], False)
  46             apply_yes_no(Extras.SMOKING_AREA, item, location["properties"]["amenities"]["smoking_area"], False)
  47             apply_yes_no(Extras.AIR_CONDITIONING, item, location["properties"]["amenities"]["air_conditioned"], False)
  48             apply_yes_no(Extras.WHEELCHAIR, item, location["properties"]["amenities"].get("disabled_access"), False)
  49             apply_yes_no(Extras.TOILETS_WHEELCHAIR, item, location["properties"]["amenities"]["disabled_toilet"], False)
  50             apply_yes_no(Extras.OUTDOOR_SEATING, item, location["properties"]["amenities"]["outside_seating"], False)
  51             apply_category(Categories.COFFEE_SHOP, item)
  52 
  53             item["website"] = f'https://caffenero.com/uk/store/{location["properties"]["slug"]}/'
  54 
  55             yield item
  56
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/locations/spiders/caffe_nero_gb.py b/locations/spiders/caffe_nero_gb.py
  --- a/locations/spiders/caffe_nero_gb.py
  +++ b/locations/spiders/caffe_nero_gb.py
  @@ -1,5 +1,8 @@
  +import re
  +from typing import Any
  +
   from scrapy import Spider
  -from scrapy.http import JsonRequest
  +from scrapy.http import JsonRequest, Response
   
   from locations.categories import Categories, Extras, apply_category, apply_yes_no
   from locations.dict_parser import DictParser
  @@ -9,14 +12,15 @@
   class CaffeNeroGBSpider(Spider):
       name = "caffe_nero_gb"
       item_attributes = {"brand": "Caffe Nero", "brand_wikidata": "Q675808"}
  -    allowed_domains = ["caffenero-webassets-production.s3.eu-west-2.amazonaws.com"]
  -    start_urls = ["https://caffenero-webassets-production.s3.eu-west-2.amazonaws.com/stores/stores_gb.json"]
  +    allowed_domains = ["caffenero.com", "caffenerowebsite.blob.core.windows.net"]
  +    start_urls = ["https://caffenero.com/uk/stores/"]
   
  -    def start_requests(self):
  -        for url in self.start_urls:
  -            yield JsonRequest(url=url)
  +    def parse(self, response: Response, **kwargs: Any) -> Any:
  +        yield JsonRequest(
  +            re.search(r"loadGeoJson\(\n\s+'(https://.+)', {", response.text).group(1), callback=self.parse_geojson
  +        )
   
  -    def parse(self, response):
  +    def parse_geojson(self, response: Response, **kwargs: Any) -> Any:
           for location in response.json()["features"]:
               if (
                   not location["properties"]["status"]["open"]
  @@ -30,6 +34,8 @@
               if location["properties"]["status"]["express"]:
                   item["brand"] = "Nero Express"
   
  +            item["branch"] = item.pop("name")
  +
               item["opening_hours"] = OpeningHours()
               for day_name, day_hours in location["properties"]["hoursRegular"].items():
                   if day_hours["open"] == "closed" or day_hours["close"] == "closed":
  
verification_info: {"golden_diff": "diff --git a/locations/spiders/caffe_nero_gb.py b/locations/spiders/caffe_nero_gb.py\n--- a/locations/spiders/caffe_nero_gb.py\n+++ b/locations/spiders/caffe_nero_gb.py\n@@ -1,5 +1,8 @@\n+import re\n+from typing import Any\n+\n from scrapy import Spider\n-from scrapy.http import JsonRequest\n+from scrapy.http import JsonRequest, Response\n \n from locations.categories import Categories, Extras, apply_category, apply_yes_no\n from locations.dict_parser import DictParser\n@@ -9,14 +12,15 @@\n class CaffeNeroGBSpider(Spider):\n     name = \"caffe_nero_gb\"\n     item_attributes = {\"brand\": \"Caffe Nero\", \"brand_wikidata\": \"Q675808\"}\n-    allowed_domains = [\"caffenero-webassets-production.s3.eu-west-2.amazonaws.com\"]\n-    start_urls = [\"https://caffenero-webassets-production.s3.eu-west-2.amazonaws.com/stores/stores_gb.json\"]\n+    allowed_domains = [\"caffenero.com\", \"caffenerowebsite.blob.core.windows.net\"]\n+    start_urls = [\"https://caffenero.com/uk/stores/\"]\n \n-    def start_requests(self):\n-        for url in self.start_urls:\n-            yield JsonRequest(url=url)\n+    def parse(self, response: Response, **kwargs: Any) -> Any:\n+        yield JsonRequest(\n+            re.search(r\"loadGeoJson\\(\\n\\s+'(https://.+)', {\", response.text).group(1), callback=self.parse_geojson\n+        )\n \n-    def parse(self, response):\n+    def parse_geojson(self, response: Response, **kwargs: Any) -> Any:\n         for location in response.json()[\"features\"]:\n             if (\n                 not location[\"properties\"][\"status\"][\"open\"]\n@@ -30,6 +34,8 @@\n             if location[\"properties\"][\"status\"][\"express\"]:\n                 item[\"brand\"] = \"Nero Express\"\n \n+            item[\"branch\"] = item.pop(\"name\")\n+\n             item[\"opening_hours\"] = OpeningHours()\n             for day_name, day_hours in location[\"properties\"][\"hoursRegular\"].items():\n                 if day_hours[\"open\"] == \"closed\" or day_hours[\"close\"] == \"closed\":\n", "issue": "Caffe Nero GB spider using outdated JSON file\nThe caffe_nero_gb.py spider gets its data from JSON file that the Store Finder page at https://caffenero.com/uk/stores/ uses to display its map. However, it looks like that URL of that JSON file has changed, and ATP is still referencing the old (and no longer updated one).\r\n\r\nThe ATP code currently has\r\n`allowed_domains = [\"caffenero-webassets-production.s3.eu-west-2.amazonaws.com\"]`\r\n`start_urls = [\"https://caffenero-webassets-production.s3.eu-west-2.amazonaws.com/stores/stores_gb.json\"]`\r\nBut the URL referenced by https://caffenero.com/uk/stores/ is now\r\nhttps://caffenerowebsite.blob.core.windows.net/production/data/stores/stores-gb.json\r\n\r\nI think the format of the JSON file has remained the same, so it should just be a matter of swapping the URLs over.\r\n\r\nTo help issues like this be picked up sooner in the future, I wonder if there's a way of checking that the JSON URL used is still included in the https://caffenero.com/uk/stores/ page, and producing a warning to anyone running ATP if not?\n", "before_files": [{"content": "from scrapy import Spider\nfrom scrapy.http import JsonRequest\n\nfrom locations.categories import Categories, Extras, apply_category, apply_yes_no\nfrom locations.dict_parser import DictParser\nfrom locations.hours import OpeningHours\n\n\nclass CaffeNeroGBSpider(Spider):\n    name = \"caffe_nero_gb\"\n    item_attributes = {\"brand\": \"Caffe Nero\", \"brand_wikidata\": \"Q675808\"}\n    allowed_domains = [\"caffenero-webassets-production.s3.eu-west-2.amazonaws.com\"]\n    start_urls = [\"https://caffenero-webassets-production.s3.eu-west-2.amazonaws.com/stores/stores_gb.json\"]\n\n    def start_requests(self):\n        for url in self.start_urls:\n            yield JsonRequest(url=url)\n\n    def parse(self, response):\n        for location in response.json()[\"features\"]:\n            if (\n                not location[\"properties\"][\"status\"][\"open\"]\n                or location[\"properties\"][\"status\"][\"opening_soon\"]\n                or location[\"properties\"][\"status\"][\"temp_closed\"]\n            ):\n                continue\n\n            item = DictParser.parse(location[\"properties\"])\n            item[\"geometry\"] = location[\"geometry\"]\n            if location[\"properties\"][\"status\"][\"express\"]:\n                item[\"brand\"] = \"Nero Express\"\n\n            item[\"opening_hours\"] = OpeningHours()\n            for day_name, day_hours in location[\"properties\"][\"hoursRegular\"].items():\n                if day_hours[\"open\"] == \"closed\" or day_hours[\"close\"] == \"closed\":\n                    continue\n                if day_name == \"holiday\":\n                    continue\n                item[\"opening_hours\"].add_range(day_name.title(), day_hours[\"open\"], day_hours[\"close\"])\n\n            apply_yes_no(Extras.TAKEAWAY, item, location[\"properties\"][\"status\"][\"takeaway\"], False)\n            apply_yes_no(Extras.DELIVERY, item, location[\"properties\"][\"status\"][\"delivery\"], False)\n            apply_yes_no(Extras.WIFI, item, location[\"properties\"][\"amenities\"][\"wifi\"], False)\n            apply_yes_no(Extras.TOILETS, item, location[\"properties\"][\"amenities\"][\"toilet\"], False)\n            apply_yes_no(Extras.BABY_CHANGING_TABLE, item, location[\"properties\"][\"amenities\"][\"baby_change\"], False)\n            apply_yes_no(Extras.SMOKING_AREA, item, location[\"properties\"][\"amenities\"][\"smoking_area\"], False)\n            apply_yes_no(Extras.AIR_CONDITIONING, item, location[\"properties\"][\"amenities\"][\"air_conditioned\"], False)\n            apply_yes_no(Extras.WHEELCHAIR, item, location[\"properties\"][\"amenities\"].get(\"disabled_access\"), False)\n            apply_yes_no(Extras.TOILETS_WHEELCHAIR, item, location[\"properties\"][\"amenities\"][\"disabled_toilet\"], False)\n            apply_yes_no(Extras.OUTDOOR_SEATING, item, location[\"properties\"][\"amenities\"][\"outside_seating\"], False)\n            apply_category(Categories.COFFEE_SHOP, item)\n\n            item[\"website\"] = f'https://caffenero.com/uk/store/{location[\"properties\"][\"slug\"]}/'\n\n            yield item\n", "path": "locations/spiders/caffe_nero_gb.py"}], "after_files": [{"content": "import re\nfrom typing import Any\n\nfrom scrapy import Spider\nfrom scrapy.http import JsonRequest, Response\n\nfrom locations.categories import Categories, Extras, apply_category, apply_yes_no\nfrom locations.dict_parser import DictParser\nfrom locations.hours import OpeningHours\n\n\nclass CaffeNeroGBSpider(Spider):\n    name = \"caffe_nero_gb\"\n    item_attributes = {\"brand\": \"Caffe Nero\", \"brand_wikidata\": \"Q675808\"}\n    allowed_domains = [\"caffenero.com\", \"caffenerowebsite.blob.core.windows.net\"]\n    start_urls = [\"https://caffenero.com/uk/stores/\"]\n\n    def parse(self, response: Response, **kwargs: Any) -> Any:\n        yield JsonRequest(\n            re.search(r\"loadGeoJson\\(\\n\\s+'(https://.+)', {\", response.text).group(1), callback=self.parse_geojson\n        )\n\n    def parse_geojson(self, response: Response, **kwargs: Any) -> Any:\n        for location in response.json()[\"features\"]:\n            if (\n                not location[\"properties\"][\"status\"][\"open\"]\n                or location[\"properties\"][\"status\"][\"opening_soon\"]\n                or location[\"properties\"][\"status\"][\"temp_closed\"]\n            ):\n                continue\n\n            item = DictParser.parse(location[\"properties\"])\n            item[\"geometry\"] = location[\"geometry\"]\n            if location[\"properties\"][\"status\"][\"express\"]:\n                item[\"brand\"] = \"Nero Express\"\n\n            item[\"branch\"] = item.pop(\"name\")\n\n            item[\"opening_hours\"] = OpeningHours()\n            for day_name, day_hours in location[\"properties\"][\"hoursRegular\"].items():\n                if day_hours[\"open\"] == \"closed\" or day_hours[\"close\"] == \"closed\":\n                    continue\n                if day_name == \"holiday\":\n                    continue\n                item[\"opening_hours\"].add_range(day_name.title(), day_hours[\"open\"], day_hours[\"close\"])\n\n            apply_yes_no(Extras.TAKEAWAY, item, location[\"properties\"][\"status\"][\"takeaway\"], False)\n            apply_yes_no(Extras.DELIVERY, item, location[\"properties\"][\"status\"][\"delivery\"], False)\n            apply_yes_no(Extras.WIFI, item, location[\"properties\"][\"amenities\"][\"wifi\"], False)\n            apply_yes_no(Extras.TOILETS, item, location[\"properties\"][\"amenities\"][\"toilet\"], False)\n            apply_yes_no(Extras.BABY_CHANGING_TABLE, item, location[\"properties\"][\"amenities\"][\"baby_change\"], False)\n            apply_yes_no(Extras.SMOKING_AREA, item, location[\"properties\"][\"amenities\"][\"smoking_area\"], False)\n            apply_yes_no(Extras.AIR_CONDITIONING, item, location[\"properties\"][\"amenities\"][\"air_conditioned\"], False)\n            apply_yes_no(Extras.WHEELCHAIR, item, location[\"properties\"][\"amenities\"].get(\"disabled_access\"), False)\n            apply_yes_no(Extras.TOILETS_WHEELCHAIR, item, location[\"properties\"][\"amenities\"][\"disabled_toilet\"], False)\n            apply_yes_no(Extras.OUTDOOR_SEATING, item, location[\"properties\"][\"amenities\"][\"outside_seating\"], False)\n            apply_category(Categories.COFFEE_SHOP, item)\n\n            item[\"website\"] = f'https://caffenero.com/uk/store/{location[\"properties\"][\"slug\"]}/'\n\n            yield item\n", "path": "locations/spiders/caffe_nero_gb.py"}]}