We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Spider woods_coffee is broken
During the global build at 2021-10-20-14-42-48, spider **woods_coffee** failed with **0 features** and **1 errors**.

Here's [the log](https://data.alltheplaces.xyz/runs/2021-10-20-14-42-48/logs/woods_coffee.txt) and [the output](https://data.alltheplaces.xyz/runs/2021-10-20-14-42-48/output/woods_coffee.geojson) ([on a map](https://data.alltheplaces.xyz/map.html?show=https://data.alltheplaces.xyz/runs/2021-10-20-14-42-48/output/woods_coffee.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/woods_coffee.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 import scrapy
3 from locations.items import GeojsonPointItem
4 import re
5 
6 daysKey = {
7                 'MONDAY': 'Mo', 'TUESDAY': 'Tu', 'WEDNESDAY': 'We', 'THURSDAY': 'Th',
8                 'FRIDAY': 'Fr', 'SATURDAY': 'Sa', 'SUNDAY': 'Su'
9 }
10 
11 class WoodsCoffeeSpider(scrapy.Spider):
12         name = "woods_coffee"
13         item_attributes = { 'brand': "Woods Coffee" }
14         allowed_domains = ["www.woodscoffee.com"]
15         start_urls = (
16                 'https://woodscoffee.com/locations/',
17         )
18 
19         def store_hours(self, hours):
20             hours = hours.replace('–','-')
21             hours = hours.replace(u'\xa0', u' ')
22             days = hours.split(': ')[0].strip()
23 
24             if('-' in days):
25                 startDay = daysKey[days.split('-')[0]]
26                 endDay = daysKey[days.split('-')[1]]
27                 dayOutput = startDay + "-" + endDay
28             else:
29                 if('DAILY' in days):
30                     startDay='Mo'
31                     endDay='Su'
32                     dayOutput = startDay + "-" + endDay
33                 else:
34                     dayOutput = daysKey[days]
35 
36             bothHours = hours.split(': ')[1].replace(' ','')
37             openHours = bothHours.split("-")[0]
38             closeHours = bothHours.split("-")[1]
39 
40             if("AM" in openHours):
41                 openHours = openHours.replace("AM","")
42                 if(":" in openHours):
43                     openH = openHours.split(":")[0]
44                     openM = openHours.split(":")[1]
45                 else:
46                     openH = openHours
47                     openM = "00"
48                 openHours = openH + ":" + openM
49 
50             if("PM" in openHours):
51                 openHours = openHours.replace("PM","")
52                 if(":" in openHours):
53                     openH = openHours.split(":")[0]
54                     openM = openHours.split(":")[1]
55                 else:
56                     openH = openHours
57                     openM = "00"
58                 openH = str(int(openH) + 12)
59                 openHours = openH + ":" + openM
60 
61             if("AM" in closeHours):
62                 closeHours = closeHours.replace("AM","")
63                 if(":" in closeHours):
64                     closeH = closeHours.split(":")[0]
65                     closeM = closeHours.split(":")[1]
66                 else:
67                     closeH = closeHours
68                     closeM = "00"
69                 closeHours = closeH + ":" + closeM
70 
71             if("PM" in closeHours):
72                 closeHours = closeHours.replace("PM","")
73                 if(":" in closeHours):
74                     closeH = closeHours.split(":")[0]
75                     closeM = closeHours.split(":")[1]
76                 else:
77                     closeH = closeHours
78                     closeM = "00"
79                 closeH = str(int(closeH) + 12)
80                 closeHours = closeH + ":" + closeM
81 
82                 return dayOutput +' '+ openHours.replace(' ','') + "-" + closeHours + ';'
83 
84         def parse(self, response):
85             for match in response.xpath("//h2[contains(@class,'font-weight-700 text-uppercase')]/parent::div/parent::div"):
86                 cityState = match.xpath(".//div[contains(@class,'heading-text el-text')]/div/p/text()").extract_first();
87                 cityString = cityState.split(",")[0].strip()
88                 stateString = cityState.split(",")[1].strip()
89 
90                 addressString = match.xpath(".//div[contains(@class,'uncode_text_column')]/p[contains(@style,'text-align: center;')][not(.//strong)]/text()").extract_first().strip()
91                 postcodeString = addressString.split(stateString)[1].strip()
92                 addressString = addressString.split(stateString)[0].replace(',','').strip().strip(cityString).strip()
93 
94 
95                 if(match.xpath(".//div[contains(@class,'uncode_text_column')]/p[contains(@style,'text-align: center;')][not (.//strong)]/br/following-sibling::text()").extract_first() is None):
96                     phoneString = ""
97                 else:
98                     phoneString = match.xpath(".//div[contains(@class,'uncode_text_column')]/p[contains(@style,'text-align: center;')][not (.//strong)]/br/following-sibling::text()").extract_first()
99                 phoneString = phoneString.replace(' ','').strip()
100 
101                 hoursString = ""
102                 for hoursMatch in match.xpath(".//p[contains(@style,'text-align: center;')]/strong//following-sibling::text()"):
103                     hoursString = hoursString +' '+self.store_hours(hoursMatch.extract().replace('\n',''))
104                 hoursString = hoursString.strip(';').strip()
105 
106                 yield GeojsonPointItem(
107                     ref=match.xpath(".//h2[contains(@class,'font-weight-700 text-uppercase')]/span/text()").extract_first(),
108                     addr_full=addressString,
109                     city=cityString,
110                     state=stateString,
111                     postcode=postcodeString,
112                     phone=phoneString,
113                     opening_hours=hoursString,
114                     website=match.xpath(".//a/@href").extract_first(),
115                 )
116
```
--- 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()

```

