uk_bin_collection 0.129.0__py3-none-any.whl → 0.130.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- uk_bin_collection/tests/input.json +6 -0
- uk_bin_collection/uk_bin_collection/councils/AshfieldDistrictCouncil.py +81 -71
- uk_bin_collection/uk_bin_collection/councils/HerefordshireCouncil.py +53 -0
- uk_bin_collection/uk_bin_collection/councils/PowysCouncil.py +108 -99
- uk_bin_collection/uk_bin_collection/councils/TeignbridgeCouncil.py +47 -38
- {uk_bin_collection-0.129.0.dist-info → uk_bin_collection-0.130.1.dist-info}/METADATA +1 -1
- {uk_bin_collection-0.129.0.dist-info → uk_bin_collection-0.130.1.dist-info}/RECORD +10 -9
- {uk_bin_collection-0.129.0.dist-info → uk_bin_collection-0.130.1.dist-info}/LICENSE +0 -0
- {uk_bin_collection-0.129.0.dist-info → uk_bin_collection-0.130.1.dist-info}/WHEEL +0 -0
- {uk_bin_collection-0.129.0.dist-info → uk_bin_collection-0.130.1.dist-info}/entry_points.txt +0 -0
@@ -882,6 +882,12 @@
|
|
882
882
|
"wiki_name": "Hartlepool Borough Council",
|
883
883
|
"wiki_note": "You will need to use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find your UPRN."
|
884
884
|
},
|
885
|
+
"HerefordshireCouncil": {
|
886
|
+
"url": "https://www.herefordshire.gov.uk/rubbish-recycling/check-bin-collection-day?blpu_uprn=10096232662",
|
887
|
+
"wiki_command_url_override": "https://www.herefordshire.gov.uk/rubbish-recycling/check-bin-collection-day?blpu_uprn=XXXXXXXXXXXX",
|
888
|
+
"wiki_name": "Herefordshire Council",
|
889
|
+
"wiki_note": "Replace 'XXXXXXXXXX' with your property's UPRN. You can find it using [FindMyAddress](https://www.findmyaddress.co.uk/search)."
|
890
|
+
},
|
885
891
|
"HertsmereBoroughCouncil": {
|
886
892
|
"house_number": "1",
|
887
893
|
"postcode": "WD7 9HZ",
|
@@ -19,87 +19,97 @@ class CouncilClass(AbstractGetBinDataClass):
|
|
19
19
|
"""
|
20
20
|
|
21
21
|
def parse_data(self, page: str, **kwargs) -> dict:
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
# Wait for the postcode field to appear then populate it
|
42
|
-
WebDriverWait(driver, 10).until(
|
43
|
-
EC.presence_of_element_located(
|
44
|
-
(By.CSS_SELECTOR, "input.relation_path_type_ahead_search")
|
22
|
+
driver = None
|
23
|
+
try:
|
24
|
+
# Get and check UPRN
|
25
|
+
user_postcode = kwargs.get("postcode")
|
26
|
+
user_paon = kwargs.get("paon")
|
27
|
+
check_paon(user_paon)
|
28
|
+
check_postcode(user_postcode)
|
29
|
+
web_driver = kwargs.get("web_driver")
|
30
|
+
headless = kwargs.get("headless")
|
31
|
+
bindata = {"bins": []}
|
32
|
+
|
33
|
+
API_URL = "https://portal.digital.ashfield.gov.uk/w/webpage/raise-case?service=bin_calendar"
|
34
|
+
|
35
|
+
# Create Selenium webdriver
|
36
|
+
driver = create_webdriver(web_driver, headless, None, __name__)
|
37
|
+
driver.get(API_URL)
|
38
|
+
|
39
|
+
title = WebDriverWait(driver, 10).until(
|
40
|
+
EC.presence_of_element_located((By.ID, "sub_page_title"))
|
45
41
|
)
|
46
|
-
)
|
47
42
|
|
48
|
-
|
49
|
-
|
50
|
-
(
|
43
|
+
# Wait for the postcode field to appear then populate it
|
44
|
+
WebDriverWait(driver, 10).until(
|
45
|
+
EC.presence_of_element_located(
|
46
|
+
(By.CSS_SELECTOR, "input.relation_path_type_ahead_search")
|
47
|
+
)
|
51
48
|
)
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
# Wait for the 'Select your property' dropdown to appear and select the first result
|
57
|
-
dropdown = WebDriverWait(driver, 10).until(
|
58
|
-
EC.element_to_be_clickable(
|
59
|
-
(
|
60
|
-
By.CLASS_NAME,
|
61
|
-
"result_list ",
|
49
|
+
|
50
|
+
inputElement_postcode = WebDriverWait(driver, 10).until(
|
51
|
+
EC.presence_of_element_located(
|
52
|
+
(By.CSS_SELECTOR, "input.relation_path_type_ahead_search")
|
62
53
|
)
|
63
54
|
)
|
64
|
-
|
55
|
+
inputElement_postcode.clear()
|
56
|
+
inputElement_postcode.send_keys(user_postcode)
|
65
57
|
|
66
|
-
|
67
|
-
WebDriverWait(driver, 10)
|
68
|
-
.until(
|
58
|
+
# Wait for the 'Select your property' dropdown to appear and select the first result
|
59
|
+
dropdown = WebDriverWait(driver, 10).until(
|
69
60
|
EC.element_to_be_clickable(
|
70
|
-
(
|
61
|
+
(
|
62
|
+
By.CLASS_NAME,
|
63
|
+
"result_list ",
|
64
|
+
)
|
71
65
|
)
|
72
66
|
)
|
73
|
-
.click()
|
74
|
-
)
|
75
67
|
|
76
|
-
|
77
|
-
|
78
|
-
(
|
68
|
+
address_element = (
|
69
|
+
WebDriverWait(driver, 10)
|
70
|
+
.until(
|
71
|
+
EC.element_to_be_clickable(
|
72
|
+
(By.XPATH, f"//li[starts-with(@aria-label, '{user_paon}')]")
|
73
|
+
)
|
74
|
+
)
|
75
|
+
.click()
|
79
76
|
)
|
80
|
-
)
|
81
|
-
search_button.click()
|
82
|
-
|
83
|
-
time.sleep(10)
|
84
|
-
|
85
|
-
soup = BeautifulSoup(driver.page_source, features="html.parser")
|
86
|
-
soup.prettify()
|
87
|
-
|
88
|
-
# Find the table by class name
|
89
|
-
table = soup.find("table", {"class": "table listing table-striped"})
|
90
|
-
|
91
|
-
# Iterate over each row in the tbody of the table
|
92
|
-
for row in table.find("tbody").find_all("tr"):
|
93
|
-
# Extract the service, day, and date for each row
|
94
|
-
service = row.find_all("td")[0].get_text(strip=True)
|
95
|
-
date = row.find_all("td")[2].get_text(strip=True)
|
96
|
-
|
97
|
-
dict_data = {
|
98
|
-
"type": service,
|
99
|
-
"collectionDate": datetime.strptime(date, "%a, %d %b %Y").strftime(
|
100
|
-
date_format
|
101
|
-
),
|
102
|
-
}
|
103
|
-
bindata["bins"].append(dict_data)
|
104
77
|
|
78
|
+
search_button = WebDriverWait(driver, 10).until(
|
79
|
+
EC.element_to_be_clickable(
|
80
|
+
(By.XPATH, "//input[@type='submit' and @value='Search']")
|
81
|
+
)
|
82
|
+
)
|
83
|
+
search_button.click()
|
84
|
+
|
85
|
+
time.sleep(10)
|
86
|
+
|
87
|
+
soup = BeautifulSoup(driver.page_source, features="html.parser")
|
88
|
+
soup.prettify()
|
89
|
+
|
90
|
+
# Find the table by class name
|
91
|
+
table = soup.find("table", {"class": "table listing table-striped"})
|
92
|
+
|
93
|
+
# Iterate over each row in the tbody of the table
|
94
|
+
for row in table.find("tbody").find_all("tr"):
|
95
|
+
# Extract the service, day, and date for each row
|
96
|
+
service = row.find_all("td")[0].get_text(strip=True)
|
97
|
+
date = row.find_all("td")[2].get_text(strip=True)
|
98
|
+
|
99
|
+
dict_data = {
|
100
|
+
"type": service,
|
101
|
+
"collectionDate": datetime.strptime(date, "%a, %d %b %Y").strftime(
|
102
|
+
date_format
|
103
|
+
),
|
104
|
+
}
|
105
|
+
bindata["bins"].append(dict_data)
|
106
|
+
except Exception as e:
|
107
|
+
# Here you can log the exception if needed
|
108
|
+
print(f"An error occurred: {e}")
|
109
|
+
# Optionally, re-raise the exception if you want it to propagate
|
110
|
+
raise
|
111
|
+
finally:
|
112
|
+
# This block ensures that the driver is closed regardless of an exception
|
113
|
+
if driver:
|
114
|
+
driver.quit()
|
105
115
|
return bindata
|
@@ -0,0 +1,53 @@
|
|
1
|
+
import logging
|
2
|
+
|
3
|
+
from bs4 import BeautifulSoup
|
4
|
+
|
5
|
+
from uk_bin_collection.uk_bin_collection.common import *
|
6
|
+
from uk_bin_collection.uk_bin_collection.get_bin_data import AbstractGetBinDataClass
|
7
|
+
|
8
|
+
|
9
|
+
# import the wonderful Beautiful Soup and the URL grabber
|
10
|
+
class CouncilClass(AbstractGetBinDataClass):
|
11
|
+
"""
|
12
|
+
Concrete classes have to implement all abstract operations of the
|
13
|
+
base class. They can also override some operations with a default
|
14
|
+
implementation.
|
15
|
+
"""
|
16
|
+
|
17
|
+
def parse_data(self, page: str, **kwargs) -> dict:
|
18
|
+
# Make a BS4 object
|
19
|
+
soup = BeautifulSoup(page.text, features="html.parser")
|
20
|
+
soup.prettify()
|
21
|
+
|
22
|
+
data = {"bins": []}
|
23
|
+
|
24
|
+
checkValid = soup.find("p", id="selectedAddressResult")
|
25
|
+
if checkValid is None:
|
26
|
+
raise ValueError("Address/UPRN not found")
|
27
|
+
|
28
|
+
collections = soup.find("div", id="wasteCollectionDates")
|
29
|
+
|
30
|
+
for bins in collections.select('div[class*="hc-island"]'):
|
31
|
+
bin_type = bins.h4.get_text(strip=True)
|
32
|
+
|
33
|
+
# Last div.hc-island is the calendar link, skip it
|
34
|
+
if bin_type == "Calendar":
|
35
|
+
continue
|
36
|
+
|
37
|
+
# Next collection date is in a span under the second p.hc-no-margin of the div.
|
38
|
+
bin_collection = re.search(
|
39
|
+
r"(.*) \(.*\)", bins.select("div > p > span")[0].get_text(strip=True)
|
40
|
+
).group(1)
|
41
|
+
if bin_collection:
|
42
|
+
logging.info(
|
43
|
+
f"Bin type: {bin_type} - Collection date: {bin_collection}"
|
44
|
+
)
|
45
|
+
dict_data = {
|
46
|
+
"type": bin_type,
|
47
|
+
"collectionDate": datetime.strptime(
|
48
|
+
bin_collection, "%A %d %B %Y"
|
49
|
+
).strftime(date_format),
|
50
|
+
}
|
51
|
+
data["bins"].append(dict_data)
|
52
|
+
|
53
|
+
return data
|
@@ -21,121 +21,130 @@ class CouncilClass(AbstractGetBinDataClass):
|
|
21
21
|
|
22
22
|
def parse_data(self, page: str, **kwargs) -> dict:
|
23
23
|
driver = None
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
(
|
41
|
-
|
42
|
-
|
24
|
+
try:
|
25
|
+
data = {"bins": []}
|
26
|
+
user_paon = kwargs.get("paon")
|
27
|
+
user_postcode = kwargs.get("postcode")
|
28
|
+
web_driver = kwargs.get("web_driver")
|
29
|
+
headless = kwargs.get("headless")
|
30
|
+
check_paon(user_paon)
|
31
|
+
check_postcode(user_postcode)
|
32
|
+
|
33
|
+
user_paon = user_paon.upper()
|
34
|
+
|
35
|
+
# Create Selenium webdriver
|
36
|
+
driver = create_webdriver(web_driver, headless, None, __name__)
|
37
|
+
driver.get("https://en.powys.gov.uk/binday")
|
38
|
+
|
39
|
+
accept_button = WebDriverWait(driver, timeout=10).until(
|
40
|
+
EC.element_to_be_clickable(
|
41
|
+
(
|
42
|
+
By.NAME,
|
43
|
+
"acceptall",
|
44
|
+
)
|
43
45
|
)
|
44
46
|
)
|
45
|
-
|
46
|
-
accept_button.click()
|
47
|
+
accept_button.click()
|
47
48
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
49
|
+
# Wait for the postcode field to appear then populate it
|
50
|
+
inputElement_postcode = WebDriverWait(driver, 10).until(
|
51
|
+
EC.presence_of_element_located(
|
52
|
+
(By.ID, "BINDAYLOOKUP_ADDRESSLOOKUP_ADDRESSLOOKUPPOSTCODE")
|
53
|
+
)
|
52
54
|
)
|
53
|
-
|
54
|
-
inputElement_postcode.send_keys(user_postcode)
|
55
|
+
inputElement_postcode.send_keys(user_postcode)
|
55
56
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
)
|
61
|
-
)
|
62
|
-
findAddress.click()
|
63
|
-
|
64
|
-
# Wait for the 'Select address' dropdown to appear and select option matching the house name/number
|
65
|
-
WebDriverWait(driver, 10).until(
|
66
|
-
EC.element_to_be_clickable(
|
67
|
-
(
|
68
|
-
By.XPATH,
|
69
|
-
"//select[@id='BINDAYLOOKUP_ADDRESSLOOKUP_ADDRESSLOOKUPADDRESS']//option[contains(., '"
|
70
|
-
+ user_paon
|
71
|
-
+ "')]",
|
57
|
+
# Click search button
|
58
|
+
findAddress = WebDriverWait(driver, 10).until(
|
59
|
+
EC.presence_of_element_located(
|
60
|
+
(By.ID, "BINDAYLOOKUP_ADDRESSLOOKUP_ADDRESSLOOKUPSEARCH")
|
72
61
|
)
|
73
62
|
)
|
74
|
-
|
63
|
+
findAddress.click()
|
64
|
+
|
65
|
+
# Wait for the 'Select address' dropdown to appear and select option matching the house name/number
|
66
|
+
WebDriverWait(driver, 10).until(
|
67
|
+
EC.element_to_be_clickable(
|
68
|
+
(
|
69
|
+
By.XPATH,
|
70
|
+
"//select[@id='BINDAYLOOKUP_ADDRESSLOOKUP_ADDRESSLOOKUPADDRESS']//option[contains(., '"
|
71
|
+
+ user_paon
|
72
|
+
+ "')]",
|
73
|
+
)
|
74
|
+
)
|
75
|
+
).click()
|
76
|
+
|
77
|
+
# Wait for the submit button to appear, then click it to get the collection dates
|
78
|
+
WebDriverWait(driver, 30).until(
|
79
|
+
EC.element_to_be_clickable(
|
80
|
+
(By.ID, "BINDAYLOOKUP_ADDRESSLOOKUP_ADDRESSLOOKUPBUTTONS_NEXT")
|
81
|
+
)
|
82
|
+
).click()
|
75
83
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
84
|
+
# Wait for the collections table to appear
|
85
|
+
WebDriverWait(driver, 10).until(
|
86
|
+
EC.presence_of_element_located(
|
87
|
+
(By.ID, "BINDAYLOOKUP_COLLECTIONDATES_COLLECTIONDATES")
|
88
|
+
)
|
80
89
|
)
|
81
|
-
).click()
|
82
90
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
91
|
+
soup = BeautifulSoup(driver.page_source, features="html.parser")
|
92
|
+
|
93
|
+
# General rubbish collection dates
|
94
|
+
general_rubbish_section = soup.find(
|
95
|
+
"h3", string="General Rubbish / Wheelie bin"
|
87
96
|
)
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
# Recycling and food waste collection dates
|
110
|
-
recycling_section = soup.find("h3", string="Recycling and Food Waste")
|
111
|
-
recycling_dates = [
|
112
|
-
li.text for li in recycling_section.find_next("ul").find_all("li")
|
113
|
-
]
|
114
|
-
|
115
|
-
for date in recycling_dates:
|
116
|
-
dict_data = {
|
117
|
-
"type": "Recycling and Food Waste",
|
118
|
-
"collectionDate": datetime.strptime(
|
119
|
-
remove_ordinal_indicator_from_date_string(date), "%d %B %Y"
|
120
|
-
).strftime(date_format),
|
121
|
-
}
|
122
|
-
data["bins"].append(dict_data)
|
123
|
-
|
124
|
-
# Garden waste collection dates
|
125
|
-
garden_waste_section = soup.find("h3", string="Garden Waste")
|
126
|
-
garden_waste_dates = [
|
127
|
-
li.text for li in garden_waste_section.find_next("ul").find_all("li")
|
128
|
-
]
|
129
|
-
for date in garden_waste_dates:
|
130
|
-
try:
|
97
|
+
general_rubbish_dates = [
|
98
|
+
li.text for li in general_rubbish_section.find_next("ul").find_all("li")
|
99
|
+
]
|
100
|
+
|
101
|
+
for date in general_rubbish_dates:
|
102
|
+
dict_data = {
|
103
|
+
"type": "General Rubbish / Wheelie bin",
|
104
|
+
"collectionDate": datetime.strptime(
|
105
|
+
remove_ordinal_indicator_from_date_string(date), "%d %B %Y"
|
106
|
+
).strftime(date_format),
|
107
|
+
}
|
108
|
+
data["bins"].append(dict_data)
|
109
|
+
|
110
|
+
# Recycling and food waste collection dates
|
111
|
+
recycling_section = soup.find("h3", string="Recycling and Food Waste")
|
112
|
+
recycling_dates = [
|
113
|
+
li.text for li in recycling_section.find_next("ul").find_all("li")
|
114
|
+
]
|
115
|
+
|
116
|
+
for date in recycling_dates:
|
131
117
|
dict_data = {
|
132
|
-
"type": "
|
118
|
+
"type": "Recycling and Food Waste",
|
133
119
|
"collectionDate": datetime.strptime(
|
134
120
|
remove_ordinal_indicator_from_date_string(date), "%d %B %Y"
|
135
121
|
).strftime(date_format),
|
136
122
|
}
|
137
123
|
data["bins"].append(dict_data)
|
138
|
-
except:
|
139
|
-
continue
|
140
124
|
|
125
|
+
# Garden waste collection dates
|
126
|
+
garden_waste_section = soup.find("h3", string="Garden Waste")
|
127
|
+
garden_waste_dates = [
|
128
|
+
li.text for li in garden_waste_section.find_next("ul").find_all("li")
|
129
|
+
]
|
130
|
+
for date in garden_waste_dates:
|
131
|
+
try:
|
132
|
+
dict_data = {
|
133
|
+
"type": "Garden Waste",
|
134
|
+
"collectionDate": datetime.strptime(
|
135
|
+
remove_ordinal_indicator_from_date_string(date), "%d %B %Y"
|
136
|
+
).strftime(date_format),
|
137
|
+
}
|
138
|
+
data["bins"].append(dict_data)
|
139
|
+
except:
|
140
|
+
continue
|
141
|
+
except Exception as e:
|
142
|
+
# Here you can log the exception if needed
|
143
|
+
print(f"An error occurred: {e}")
|
144
|
+
# Optionally, re-raise the exception if you want it to propagate
|
145
|
+
raise
|
146
|
+
finally:
|
147
|
+
# This block ensures that the driver is closed regardless of an exception
|
148
|
+
if driver:
|
149
|
+
driver.quit()
|
141
150
|
return data
|
@@ -16,44 +16,53 @@ class CouncilClass(AbstractGetBinDataClass):
|
|
16
16
|
"""
|
17
17
|
|
18
18
|
def parse_data(self, page: str, **kwargs) -> dict:
|
19
|
+
driver = None
|
20
|
+
try:
|
21
|
+
user_uprn = kwargs.get("uprn")
|
22
|
+
web_driver = kwargs.get("web_driver")
|
23
|
+
headless = kwargs.get("headless")
|
24
|
+
check_uprn(user_uprn)
|
25
|
+
bindata = {"bins": []}
|
19
26
|
|
20
|
-
|
21
|
-
web_driver = kwargs.get("web_driver")
|
22
|
-
headless = kwargs.get("headless")
|
23
|
-
check_uprn(user_uprn)
|
24
|
-
bindata = {"bins": []}
|
25
|
-
|
26
|
-
URI = f"https://www.teignbridge.gov.uk/repositories/hidden-pages/bin-finder?uprn={user_uprn}"
|
27
|
-
|
28
|
-
driver = create_webdriver(web_driver, headless, None, __name__)
|
29
|
-
driver.get(URI)
|
30
|
-
|
31
|
-
soup = BeautifulSoup(driver.page_source, features="html.parser")
|
32
|
-
|
33
|
-
collection_dates = soup.find_all(
|
34
|
-
"h3"
|
35
|
-
) # Assuming bin types are inside <h3> tags
|
36
|
-
bin_type_headers = soup.find_all(
|
37
|
-
"div", {"class": "binInfoContainer"}
|
38
|
-
) # Assuming collection dates are inside <p> tags
|
39
|
-
|
40
|
-
# Iterate over the results and extract bin type and collection dates
|
41
|
-
for i, date in enumerate(collection_dates):
|
42
|
-
collection_date = date.get_text(strip=True)
|
43
|
-
|
44
|
-
bin_types = bin_type_headers[i].find_all("div")
|
45
|
-
for bin_type in bin_types:
|
46
|
-
dict_data = {
|
47
|
-
"type": bin_type.text.strip(),
|
48
|
-
"collectionDate": datetime.strptime(
|
49
|
-
collection_date,
|
50
|
-
"%d %B %Y%A",
|
51
|
-
).strftime("%d/%m/%Y"),
|
52
|
-
}
|
53
|
-
bindata["bins"].append(dict_data)
|
54
|
-
|
55
|
-
bindata["bins"].sort(
|
56
|
-
key=lambda x: datetime.strptime(x.get("collectionDate"), "%d/%m/%Y")
|
57
|
-
)
|
27
|
+
URI = f"https://www.teignbridge.gov.uk/repositories/hidden-pages/bin-finder?uprn={user_uprn}"
|
58
28
|
|
29
|
+
driver = create_webdriver(web_driver, headless, None, __name__)
|
30
|
+
driver.get(URI)
|
31
|
+
|
32
|
+
soup = BeautifulSoup(driver.page_source, features="html.parser")
|
33
|
+
|
34
|
+
collection_dates = soup.find_all(
|
35
|
+
"h3"
|
36
|
+
) # Assuming bin types are inside <h3> tags
|
37
|
+
bin_type_headers = soup.find_all(
|
38
|
+
"div", {"class": "binInfoContainer"}
|
39
|
+
) # Assuming collection dates are inside <p> tags
|
40
|
+
|
41
|
+
# Iterate over the results and extract bin type and collection dates
|
42
|
+
for i, date in enumerate(collection_dates):
|
43
|
+
collection_date = date.get_text(strip=True)
|
44
|
+
|
45
|
+
bin_types = bin_type_headers[i].find_all("div")
|
46
|
+
for bin_type in bin_types:
|
47
|
+
dict_data = {
|
48
|
+
"type": bin_type.text.strip(),
|
49
|
+
"collectionDate": datetime.strptime(
|
50
|
+
collection_date,
|
51
|
+
"%d %B %Y%A",
|
52
|
+
).strftime("%d/%m/%Y"),
|
53
|
+
}
|
54
|
+
bindata["bins"].append(dict_data)
|
55
|
+
|
56
|
+
bindata["bins"].sort(
|
57
|
+
key=lambda x: datetime.strptime(x.get("collectionDate"), "%d/%m/%Y")
|
58
|
+
)
|
59
|
+
except Exception as e:
|
60
|
+
# Here you can log the exception if needed
|
61
|
+
print(f"An error occurred: {e}")
|
62
|
+
# Optionally, re-raise the exception if you want it to propagate
|
63
|
+
raise
|
64
|
+
finally:
|
65
|
+
# This block ensures that the driver is closed regardless of an exception
|
66
|
+
if driver:
|
67
|
+
driver.quit()
|
59
68
|
return bindata
|
@@ -2,7 +2,7 @@ uk_bin_collection/README.rst,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,
|
|
2
2
|
uk_bin_collection/tests/council_feature_input_parity.py,sha256=DO6Mk4ImYgM5ZCZ-cutwz5RoYYWZRLYx2tr6zIs_9Rc,3843
|
3
3
|
uk_bin_collection/tests/features/environment.py,sha256=VQZjJdJI_kZn08M0j5cUgvKT4k3iTw8icJge1DGOkoA,127
|
4
4
|
uk_bin_collection/tests/features/validate_council_outputs.feature,sha256=SJK-Vc737hrf03tssxxbeg_JIvAH-ddB8f6gU1LTbuQ,251
|
5
|
-
uk_bin_collection/tests/input.json,sha256=
|
5
|
+
uk_bin_collection/tests/input.json,sha256=EUx3biB0uK4bYrQEM5YTMa3xXTxKVfb0-mcw8bupyqM,115835
|
6
6
|
uk_bin_collection/tests/output.schema,sha256=ZwKQBwYyTDEM4G2hJwfLUVM-5v1vKRvRK9W9SS1sd18,1086
|
7
7
|
uk_bin_collection/tests/step_defs/step_helpers/file_handler.py,sha256=Ygzi4V0S1MIHqbdstUlIqtRIwnynvhu4UtpweJ6-5N8,1474
|
8
8
|
uk_bin_collection/tests/step_defs/test_validate_council.py,sha256=VZ0a81sioJULD7syAYHjvK_-nT_Rd36tUyzPetSA0gk,3475
|
@@ -20,7 +20,7 @@ uk_bin_collection/uk_bin_collection/councils/ArdsAndNorthDownCouncil.py,sha256=E
|
|
20
20
|
uk_bin_collection/uk_bin_collection/councils/ArgyllandButeCouncil.py,sha256=fJ0UvuSCbzFE9CPoxt1U9CJeFsbTKts_5GRBc3E9Eno,2201
|
21
21
|
uk_bin_collection/uk_bin_collection/councils/ArmaghBanbridgeCraigavonCouncil.py,sha256=o9NBbVCTdxKXnpYbP8-zxe1Gh8s57vwfV75Son_sAHE,2863
|
22
22
|
uk_bin_collection/uk_bin_collection/councils/ArunCouncil.py,sha256=yfhthv9nuogP19VOZ3TYQrq51qqjiCZcSel4sXhiKjs,4012
|
23
|
-
uk_bin_collection/uk_bin_collection/councils/AshfieldDistrictCouncil.py,sha256=
|
23
|
+
uk_bin_collection/uk_bin_collection/councils/AshfieldDistrictCouncil.py,sha256=fhX7S_A3jqoND7NE6qITPMPvdk3FJSKZ3Eoa5RtSg3I,4247
|
24
24
|
uk_bin_collection/uk_bin_collection/councils/AshfordBoroughCouncil.py,sha256=yC-8UMQHSbvze43PJ2_F4Z3cu7M7cynKTojipBJU7Ug,4307
|
25
25
|
uk_bin_collection/uk_bin_collection/councils/AylesburyValeCouncil.py,sha256=LouqjspEMt1TkOGqWHs2zkxwOETIy3n7p64uKIlAgUg,2401
|
26
26
|
uk_bin_collection/uk_bin_collection/councils/BCPCouncil.py,sha256=W7QBx6Mgso8RYosuXsaYo3GGNAu-tiyBSmuYxr1JSOU,1707
|
@@ -129,6 +129,7 @@ uk_bin_collection/uk_bin_collection/councils/HaringeyCouncil.py,sha256=t_6AkAu4w
|
|
129
129
|
uk_bin_collection/uk_bin_collection/councils/HarrogateBoroughCouncil.py,sha256=_g3fP5Nq-OUjgNrfRf4UEyFKzq0x8QK-4enh5RP1efA,2050
|
130
130
|
uk_bin_collection/uk_bin_collection/councils/HartDistrictCouncil.py,sha256=_llxT4JYYlwm20ZtS3fXwtDs6mwJyLTZBP2wBhvEpWk,2342
|
131
131
|
uk_bin_collection/uk_bin_collection/councils/HartlepoolBoroughCouncil.py,sha256=MUT1A24iZShT2p55rXEvgYwGUuw3W05Z4ZQAveehv-s,2842
|
132
|
+
uk_bin_collection/uk_bin_collection/councils/HerefordshireCouncil.py,sha256=JpQhkWM6Jeuzf1W7r0HqvtVnEqNi18nhwJX70YucdsI,1848
|
132
133
|
uk_bin_collection/uk_bin_collection/councils/HertsmereBoroughCouncil.py,sha256=-ThSG6NIJP_wf2GmGL7SAvxbOujdhanZ8ECP4VSQCBs,5415
|
133
134
|
uk_bin_collection/uk_bin_collection/councils/HighPeakCouncil.py,sha256=x7dfy8mdt2iGl8qJxHb-uBh4u0knmi9MJ6irOJw9WYA,4805
|
134
135
|
uk_bin_collection/uk_bin_collection/councils/HighlandCouncil.py,sha256=GNxDU65QuZHV5va2IrKtcJ6TQoDdwmV03JvkVqOauP4,3291
|
@@ -203,7 +204,7 @@ uk_bin_collection/uk_bin_collection/councils/OxfordCityCouncil.py,sha256=d_bY0cX
|
|
203
204
|
uk_bin_collection/uk_bin_collection/councils/PerthAndKinrossCouncil.py,sha256=Kos5GzN2co3Ij3tSHOXB9S71Yt78RROCfVRtnh7M1VU,3657
|
204
205
|
uk_bin_collection/uk_bin_collection/councils/PlymouthCouncil.py,sha256=FJqpJ0GJhpjYeyZ9ioZPkKGl-zrqMD3y5iKa07e_i30,3202
|
205
206
|
uk_bin_collection/uk_bin_collection/councils/PortsmouthCityCouncil.py,sha256=xogNgVvwM5FljCziiNLgZ_wzkOnrQkifi1dkPMDRMtg,5588
|
206
|
-
uk_bin_collection/uk_bin_collection/councils/PowysCouncil.py,sha256=
|
207
|
+
uk_bin_collection/uk_bin_collection/councils/PowysCouncil.py,sha256=db3Y5FJz-LFDqmVZqPdzcBxh0Q26OFPrbUxlQ7r4vsQ,5896
|
207
208
|
uk_bin_collection/uk_bin_collection/councils/PrestonCityCouncil.py,sha256=3Nuin2hQsiEsbJR_kHldtzRhzmnPFctH7C7MFG7thj8,3838
|
208
209
|
uk_bin_collection/uk_bin_collection/councils/ReadingBoroughCouncil.py,sha256=ZlQjU0IeKylGE9VlivSMh4XKwoLgntESPiylSOYkuD4,1009
|
209
210
|
uk_bin_collection/uk_bin_collection/councils/RedditchBoroughCouncil.py,sha256=8QmcpStCT7c-CLhmiQ8ZeEyvtysU110VDiMQdfQTErk,2469
|
@@ -256,7 +257,7 @@ uk_bin_collection/uk_bin_collection/councils/SwanseaCouncil.py,sha256=nmVPoPhnFg
|
|
256
257
|
uk_bin_collection/uk_bin_collection/councils/SwindonBoroughCouncil.py,sha256=lSIykpkBjVwQSf3rrnrNuh7YRepgnkKQLbf1iErMuJs,1932
|
257
258
|
uk_bin_collection/uk_bin_collection/councils/TamesideMBCouncil.py,sha256=k2TAAZG7n2S1BWVyxbE_-4-lZuzhOimCNz4yimUCOGk,1995
|
258
259
|
uk_bin_collection/uk_bin_collection/councils/TandridgeDistrictCouncil.py,sha256=KLVvM2NNq_DQylVe5dwO2l7qPahLHg08jJGLCv1MBQ4,2324
|
259
|
-
uk_bin_collection/uk_bin_collection/councils/TeignbridgeCouncil.py,sha256
|
260
|
+
uk_bin_collection/uk_bin_collection/councils/TeignbridgeCouncil.py,sha256=-NowMNcxsnktzUxTk-XUfzFJgXKSSerCmdZ7cN4cE1s,2703
|
260
261
|
uk_bin_collection/uk_bin_collection/councils/TelfordAndWrekinCouncil.py,sha256=p1ZS5R4EGxbEWlRBrkGXgKwE_lkyBT-R60yKFFhVObc,1844
|
261
262
|
uk_bin_collection/uk_bin_collection/councils/TendringDistrictCouncil.py,sha256=DJbYI8m6lIISDrK5h8V5Jo-9kGG7kr9dz7GD8St4nc8,4274
|
262
263
|
uk_bin_collection/uk_bin_collection/councils/TestValleyBoroughCouncil.py,sha256=Dtfkyrwt795W7gqFJxVGRR8t3R5WMNQZwTWJckLpZWE,8480
|
@@ -305,8 +306,8 @@ uk_bin_collection/uk_bin_collection/councils/YorkCouncil.py,sha256=I2kBYMlsD4bId
|
|
305
306
|
uk_bin_collection/uk_bin_collection/councils/council_class_template/councilclasstemplate.py,sha256=EQWRhZ2pEejlvm0fPyOTsOHKvUZmPnxEYO_OWRGKTjs,1158
|
306
307
|
uk_bin_collection/uk_bin_collection/create_new_council.py,sha256=m-IhmWmeWQlFsTZC4OxuFvtw5ZtB8EAJHxJTH4O59lQ,1536
|
307
308
|
uk_bin_collection/uk_bin_collection/get_bin_data.py,sha256=YvmHfZqanwrJ8ToGch34x-L-7yPe31nB_x77_Mgl_vo,4545
|
308
|
-
uk_bin_collection-0.
|
309
|
-
uk_bin_collection-0.
|
310
|
-
uk_bin_collection-0.
|
311
|
-
uk_bin_collection-0.
|
312
|
-
uk_bin_collection-0.
|
309
|
+
uk_bin_collection-0.130.1.dist-info/LICENSE,sha256=vABBUOzcrgfaTKpzeo-si9YVEun6juDkndqA8RKdKGs,1071
|
310
|
+
uk_bin_collection-0.130.1.dist-info/METADATA,sha256=hJOq8xXrfHC1KyQ9OutxVsvz57Mi8aXuBCjC8scAFEI,19549
|
311
|
+
uk_bin_collection-0.130.1.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
|
312
|
+
uk_bin_collection-0.130.1.dist-info/entry_points.txt,sha256=36WCSGMWSc916S3Hi1ZkazzDKHaJ6CD-4fCEFm5MIao,90
|
313
|
+
uk_bin_collection-0.130.1.dist-info/RECORD,,
|
File without changes
|
File without changes
|
{uk_bin_collection-0.129.0.dist-info → uk_bin_collection-0.130.1.dist-info}/entry_points.txt
RENAMED
File without changes
|