prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Spider avis is broken
  During the global build at 2021-06-02-14-42-40, spider **avis** failed with **4383 features** and **36 errors**.
  
  Here's [the log](https://data.alltheplaces.xyz/runs/2021-06-02-14-42-40/logs/avis.txt) and [the output](https://data.alltheplaces.xyz/runs/2021-06-02-14-42-40/output/avis.geojson) ([on a map](https://data.alltheplaces.xyz/map.html?show=https://data.alltheplaces.xyz/runs/2021-06-02-14-42-40/output/avis.geojson))
  
  --- 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/avis.py`
  Content:
  ```
  1 import scrapy
  2 import re
  3 
  4 from locations.items import GeojsonPointItem
  5 from locations.hours import OpeningHours
  6 
  7 
  8 DAY_MAPPING = {
  9     'Mon': 'Mo',
  10     'Tue': 'Tu',
  11     'Wed': 'We',
  12     'Thu': 'Th',
  13     'Fri': 'Fr',
  14     'Sat': 'Sa',
  15     'Sun': 'Su'
  16 }
  17 DAYS = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
  18 
  19 
  20 class AvisSpider(scrapy.Spider):
  21 
  22     name = "avis"
  23     item_attributes = { 'brand': "Avis", 'brand_wikidata': "Q791136" }
  24     download_delay = 0.5
  25     allowed_domains = [
  26         "avis.com",
  27     ]
  28     start_urls = (
  29         'https://www.avis.com/en/locations/avisworldwide',
  30     )
  31 
  32     def parse_hours(self, hours):
  33         "Sun - Sat 7:00 AM - 10:00 PM"
  34         opening_hours = OpeningHours()
  35         hours = [h.strip() for h in hours.split(';')]
  36 
  37         for hour in hours:
  38             if hour == "Sun - Sat open 24 hrs":
  39                 return "24/7"
  40             range_match = re.search(r'([A-Za-z]{3})\s-\s([A-Za-z]{3})\s([\d:\sAMP]+)\s-\s([\d:\sAMP]+)', hour)
  41             if range_match:
  42                 start_day, end_day, start_time, end_time = range_match.groups()
  43             else:
  44                 single_match = re.search(r'([A-Za-z]{3})\s([\d:\sAMP]+)\s-\s([\d:\sAMP]+)', hour)
  45                 if not single_match:
  46                     continue
  47                 start_day, start_time, end_time = single_match.groups()
  48                 end_day = start_day
  49 
  50             for day in DAYS[DAYS.index(start_day):DAYS.index(end_day)+1]:
  51                 opening_hours.add_range(day=DAY_MAPPING[day],
  52                                         open_time=start_time.strip(),
  53                                         close_time=end_time.strip(),
  54                                         time_format='%I:%M %p')
  55         return opening_hours.as_opening_hours()
  56 
  57     def parse_store(self, response):
  58         if response.url == 'https://www.avis.com/en/error/500':
  59             # some closed locations get redirected to this error page
  60             return
  61 
  62         def clean(val):
  63             if val:
  64                 return val.strip(', ')
  65             return val
  66 
  67         ref = response.url.split('/')[-1]
  68 
  69         properties = {
  70             'name': clean(response.xpath('//h2/span[@itemprop="name"]/text()').extract_first()),
  71             'addr_full': clean(response.xpath('normalize-space(//span[@itemprop="streetAddress"]/text())').extract_first()),
  72             'phone': response.xpath('normalize-space(//span[@itemprop="telephone"]/text())').extract_first(),
  73             'city': clean(response.xpath('normalize-space(//span[@itemprop="addressLocality"]/text())').extract_first()),
  74             'state': clean(response.xpath('normalize-space(//span[@itemprop="addressRegion"]/text())').extract_first()),
  75             'postcode': clean(response.xpath('normalize-space(//span[@itemprop="postalCode"]/text())').extract_first()),
  76             'country': clean(response.xpath('normalize-space(//span[@itemprop="addressCountry"]/text())').extract_first()),
  77             'ref': ref,
  78             'website': response.url,
  79             'lat':  float(response.xpath('//meta[@itemprop="latitude"]/@content').extract_first()),
  80             'lon':  float(response.xpath('//meta[@itemprop="longitude"]/@content').extract_first()),
  81         }
  82         hours = response.xpath('//meta[@itemprop="openingHours"]/@content').extract_first()
  83         if hours:
  84             properties['opening_hours'] = self.parse_hours(hours)
  85         yield GeojsonPointItem(**properties)
  86 
  87     def parse_state(self, response):
  88         urls = response.xpath('//ul[contains(@class, "location-list-ul")]//li/a/@href').extract()
  89 
  90         if not urls:
  91             urls = set(response.xpath('//ul[contains(@class, "LocContainer")]//a/@href').extract())
  92             urls = [u for u in urls if 'javascript:void' not in u]
  93 
  94         location_list = re.compile("^/en/locations/(?:us|ca|au)/[a-z]{2}/[^/]+$")
  95         us_single_location = re.compile(r'/en/locations/(?:us|ca|au)/[a-z]{2}/[^/]+/[^/]+$')
  96         single_location = re.compile(r'/en/locations/(?!us|ca|au)[a-z]{2}/[^/]+/[^/]+$')
  97 
  98         for url in urls:
  99             if single_location.match(url) or us_single_location.match(url):
  100                 yield scrapy.Request(response.urljoin(url), callback=self.parse_store)
  101             elif location_list.match(url):
  102                 # skip these, we get them already
  103                 continue
  104             elif 'xx' in url:
  105                 continue
  106 
  107     def parse_country(self,response):
  108         urls = response.xpath('//div[contains(@class,"country-wrapper")]//li/a/@href').extract()
  109 
  110         for url in urls:
  111             yield scrapy.Request(response.urljoin(url), callback=self.parse_state)
  112 
  113     def parse(self, response):
  114         urls = response.xpath('//div[@class="wl-location-state"]//li/a/@href').extract()
  115 
  116         for url in urls:
  117             yield scrapy.Request(response.urljoin(url), callback=self.parse_country)
  118
  ```
  --- 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/avis.py b/locations/spiders/avis.py
  --- a/locations/spiders/avis.py
  +++ b/locations/spiders/avis.py
  @@ -66,6 +66,15 @@
   
           ref = response.url.split('/')[-1]
   
  +        latitude = None
  +        longitude = None
  +
  +        if response.xpath('//meta[@itemprop="latitude"]/@content').extract_first() is not None:
  +            latitude = float(response.xpath('//meta[@itemprop="latitude"]/@content').extract_first())
  +
  +        if response.xpath('//meta[@itemprop="longitude"]/@content').extract_first() is not None:
  +            longitude = float(response.xpath('//meta[@itemprop="longitude"]/@content').extract_first())
  +
           properties = {
               'name': clean(response.xpath('//h2/span[@itemprop="name"]/text()').extract_first()),
               'addr_full': clean(response.xpath('normalize-space(//span[@itemprop="streetAddress"]/text())').extract_first()),
  @@ -76,8 +85,8 @@
               'country': clean(response.xpath('normalize-space(//span[@itemprop="addressCountry"]/text())').extract_first()),
               'ref': ref,
               'website': response.url,
  -            'lat':  float(response.xpath('//meta[@itemprop="latitude"]/@content').extract_first()),
  -            'lon':  float(response.xpath('//meta[@itemprop="longitude"]/@content').extract_first()),
  +            'lat':  latitude,
  +            'lon':  longitude,
           }
           hours = response.xpath('//meta[@itemprop="openingHours"]/@content').extract_first()
           if hours:
  
verification_info: {"golden_diff": "diff --git a/locations/spiders/avis.py b/locations/spiders/avis.py\n--- a/locations/spiders/avis.py\n+++ b/locations/spiders/avis.py\n@@ -66,6 +66,15 @@\n \n         ref = response.url.split('/')[-1]\n \n+        latitude = None\n+        longitude = None\n+\n+        if response.xpath('//meta[@itemprop=\"latitude\"]/@content').extract_first() is not None:\n+            latitude = float(response.xpath('//meta[@itemprop=\"latitude\"]/@content').extract_first())\n+\n+        if response.xpath('//meta[@itemprop=\"longitude\"]/@content').extract_first() is not None:\n+            longitude = float(response.xpath('//meta[@itemprop=\"longitude\"]/@content').extract_first())\n+\n         properties = {\n             'name': clean(response.xpath('//h2/span[@itemprop=\"name\"]/text()').extract_first()),\n             'addr_full': clean(response.xpath('normalize-space(//span[@itemprop=\"streetAddress\"]/text())').extract_first()),\n@@ -76,8 +85,8 @@\n             'country': clean(response.xpath('normalize-space(//span[@itemprop=\"addressCountry\"]/text())').extract_first()),\n             'ref': ref,\n             'website': response.url,\n-            'lat':  float(response.xpath('//meta[@itemprop=\"latitude\"]/@content').extract_first()),\n-            'lon':  float(response.xpath('//meta[@itemprop=\"longitude\"]/@content').extract_first()),\n+            'lat':  latitude,\n+            'lon':  longitude,\n         }\n         hours = response.xpath('//meta[@itemprop=\"openingHours\"]/@content').extract_first()\n         if hours:\n", "issue": "Spider avis is broken\nDuring the global build at 2021-06-02-14-42-40, spider **avis** failed with **4383 features** and **36 errors**.\n\nHere's [the log](https://data.alltheplaces.xyz/runs/2021-06-02-14-42-40/logs/avis.txt) and [the output](https://data.alltheplaces.xyz/runs/2021-06-02-14-42-40/output/avis.geojson) ([on a map](https://data.alltheplaces.xyz/map.html?show=https://data.alltheplaces.xyz/runs/2021-06-02-14-42-40/output/avis.geojson))\n", "before_files": [{"content": "import scrapy\nimport re\n\nfrom locations.items import GeojsonPointItem\nfrom locations.hours import OpeningHours\n\n\nDAY_MAPPING = {\n    'Mon': 'Mo',\n    'Tue': 'Tu',\n    'Wed': 'We',\n    'Thu': 'Th',\n    'Fri': 'Fr',\n    'Sat': 'Sa',\n    'Sun': 'Su'\n}\nDAYS = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']\n\n\nclass AvisSpider(scrapy.Spider):\n\n    name = \"avis\"\n    item_attributes = { 'brand': \"Avis\", 'brand_wikidata': \"Q791136\" }\n    download_delay = 0.5\n    allowed_domains = [\n        \"avis.com\",\n    ]\n    start_urls = (\n        'https://www.avis.com/en/locations/avisworldwide',\n    )\n\n    def parse_hours(self, hours):\n        \"Sun - Sat 7:00 AM - 10:00 PM\"\n        opening_hours = OpeningHours()\n        hours = [h.strip() for h in hours.split(';')]\n\n        for hour in hours:\n            if hour == \"Sun - Sat open 24 hrs\":\n                return \"24/7\"\n            range_match = re.search(r'([A-Za-z]{3})\\s-\\s([A-Za-z]{3})\\s([\\d:\\sAMP]+)\\s-\\s([\\d:\\sAMP]+)', hour)\n            if range_match:\n                start_day, end_day, start_time, end_time = range_match.groups()\n            else:\n                single_match = re.search(r'([A-Za-z]{3})\\s([\\d:\\sAMP]+)\\s-\\s([\\d:\\sAMP]+)', hour)\n                if not single_match:\n                    continue\n                start_day, start_time, end_time = single_match.groups()\n                end_day = start_day\n\n            for day in DAYS[DAYS.index(start_day):DAYS.index(end_day)+1]:\n                opening_hours.add_range(day=DAY_MAPPING[day],\n                                        open_time=start_time.strip(),\n                                        close_time=end_time.strip(),\n                                        time_format='%I:%M %p')\n        return opening_hours.as_opening_hours()\n\n    def parse_store(self, response):\n        if response.url == 'https://www.avis.com/en/error/500':\n            # some closed locations get redirected to this error page\n            return\n\n        def clean(val):\n            if val:\n                return val.strip(', ')\n            return val\n\n        ref = response.url.split('/')[-1]\n\n        properties = {\n            'name': clean(response.xpath('//h2/span[@itemprop=\"name\"]/text()').extract_first()),\n            'addr_full': clean(response.xpath('normalize-space(//span[@itemprop=\"streetAddress\"]/text())').extract_first()),\n            'phone': response.xpath('normalize-space(//span[@itemprop=\"telephone\"]/text())').extract_first(),\n            'city': clean(response.xpath('normalize-space(//span[@itemprop=\"addressLocality\"]/text())').extract_first()),\n            'state': clean(response.xpath('normalize-space(//span[@itemprop=\"addressRegion\"]/text())').extract_first()),\n            'postcode': clean(response.xpath('normalize-space(//span[@itemprop=\"postalCode\"]/text())').extract_first()),\n            'country': clean(response.xpath('normalize-space(//span[@itemprop=\"addressCountry\"]/text())').extract_first()),\n            'ref': ref,\n            'website': response.url,\n            'lat':  float(response.xpath('//meta[@itemprop=\"latitude\"]/@content').extract_first()),\n            'lon':  float(response.xpath('//meta[@itemprop=\"longitude\"]/@content').extract_first()),\n        }\n        hours = response.xpath('//meta[@itemprop=\"openingHours\"]/@content').extract_first()\n        if hours:\n            properties['opening_hours'] = self.parse_hours(hours)\n        yield GeojsonPointItem(**properties)\n\n    def parse_state(self, response):\n        urls = response.xpath('//ul[contains(@class, \"location-list-ul\")]//li/a/@href').extract()\n\n        if not urls:\n            urls = set(response.xpath('//ul[contains(@class, \"LocContainer\")]//a/@href').extract())\n            urls = [u for u in urls if 'javascript:void' not in u]\n\n        location_list = re.compile(\"^/en/locations/(?:us|ca|au)/[a-z]{2}/[^/]+$\")\n        us_single_location = re.compile(r'/en/locations/(?:us|ca|au)/[a-z]{2}/[^/]+/[^/]+$')\n        single_location = re.compile(r'/en/locations/(?!us|ca|au)[a-z]{2}/[^/]+/[^/]+$')\n\n        for url in urls:\n            if single_location.match(url) or us_single_location.match(url):\n                yield scrapy.Request(response.urljoin(url), callback=self.parse_store)\n            elif location_list.match(url):\n                # skip these, we get them already\n                continue\n            elif 'xx' in url:\n                continue\n\n    def parse_country(self,response):\n        urls = response.xpath('//div[contains(@class,\"country-wrapper\")]//li/a/@href').extract()\n\n        for url in urls:\n            yield scrapy.Request(response.urljoin(url), callback=self.parse_state)\n\n    def parse(self, response):\n        urls = response.xpath('//div[@class=\"wl-location-state\"]//li/a/@href').extract()\n\n        for url in urls:\n            yield scrapy.Request(response.urljoin(url), callback=self.parse_country)\n", "path": "locations/spiders/avis.py"}], "after_files": [{"content": "import scrapy\nimport re\n\nfrom locations.items import GeojsonPointItem\nfrom locations.hours import OpeningHours\n\n\nDAY_MAPPING = {\n    'Mon': 'Mo',\n    'Tue': 'Tu',\n    'Wed': 'We',\n    'Thu': 'Th',\n    'Fri': 'Fr',\n    'Sat': 'Sa',\n    'Sun': 'Su'\n}\nDAYS = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']\n\n\nclass AvisSpider(scrapy.Spider):\n\n    name = \"avis\"\n    item_attributes = { 'brand': \"Avis\", 'brand_wikidata': \"Q791136\" }\n    download_delay = 0.5\n    allowed_domains = [\n        \"avis.com\",\n    ]\n    start_urls = (\n        'https://www.avis.com/en/locations/avisworldwide',\n    )\n\n    def parse_hours(self, hours):\n        \"Sun - Sat 7:00 AM - 10:00 PM\"\n        opening_hours = OpeningHours()\n        hours = [h.strip() for h in hours.split(';')]\n\n        for hour in hours:\n            if hour == \"Sun - Sat open 24 hrs\":\n                return \"24/7\"\n            range_match = re.search(r'([A-Za-z]{3})\\s-\\s([A-Za-z]{3})\\s([\\d:\\sAMP]+)\\s-\\s([\\d:\\sAMP]+)', hour)\n            if range_match:\n                start_day, end_day, start_time, end_time = range_match.groups()\n            else:\n                single_match = re.search(r'([A-Za-z]{3})\\s([\\d:\\sAMP]+)\\s-\\s([\\d:\\sAMP]+)', hour)\n                if not single_match:\n                    continue\n                start_day, start_time, end_time = single_match.groups()\n                end_day = start_day\n\n            for day in DAYS[DAYS.index(start_day):DAYS.index(end_day)+1]:\n                opening_hours.add_range(day=DAY_MAPPING[day],\n                                        open_time=start_time.strip(),\n                                        close_time=end_time.strip(),\n                                        time_format='%I:%M %p')\n        return opening_hours.as_opening_hours()\n\n    def parse_store(self, response):\n        if response.url == 'https://www.avis.com/en/error/500':\n            # some closed locations get redirected to this error page\n            return\n\n        def clean(val):\n            if val:\n                return val.strip(', ')\n            return val\n\n        ref = response.url.split('/')[-1]\n\n        latitude = None\n        longitude = None\n\n        if response.xpath('//meta[@itemprop=\"latitude\"]/@content').extract_first() is not None:\n            latitude = float(response.xpath('//meta[@itemprop=\"latitude\"]/@content').extract_first())\n\n        if response.xpath('//meta[@itemprop=\"longitude\"]/@content').extract_first() is not None:\n            longitude = float(response.xpath('//meta[@itemprop=\"longitude\"]/@content').extract_first())\n\n        properties = {\n            'name': clean(response.xpath('//h2/span[@itemprop=\"name\"]/text()').extract_first()),\n            'addr_full': clean(response.xpath('normalize-space(//span[@itemprop=\"streetAddress\"]/text())').extract_first()),\n            'phone': response.xpath('normalize-space(//span[@itemprop=\"telephone\"]/text())').extract_first(),\n            'city': clean(response.xpath('normalize-space(//span[@itemprop=\"addressLocality\"]/text())').extract_first()),\n            'state': clean(response.xpath('normalize-space(//span[@itemprop=\"addressRegion\"]/text())').extract_first()),\n            'postcode': clean(response.xpath('normalize-space(//span[@itemprop=\"postalCode\"]/text())').extract_first()),\n            'country': clean(response.xpath('normalize-space(//span[@itemprop=\"addressCountry\"]/text())').extract_first()),\n            'ref': ref,\n            'website': response.url,\n            'lat':  latitude,\n            'lon':  longitude,\n        }\n        hours = response.xpath('//meta[@itemprop=\"openingHours\"]/@content').extract_first()\n        if hours:\n            properties['opening_hours'] = self.parse_hours(hours)\n        yield GeojsonPointItem(**properties)\n\n    def parse_state(self, response):\n        urls = response.xpath('//ul[contains(@class, \"location-list-ul\")]//li/a/@href').extract()\n\n        if not urls:\n            urls = set(response.xpath('//ul[contains(@class, \"LocContainer\")]//a/@href').extract())\n            urls = [u for u in urls if 'javascript:void' not in u]\n\n        location_list = re.compile(\"^/en/locations/(?:us|ca|au)/[a-z]{2}/[^/]+$\")\n        us_single_location = re.compile(r'/en/locations/(?:us|ca|au)/[a-z]{2}/[^/]+/[^/]+$')\n        single_location = re.compile(r'/en/locations/(?!us|ca|au)[a-z]{2}/[^/]+/[^/]+$')\n\n        for url in urls:\n            if single_location.match(url) or us_single_location.match(url):\n                yield scrapy.Request(response.urljoin(url), callback=self.parse_store)\n            elif location_list.match(url):\n                # skip these, we get them already\n                continue\n            elif 'xx' in url:\n                continue\n\n    def parse_country(self,response):\n        urls = response.xpath('//div[contains(@class,\"country-wrapper\")]//li/a/@href').extract()\n\n        for url in urls:\n            yield scrapy.Request(response.urljoin(url), callback=self.parse_state)\n\n    def parse(self, response):\n        urls = response.xpath('//div[@class=\"wl-location-state\"]//li/a/@href').extract()\n\n        for url in urls:\n            yield scrapy.Request(response.urljoin(url), callback=self.parse_country)\n", "path": "locations/spiders/avis.py"}]}