diff --git a/locations/spiders/woods_coffee.py b/locations/spiders/woods_coffee.py
--- a/locations/spiders/woods_coffee.py
+++ b/locations/spiders/woods_coffee.py
@@ -1,16 +1,17 @@
 # -*- coding: utf-8 -*-
 import scrapy
+
 from locations.items import GeojsonPointItem
-import re
 
 daysKey = {
                 'MONDAY': 'Mo', 'TUESDAY': 'Tu', 'WEDNESDAY': 'We', 'THURSDAY': 'Th',
                 'FRIDAY': 'Fr', 'SATURDAY': 'Sa', 'SUNDAY': 'Su'
 }
 
+
 class WoodsCoffeeSpider(scrapy.Spider):
         name = "woods_coffee"
-        item_attributes = { 'brand': "Woods Coffee" }
+        item_attributes = {'brand': "Woods Coffee", "brand_wikidata": "Q8033255"}
         allowed_domains = ["www.woodscoffee.com"]
         start_urls = (
                 'https://woodscoffee.com/locations/',
@@ -82,8 +83,8 @@
                 return dayOutput +' '+ openHours.replace(' ','') + "-" + closeHours + ';'
 
         def parse(self, response):
-            for match in response.xpath("//h2[contains(@class,'font-weight-700 text-uppercase')]/parent::div/parent::div"):
-                cityState = match.xpath(".//div[contains(@class,'heading-text el-text')]/div/p/text()").extract_first();
+            for match in response.xpath("//h2[contains(@class,'font-weight-700 text-uppercase')]/parent::div/parent::div/parent::div"):
+                cityState = match.xpath(".//div[contains(@class,'heading-text el-text')]/div/p/text()").extract_first()
                 cityString = cityState.split(",")[0].strip()
                 stateString = cityState.split(",")[1].strip()
 
@@ -103,13 +104,17 @@
                     hoursString = hoursString +' '+self.store_hours(hoursMatch.extract().replace('\n',''))
                 hoursString = hoursString.strip(';').strip()
 
+                name = match.xpath(".//h2[contains(@class,'font-weight-700 text-uppercase')]/span/text()").extract_first()
+
                 yield GeojsonPointItem(
-                    ref=match.xpath(".//h2[contains(@class,'font-weight-700 text-uppercase')]/span/text()").extract_first(),
+                    ref=name,
+                    name=name,
                     addr_full=addressString,
                     city=cityString,
                     state=stateString,
                     postcode=postcodeString,
+                    country="USA",
                     phone=phoneString,
                     opening_hours=hoursString,
-                    website=match.xpath(".//a/@href").extract_first(),
+                    website=response.urljoin(match.xpath(".//a/@href").extract_first()),
                 )

{"golden_diff": "diff --git a/locations/spiders/woods_coffee.py b/locations/spiders/woods_coffee.py\n--- a/locations/spiders/woods_coffee.py\n+++ b/locations/spiders/woods_coffee.py\n@@ -1,16 +1,17 @@\n # -*- coding: utf-8 -*-\n import scrapy\n+\n from locations.items import GeojsonPointItem\n-import re\n \n daysKey = {\n                 'MONDAY': 'Mo', 'TUESDAY': 'Tu', 'WEDNESDAY': 'We', 'THURSDAY': 'Th',\n                 'FRIDAY': 'Fr', 'SATURDAY': 'Sa', 'SUNDAY': 'Su'\n }\n \n+\n class WoodsCoffeeSpider(scrapy.Spider):\n         name = \"woods_coffee\"\n-        item_attributes = { 'brand': \"Woods Coffee\" }\n+        item_attributes = {'brand': \"Woods Coffee\", \"brand_wikidata\": \"Q8033255\"}\n         allowed_domains = [\"www.woodscoffee.com\"]\n         start_urls = (\n                 'https://woodscoffee.com/locations/',\n@@ -82,8 +83,8 @@\n                 return dayOutput +' '+ openHours.replace(' ','') + \"-\" + closeHours + ';'\n \n         def parse(self, response):\n-            for match in response.xpath(\"//h2[contains(@class,'font-weight-700 text-uppercase')]/parent::div/parent::div\"):\n-                cityState = match.xpath(\".//div[contains(@class,'heading-text el-text')]/div/p/text()\").extract_first();\n+            for match in response.xpath(\"//h2[contains(@class,'font-weight-700 text-uppercase')]/parent::div/parent::div/parent::div\"):\n+                cityState = match.xpath(\".//div[contains(@class,'heading-text el-text')]/div/p/text()\").extract_first()\n                 cityString = cityState.split(\",\")[0].strip()\n                 stateString = cityState.split(\",\")[1].strip()\n \n@@ -103,13 +104,17 @@\n                     hoursString = hoursString +' '+self.store_hours(hoursMatch.extract().replace('\\n',''))\n                 hoursString = hoursString.strip(';').strip()\n \n+                name = match.xpath(\".//h2[contains(@class,'font-weight-700 text-uppercase')]/span/text()\").extract_first()\n+\n                 yield GeojsonPointItem(\n-                    ref=match.xpath(\".//h2[contains(@class,'font-weight-700 text-uppercase')]/span/text()\").extract_first(),\n+                    ref=name,\n+                    name=name,\n                     addr_full=addressString,\n                     city=cityString,\n                     state=stateString,\n                     postcode=postcodeString,\n+                    country=\"USA\",\n                     phone=phoneString,\n                     opening_hours=hoursString,\n-                    website=match.xpath(\".//a/@href\").extract_first(),\n+                    website=response.urljoin(match.xpath(\".//a/@href\").extract_first()),\n                 )\n", "issue": "Spider woods_coffee is broken\nDuring the global build at 2021-10-20-14-42-48, spider **woods_coffee** failed with **0 features** and **1 errors**.\n\nHere's [the log](https://data.alltheplaces.xyz/runs/2021-10-20-14-42-48/logs/woods_coffee.txt) and [the output](https://data.alltheplaces.xyz/runs/2021-10-20-14-42-48/output/woods_coffee.geojson) ([on a map](https://data.alltheplaces.xyz/map.html?show=https://data.alltheplaces.xyz/runs/2021-10-20-14-42-48/output/woods_coffee.geojson))\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\nimport scrapy\nfrom locations.items import GeojsonPointItem\nimport re\n\ndaysKey = {\n                'MONDAY': 'Mo', 'TUESDAY': 'Tu', 'WEDNESDAY': 'We', 'THURSDAY': 'Th',\n                'FRIDAY': 'Fr', 'SATURDAY': 'Sa', 'SUNDAY': 'Su'\n}\n\nclass WoodsCoffeeSpider(scrapy.Spider):\n        name = \"woods_coffee\"\n        item_attributes = { 'brand': \"Woods Coffee\" }\n        allowed_domains = [\"www.woodscoffee.com\"]\n        start_urls = (\n                'https://woodscoffee.com/locations/',\n        )\n\n        def store_hours(self, hours):\n            hours = hours.replace('\u2013','-')\n            hours = hours.replace(u'\\xa0', u' ')\n            days = hours.split(': ')[0].strip()\n\n            if('-' in days):\n                startDay = daysKey[days.split('-')[0]]\n                endDay = daysKey[days.split('-')[1]]\n                dayOutput = startDay + \"-\" + endDay\n            else:\n                if('DAILY' in days):\n                    startDay='Mo'\n                    endDay='Su'\n                    dayOutput = startDay + \"-\" + endDay\n                else:\n                    dayOutput = daysKey[days]\n\n            bothHours = hours.split(': ')[1].replace(' ','')\n            openHours = bothHours.split(\"-\")[0]\n            closeHours = bothHours.split(\"-\")[1]\n\n            if(\"AM\" in openHours):\n                openHours = openHours.replace(\"AM\",\"\")\n                if(\":\" in openHours):\n                    openH = openHours.split(\":\")[0]\n                    openM = openHours.split(\":\")[1]\n                else:\n                    openH = openHours\n                    openM = \"00\"\n                openHours = openH + \":\" + openM\n\n            if(\"PM\" in openHours):\n                openHours = openHours.replace(\"PM\",\"\")\n                if(\":\" in openHours):\n                    openH = openHours.split(\":\")[0]\n                    openM = openHours.split(\":\")[1]\n                else:\n                    openH = openHours\n                    openM = \"00\"\n                openH = str(int(openH) + 12)\n                openHours = openH + \":\" + openM\n\n            if(\"AM\" in closeHours):\n                closeHours = closeHours.replace(\"AM\",\"\")\n                if(\":\" in closeHours):\n                    closeH = closeHours.split(\":\")[0]\n                    closeM = closeHours.split(\":\")[1]\n                else:\n                    closeH = closeHours\n                    closeM = \"00\"\n                closeHours = closeH + \":\" + closeM\n\n            if(\"PM\" in closeHours):\n                closeHours = closeHours.replace(\"PM\",\"\")\n                if(\":\" in closeHours):\n                    closeH = closeHours.split(\":\")[0]\n                    closeM = closeHours.split(\":\")[1]\n                else:\n                    closeH = closeHours\n                    closeM = \"00\"\n                closeH = str(int(closeH) + 12)\n                closeHours = closeH + \":\" + closeM\n\n                return dayOutput +' '+ openHours.replace(' ','') + \"-\" + closeHours + ';'\n\n        def parse(self, response):\n            for match in response.xpath(\"//h2[contains(@class,'font-weight-700 text-uppercase')]/parent::div/parent::div\"):\n                cityState = match.xpath(\".//div[contains(@class,'heading-text el-text')]/div/p/text()\").extract_first();\n                cityString = cityState.split(\",\")[0].strip()\n                stateString = cityState.split(\",\")[1].strip()\n\n                addressString = match.xpath(\".//div[contains(@class,'uncode_text_column')]/p[contains(@style,'text-align: center;')][not(.//strong)]/text()\").extract_first().strip()\n                postcodeString = addressString.split(stateString)[1].strip()\n                addressString = addressString.split(stateString)[0].replace(',','').strip().strip(cityString).strip()\n\n\n                if(match.xpath(\".//div[contains(@class,'uncode_text_column')]/p[contains(@style,'text-align: center;')][not (.//strong)]/br/following-sibling::text()\").extract_first() is None):\n                    phoneString = \"\"\n                else:\n                    phoneString = match.xpath(\".//div[contains(@class,'uncode_text_column')]/p[contains(@style,'text-align: center;')][not (.//strong)]/br/following-sibling::text()\").extract_first()\n                phoneString = phoneString.replace(' ','').strip()\n\n                hoursString = \"\"\n                for hoursMatch in match.xpath(\".//p[contains(@style,'text-align: center;')]/strong//following-sibling::text()\"):\n                    hoursString = hoursString +' '+self.store_hours(hoursMatch.extract().replace('\\n',''))\n                hoursString = hoursString.strip(';').strip()\n\n                yield GeojsonPointItem(\n                    ref=match.xpath(\".//h2[contains(@class,'font-weight-700 text-uppercase')]/span/text()\").extract_first(),\n                    addr_full=addressString,\n                    city=cityString,\n                    state=stateString,\n                    postcode=postcodeString,\n                    phone=phoneString,\n                    opening_hours=hoursString,\n                    website=match.xpath(\".//a/@href\").extract_first(),\n                )\n", "path": "locations/spiders/woods_coffee.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\nimport scrapy\n\nfrom locations.items import GeojsonPointItem\n\ndaysKey = {\n                'MONDAY': 'Mo', 'TUESDAY': 'Tu', 'WEDNESDAY': 'We', 'THURSDAY': 'Th',\n                'FRIDAY': 'Fr', 'SATURDAY': 'Sa', 'SUNDAY': 'Su'\n}\n\n\nclass WoodsCoffeeSpider(scrapy.Spider):\n        name = \"woods_coffee\"\n        item_attributes = {'brand': \"Woods Coffee\", \"brand_wikidata\": \"Q8033255\"}\n        allowed_domains = [\"www.woodscoffee.com\"]\n        start_urls = (\n                'https://woodscoffee.com/locations/',\n        )\n\n        def store_hours(self, hours):\n            hours = hours.replace('\u2013','-')\n            hours = hours.replace(u'\\xa0', u' ')\n            days = hours.split(': ')[0].strip()\n\n            if('-' in days):\n                startDay = daysKey[days.split('-')[0]]\n                endDay = daysKey[days.split('-')[1]]\n                dayOutput = startDay + \"-\" + endDay\n            else:\n                if('DAILY' in days):\n                    startDay='Mo'\n                    endDay='Su'\n                    dayOutput = startDay + \"-\" + endDay\n                else:\n                    dayOutput = daysKey[days]\n\n            bothHours = hours.split(': ')[1].replace(' ','')\n            openHours = bothHours.split(\"-\")[0]\n            closeHours = bothHours.split(\"-\")[1]\n\n            if(\"AM\" in openHours):\n                openHours = openHours.replace(\"AM\",\"\")\n                if(\":\" in openHours):\n                    openH = openHours.split(\":\")[0]\n                    openM = openHours.split(\":\")[1]\n                else:\n                    openH = openHours\n                    openM = \"00\"\n                openHours = openH + \":\" + openM\n\n            if(\"PM\" in openHours):\n                openHours = openHours.replace(\"PM\",\"\")\n                if(\":\" in openHours):\n                    openH = openHours.split(\":\")[0]\n                    openM = openHours.split(\":\")[1]\n                else:\n                    openH = openHours\n                    openM = \"00\"\n                openH = str(int(openH) + 12)\n                openHours = openH + \":\" + openM\n\n            if(\"AM\" in closeHours):\n                closeHours = closeHours.replace(\"AM\",\"\")\n                if(\":\" in closeHours):\n                    closeH = closeHours.split(\":\")[0]\n                    closeM = closeHours.split(\":\")[1]\n                else:\n                    closeH = closeHours\n                    closeM = \"00\"\n                closeHours = closeH + \":\" + closeM\n\n            if(\"PM\" in closeHours):\n                closeHours = closeHours.replace(\"PM\",\"\")\n                if(\":\" in closeHours):\n                    closeH = closeHours.split(\":\")[0]\n                    closeM = closeHours.split(\":\")[1]\n                else:\n                    closeH = closeHours\n                    closeM = \"00\"\n                closeH = str(int(closeH) + 12)\n                closeHours = closeH + \":\" + closeM\n\n                return dayOutput +' '+ openHours.replace(' ','') + \"-\" + closeHours + ';'\n\n        def parse(self, response):\n            for match in response.xpath(\"//h2[contains(@class,'font-weight-700 text-uppercase')]/parent::div/parent::div/parent::div\"):\n                cityState = match.xpath(\".//div[contains(@class,'heading-text el-text')]/div/p/text()\").extract_first()\n                cityString = cityState.split(\",\")[0].strip()\n                stateString = cityState.split(\",\")[1].strip()\n\n                addressString = match.xpath(\".//div[contains(@class,'uncode_text_column')]/p[contains(@style,'text-align: center;')][not(.//strong)]/text()\").extract_first().strip()\n                postcodeString = addressString.split(stateString)[1].strip()\n                addressString = addressString.split(stateString)[0].replace(',','').strip().strip(cityString).strip()\n\n\n                if(match.xpath(\".//div[contains(@class,'uncode_text_column')]/p[contains(@style,'text-align: center;')][not (.//strong)]/br/following-sibling::text()\").extract_first() is None):\n                    phoneString = \"\"\n                else:\n                    phoneString = match.xpath(\".//div[contains(@class,'uncode_text_column')]/p[contains(@style,'text-align: center;')][not (.//strong)]/br/following-sibling::text()\").extract_first()\n                phoneString = phoneString.replace(' ','').strip()\n\n                hoursString = \"\"\n                for hoursMatch in match.xpath(\".//p[contains(@style,'text-align: center;')]/strong//following-sibling::text()\"):\n                    hoursString = hoursString +' '+self.store_hours(hoursMatch.extract().replace('\\n',''))\n                hoursString = hoursString.strip(';').strip()\n\n                name = match.xpath(\".//h2[contains(@class,'font-weight-700 text-uppercase')]/span/text()\").extract_first()\n\n                yield GeojsonPointItem(\n                    ref=name,\n                    name=name,\n                    addr_full=addressString,\n                    city=cityString,\n                    state=stateString,\n                    postcode=postcodeString,\n                    country=\"USA\",\n                    phone=phoneString,\n                    opening_hours=hoursString,\n                    website=response.urljoin(match.xpath(\".//a/@href\").extract_first()),\n                )\n", "path": "locations/spiders/woods_coffee.py"}]}