uk_bin_collection 0.152.11__py3-none-any.whl → 0.153.0__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 +3 -6
- uk_bin_collection/uk_bin_collection/councils/BoltonCouncil.py +1 -1
- uk_bin_collection/uk_bin_collection/councils/BuckinghamshireCouncil.py +75 -100
- uk_bin_collection/uk_bin_collection/councils/EastHertsCouncil.py +82 -24
- uk_bin_collection/uk_bin_collection/councils/HinckleyandBosworthBoroughCouncil.py +7 -1
- uk_bin_collection/uk_bin_collection/councils/IpswichBoroughCouncil.py +3 -1
- uk_bin_collection/uk_bin_collection/councils/LichfieldDistrictCouncil.py +7 -1
- uk_bin_collection/uk_bin_collection/councils/NorthEastLincs.py +17 -6
- uk_bin_collection/uk_bin_collection/councils/NorwichCityCouncil.py +67 -66
- uk_bin_collection/uk_bin_collection/councils/NuneatonBedworthBoroughCouncil.py +19 -7
- uk_bin_collection/uk_bin_collection/councils/RunnymedeBoroughCouncil.py +7 -1
- uk_bin_collection/uk_bin_collection/councils/StaffordshireMoorlandsDistrictCouncil.py +4 -0
- uk_bin_collection/uk_bin_collection/councils/WiltshireCouncil.py +47 -29
- {uk_bin_collection-0.152.11.dist-info → uk_bin_collection-0.153.0.dist-info}/METADATA +1 -1
- {uk_bin_collection-0.152.11.dist-info → uk_bin_collection-0.153.0.dist-info}/RECORD +18 -18
- {uk_bin_collection-0.152.11.dist-info → uk_bin_collection-0.153.0.dist-info}/LICENSE +0 -0
- {uk_bin_collection-0.152.11.dist-info → uk_bin_collection-0.153.0.dist-info}/WHEEL +0 -0
- {uk_bin_collection-0.152.11.dist-info → uk_bin_collection-0.153.0.dist-info}/entry_points.txt +0 -0
@@ -253,7 +253,7 @@
|
|
253
253
|
"postcode": "BL1 5PQ",
|
254
254
|
"skip_get_url": true,
|
255
255
|
"uprn": "100010886936",
|
256
|
-
"url": "https://
|
256
|
+
"url": "https://web.bolton.gov.uk/bins.aspx",
|
257
257
|
"web_driver": "http://selenium:4444",
|
258
258
|
"wiki_name": "Bolton",
|
259
259
|
"wiki_note": "To get the UPRN, you will need to use [FindMyAddress](https://www.findmyaddress.co.uk/search). Previously required a single field that was UPRN and full address; now requires UPRN and postcode as separate fields.",
|
@@ -377,13 +377,10 @@
|
|
377
377
|
"LAD24CD": "E07000172"
|
378
378
|
},
|
379
379
|
"BuckinghamshireCouncil": {
|
380
|
-
"house_number": "The Ridings, Magpie Lane, Loudwater, High Wycombe, HP13 7BA",
|
381
|
-
"postcode": "HP13 7BA",
|
382
380
|
"uprn": "100081093078",
|
383
381
|
"url": "https://www.buckinghamshire.gov.uk/waste-and-recycling/find-out-when-its-your-bin-collection/",
|
384
|
-
"web_driver": "http://selenium:4444",
|
385
382
|
"wiki_name": "Buckinghamshire",
|
386
|
-
"wiki_note": "Pass the
|
383
|
+
"wiki_note": "Pass the UPRN. You can find it using [FindMyAddress](https://www.findmyaddress.co.uk/search).",
|
387
384
|
"LAD24CD": "E06000060"
|
388
385
|
},
|
389
386
|
"BurnleyBoroughCouncil": {
|
@@ -1446,7 +1443,7 @@
|
|
1446
1443
|
"house_number": "71",
|
1447
1444
|
"postcode": "ME16 8BT",
|
1448
1445
|
"url": "https://my.maidstone.gov.uk/service/Find-your-bin-day",
|
1449
|
-
"web_driver": "http://selenium:4444",
|
1446
|
+
"web_driver": "http://selenium:4444",
|
1450
1447
|
"wiki_name": "Maidstone",
|
1451
1448
|
"wiki_note": "Pass the house number and postcode in their respective parameters. This parser requires a Selenium webdriver.",
|
1452
1449
|
"LAD24CD": "E07000110"
|
@@ -35,7 +35,7 @@ class CouncilClass(AbstractGetBinDataClass):
|
|
35
35
|
data = {"bins": []}
|
36
36
|
|
37
37
|
# Get our initial session running
|
38
|
-
page = "https://
|
38
|
+
page = "https://web.bolton.gov.uk/bins.aspx"
|
39
39
|
|
40
40
|
driver = create_webdriver(web_driver, headless, None, __name__)
|
41
41
|
driver.get(page)
|
@@ -1,11 +1,26 @@
|
|
1
|
-
|
2
|
-
from
|
3
|
-
from
|
4
|
-
from selenium.webdriver.support.wait import WebDriverWait
|
1
|
+
import json
|
2
|
+
from dataclasses import asdict, dataclass
|
3
|
+
from typing import Literal
|
5
4
|
|
6
|
-
|
5
|
+
import requests
|
6
|
+
from cryptography.hazmat.backends import default_backend
|
7
|
+
from cryptography.hazmat.primitives import padding
|
8
|
+
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
|
9
|
+
|
10
|
+
from uk_bin_collection.uk_bin_collection.common import check_uprn
|
7
11
|
from uk_bin_collection.uk_bin_collection.get_bin_data import AbstractGetBinDataClass
|
8
12
|
|
13
|
+
key_hex = "F57E76482EE3DC3336495DEDEEF3962671B054FE353E815145E29C5689F72FEC"
|
14
|
+
iv_hex = "2CBF4FC35C69B82362D393A4F0B9971A"
|
15
|
+
|
16
|
+
|
17
|
+
@dataclass
|
18
|
+
class BucksInput:
|
19
|
+
P_CLIENT_ID: Literal[152]
|
20
|
+
P_COUNCIL_ID: Literal[34505]
|
21
|
+
P_LANG_CODE: Literal["EN"]
|
22
|
+
P_UPRN: str
|
23
|
+
|
9
24
|
|
10
25
|
class CouncilClass(AbstractGetBinDataClass):
|
11
26
|
"""
|
@@ -14,113 +29,73 @@ class CouncilClass(AbstractGetBinDataClass):
|
|
14
29
|
implementation.
|
15
30
|
"""
|
16
31
|
|
17
|
-
def
|
18
|
-
|
32
|
+
def encode_body(self, bucks_input: BucksInput):
|
33
|
+
key = bytes.fromhex(key_hex)
|
34
|
+
iv = bytes.fromhex(iv_hex)
|
35
|
+
|
36
|
+
json_data = json.dumps(asdict(bucks_input))
|
37
|
+
data_bytes = json_data.encode("utf-8")
|
38
|
+
|
39
|
+
padder = padding.PKCS7(128).padder()
|
40
|
+
padded_data = padder.update(data_bytes) + padder.finalize()
|
41
|
+
|
42
|
+
backend = default_backend()
|
43
|
+
cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=backend)
|
44
|
+
encryptor = cipher.encryptor()
|
45
|
+
ciphertext = encryptor.update(padded_data) + encryptor.finalize()
|
46
|
+
|
47
|
+
return ciphertext.hex()
|
48
|
+
|
49
|
+
def decode_response(self, hex_input: str):
|
50
|
+
|
51
|
+
key = bytes.fromhex(key_hex)
|
52
|
+
iv = bytes.fromhex(iv_hex)
|
53
|
+
ciphertext = bytes.fromhex(hex_input)
|
54
|
+
|
55
|
+
backend = default_backend()
|
56
|
+
cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=backend)
|
57
|
+
decryptor = cipher.decryptor()
|
58
|
+
decrypted_padded = decryptor.update(ciphertext) + decryptor.finalize()
|
59
|
+
|
60
|
+
unpadder = padding.PKCS7(128).unpadder()
|
61
|
+
plaintext_bytes = unpadder.update(decrypted_padded) + unpadder.finalize()
|
62
|
+
plaintext = plaintext_bytes.decode("utf-8")
|
63
|
+
|
64
|
+
return json.loads(plaintext)
|
65
|
+
|
66
|
+
def parse_data(self, _: str, **kwargs) -> dict:
|
19
67
|
try:
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
web_driver = kwargs.get("web_driver")
|
25
|
-
headless = kwargs.get("headless")
|
26
|
-
check_paon(user_paon)
|
27
|
-
check_postcode(user_postcode)
|
28
|
-
|
29
|
-
# Create Selenium webdriver
|
30
|
-
driver = create_webdriver(web_driver, headless, None, __name__)
|
31
|
-
driver.get(kwargs.get("url"))
|
32
|
-
|
33
|
-
# Click "Check now" button
|
34
|
-
check_now_button = WebDriverWait(driver, 10).until(
|
35
|
-
EC.element_to_be_clickable((By.XPATH, "//a[contains(text(), 'Check now')]"))
|
68
|
+
user_uprn: str = kwargs.get("uprn") or ""
|
69
|
+
check_uprn(user_uprn)
|
70
|
+
bucks_input = BucksInput(
|
71
|
+
P_CLIENT_ID=152, P_COUNCIL_ID=34505, P_LANG_CODE="EN", P_UPRN=user_uprn
|
36
72
|
)
|
37
|
-
check_now_button.click()
|
38
73
|
|
39
|
-
|
40
|
-
inputElement_postcode = WebDriverWait(driver, 10).until(
|
41
|
-
EC.presence_of_element_located((By.ID, "postcodeSearch"))
|
42
|
-
)
|
43
|
-
inputElement_postcode.send_keys(user_postcode)
|
74
|
+
encoded_input = self.encode_body(bucks_input)
|
44
75
|
|
45
|
-
|
46
|
-
|
47
|
-
|
76
|
+
session = requests.Session()
|
77
|
+
response = session.post(
|
78
|
+
"https://itouchvision.app/portal/itouchvision/kmbd/collectionDay",
|
79
|
+
data=encoded_input,
|
48
80
|
)
|
49
|
-
find_button.click()
|
50
|
-
|
51
|
-
# Wait for the address dropdown and select by UPRN
|
52
|
-
if user_uprn:
|
53
|
-
address_option = WebDriverWait(driver, 10).until(
|
54
|
-
EC.element_to_be_clickable((By.XPATH, f"//option[@value='{user_uprn}']"))
|
55
|
-
)
|
56
|
-
address_option.click()
|
57
|
-
else:
|
58
|
-
# Fallback to selecting by address text
|
59
|
-
address_option = WebDriverWait(driver, 10).until(
|
60
|
-
EC.element_to_be_clickable(
|
61
|
-
(By.XPATH, f"//select[@id='addressSelect']//option[contains(., '{user_paon}')]")
|
62
|
-
)
|
63
|
-
)
|
64
|
-
address_option.click()
|
65
81
|
|
66
|
-
|
67
|
-
import time
|
68
|
-
time.sleep(2)
|
82
|
+
output = response.text
|
69
83
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
84
|
+
decoded_bins = self.decode_response(output)
|
85
|
+
data: dict[str, list[dict[str, str]]] = {}
|
86
|
+
data["bins"] = list(
|
87
|
+
map(
|
88
|
+
lambda a: {
|
89
|
+
"type": a["binType"],
|
90
|
+
"collectionDate": a["collectionDay"].replace("-", "/"),
|
91
|
+
},
|
92
|
+
decoded_bins["collectionDay"],
|
79
93
|
)
|
80
|
-
|
81
|
-
soup = BeautifulSoup(driver.page_source, features="html.parser")
|
82
|
-
|
83
|
-
# Find all collection items with the specific structure - try multiple class patterns
|
84
|
-
collection_items = soup.find_all("div", class_=lambda x: x and "ant-col" in x and "ant-col-xs-12" in x)
|
85
|
-
if not collection_items:
|
86
|
-
# Fallback to finding items by structure
|
87
|
-
collection_items = soup.find_all("div", class_=lambda x: x and "p-2" in x and "d-flex" in x and "flex-column" in x)
|
88
|
-
|
89
|
-
current_year = datetime.now().year
|
90
|
-
current_month = datetime.now().month
|
91
|
-
|
92
|
-
for item in collection_items:
|
93
|
-
# Extract bin type from h3 element
|
94
|
-
bin_type_elem = item.find("h3", class_="text-white")
|
95
|
-
# Extract date from div with specific classes
|
96
|
-
date_elem = item.find("div", class_="text-white fw-bold")
|
97
|
-
|
98
|
-
if bin_type_elem and date_elem:
|
99
|
-
bin_type = bin_type_elem.get_text().strip()
|
100
|
-
date_text = date_elem.get_text().strip()
|
101
|
-
|
102
|
-
try:
|
103
|
-
collection_date = datetime.strptime(date_text, "%A %d %B")
|
104
|
-
if (current_month > 10) and (collection_date.month < 3):
|
105
|
-
collection_date = collection_date.replace(year=(current_year + 1))
|
106
|
-
else:
|
107
|
-
collection_date = collection_date.replace(year=current_year)
|
108
|
-
|
109
|
-
dict_data = {
|
110
|
-
"type": bin_type,
|
111
|
-
"collectionDate": collection_date.strftime("%d/%m/%Y"),
|
112
|
-
}
|
113
|
-
data["bins"].append(dict_data)
|
114
|
-
except ValueError:
|
115
|
-
continue
|
94
|
+
)
|
116
95
|
|
117
96
|
except Exception as e:
|
118
97
|
# Here you can log the exception if needed
|
119
98
|
print(f"An error occurred: {e}")
|
120
99
|
# Optionally, re-raise the exception if you want it to propagate
|
121
100
|
raise
|
122
|
-
finally:
|
123
|
-
# This block ensures that the driver is closed regardless of an exception
|
124
|
-
if driver:
|
125
|
-
driver.quit()
|
126
101
|
return data
|
@@ -1,11 +1,13 @@
|
|
1
|
-
import
|
1
|
+
import time
|
2
|
+
|
2
3
|
import requests
|
3
|
-
from
|
4
|
+
from dateutil.relativedelta import relativedelta
|
4
5
|
|
5
6
|
from uk_bin_collection.uk_bin_collection.common import *
|
6
7
|
from uk_bin_collection.uk_bin_collection.get_bin_data import AbstractGetBinDataClass
|
7
8
|
|
8
9
|
|
10
|
+
# import the wonderful Beautiful Soup and the URL grabber
|
9
11
|
class CouncilClass(AbstractGetBinDataClass):
|
10
12
|
"""
|
11
13
|
Concrete classes have to implement all abstract operations of the
|
@@ -14,28 +16,84 @@ class CouncilClass(AbstractGetBinDataClass):
|
|
14
16
|
"""
|
15
17
|
|
16
18
|
def parse_data(self, page: str, **kwargs) -> dict:
|
17
|
-
|
18
|
-
|
19
|
+
# Make a BS4 object
|
20
|
+
uprn = kwargs.get("uprn")
|
21
|
+
# usrn = kwargs.get("paon")
|
22
|
+
check_uprn(uprn)
|
23
|
+
# check_usrn(usrn)
|
19
24
|
bindata = {"bins": []}
|
20
|
-
|
21
|
-
#
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
25
|
+
|
26
|
+
# uprn = uprn.zfill(12)
|
27
|
+
|
28
|
+
SESSION_URL = "https://eastherts-self.achieveservice.com/authapi/isauthenticated?uri=https%253A%252F%252Feastherts-self.achieveservice.com%252FAchieveForms%252F%253Fmode%253Dfill%2526consentMessage%253Dyes%2526form_uri%253Dsandbox-publish%253A%252F%252FAF-Process-98782935-6101-4962-9a55-5923e76057b6%252FAF-Stage-dcd0ec18-dfb4-496a-a266-bd8fadaa28a7%252Fdefinition.json%2526process%253D1%2526process_uri%253Dsandbox-processes%253A%252F%252FAF-Process-98782935-6101-4962-9a55-5923e76057b6%2526process_id%253DAF-Process-98782935-6101-4962-9a55-5923e76057b6&hostname=eastherts-self.achieveservice.com&withCredentials=true"
|
29
|
+
|
30
|
+
API_URL = "https://eastherts-self.achieveservice.com/apibroker/runLookup"
|
31
|
+
|
32
|
+
headers = {
|
33
|
+
"Content-Type": "application/json",
|
34
|
+
"Accept": "*/*",
|
35
|
+
"User-Agent": "Mozilla/5.0",
|
36
|
+
"X-Requested-With": "XMLHttpRequest",
|
37
|
+
"Referer": "https://eastherts-self.achieveservice.com/fillform/?iframe_id=fillform-frame-1&db_id=",
|
38
|
+
}
|
39
|
+
s = requests.session()
|
40
|
+
r = s.get(SESSION_URL)
|
41
|
+
r.raise_for_status()
|
42
|
+
session_data = r.json()
|
43
|
+
sid = session_data["auth-session"]
|
44
|
+
params = {
|
45
|
+
# unix_timestamp
|
46
|
+
"_": str(int(time.time() * 1000)),
|
47
|
+
"sid": sid,
|
48
|
+
}
|
49
|
+
|
50
|
+
params = {
|
51
|
+
"id": "683d9ff0e299d",
|
52
|
+
"repeat_against": "",
|
53
|
+
"noRetry": "true",
|
54
|
+
"getOnlyTokens": "undefined",
|
55
|
+
"log_id": "",
|
56
|
+
"app_name": "AF-Renderer::Self",
|
57
|
+
# unix_timestamp
|
58
|
+
"_": str(int(time.time() * 1000)),
|
59
|
+
"sid": sid,
|
60
|
+
}
|
61
|
+
|
62
|
+
data = {
|
63
|
+
"formValues": {
|
64
|
+
"Collection Days": {
|
65
|
+
"inputUPRN": {
|
66
|
+
"value": uprn,
|
38
67
|
}
|
39
|
-
|
40
|
-
|
68
|
+
},
|
69
|
+
}
|
70
|
+
}
|
71
|
+
|
72
|
+
r = s.post(API_URL, json=data, headers=headers, params=params)
|
73
|
+
r.raise_for_status()
|
74
|
+
|
75
|
+
data = r.json()
|
76
|
+
rows_data = data["integration"]["transformed"]["rows_data"]["0"]
|
77
|
+
if not isinstance(rows_data, dict):
|
78
|
+
raise ValueError("Invalid data returned from API")
|
79
|
+
|
80
|
+
# Extract each service's relevant details for the bin schedule
|
81
|
+
for key, value in rows_data.items():
|
82
|
+
if key.endswith("NextDate"):
|
83
|
+
BinType = key.replace("NextDate", "ServiceName")
|
84
|
+
for key2, value2 in rows_data.items():
|
85
|
+
if key2 == BinType:
|
86
|
+
BinType = value2
|
87
|
+
next_collection = datetime.strptime(
|
88
|
+
remove_ordinal_indicator_from_date_string(value), "%A %d %B"
|
89
|
+
).replace(year=datetime.now().year)
|
90
|
+
if datetime.now().month == 12 and next_collection.month == 1:
|
91
|
+
next_collection = next_collection + relativedelta(years=1)
|
92
|
+
|
93
|
+
dict_data = {
|
94
|
+
"type": BinType,
|
95
|
+
"collectionDate": next_collection.strftime(date_format),
|
96
|
+
}
|
97
|
+
bindata["bins"].append(dict_data)
|
98
|
+
|
41
99
|
return bindata
|
@@ -20,10 +20,16 @@ class CouncilClass(AbstractGetBinDataClass):
|
|
20
20
|
check_uprn(user_uprn)
|
21
21
|
bindata = {"bins": []}
|
22
22
|
|
23
|
+
headers = {
|
24
|
+
"Origin": "https://www.hinckley-bosworth.gov.uk",
|
25
|
+
"Referer": "https://www.hinckley-bosworth.gov.uk",
|
26
|
+
"User-Agent": "Mozilla/5.0",
|
27
|
+
}
|
28
|
+
|
23
29
|
URI = f"https://www.hinckley-bosworth.gov.uk/set-location?id={user_uprn}&redirect=refuse&rememberloc="
|
24
30
|
|
25
31
|
# Make the GET request
|
26
|
-
response = requests.get(URI)
|
32
|
+
response = requests.get(URI, headers=headers)
|
27
33
|
|
28
34
|
# Parse the HTML
|
29
35
|
soup = BeautifulSoup(response.content, "html.parser")
|
@@ -31,7 +31,9 @@ class CouncilClass(AbstractGetBinDataClass):
|
|
31
31
|
IBC_ENDPOINT = "https://app.ipswich.gov.uk/bin-collection/"
|
32
32
|
|
33
33
|
def transform_date(self, date_str):
|
34
|
-
date_str = re.sub(
|
34
|
+
date_str = re.sub(
|
35
|
+
r"(\d{1,2})(st|nd|rd|th)", r"\1", date_str
|
36
|
+
) # Remove ordinal suffixes
|
35
37
|
date_obj = datetime.strptime(date_str, "%A %d %B %Y")
|
36
38
|
return date_obj.strftime(date_format)
|
37
39
|
|
@@ -24,10 +24,16 @@ class CouncilClass(AbstractGetBinDataClass):
|
|
24
24
|
def solve(s):
|
25
25
|
return re.sub(r"(\d)(st|nd|rd|th)", r"\1", s)
|
26
26
|
|
27
|
+
headers = {
|
28
|
+
"Origin": "https://www.lichfielddc.gov.uk",
|
29
|
+
"Referer": "https://www.lichfielddc.gov.uk",
|
30
|
+
"User-Agent": "Mozilla/5.0",
|
31
|
+
}
|
32
|
+
|
27
33
|
URI = f"https://www.lichfielddc.gov.uk/homepage/6/bin-collection-dates?uprn={user_uprn}"
|
28
34
|
|
29
35
|
# Make the GET request
|
30
|
-
response = requests.get(URI)
|
36
|
+
response = requests.get(URI, headers=headers)
|
31
37
|
|
32
38
|
soup = BeautifulSoup(response.text, "html.parser")
|
33
39
|
|
@@ -1,5 +1,7 @@
|
|
1
1
|
import pandas as pd
|
2
|
+
import requests
|
2
3
|
from bs4 import BeautifulSoup
|
4
|
+
|
3
5
|
from uk_bin_collection.uk_bin_collection.common import date_format
|
4
6
|
from uk_bin_collection.uk_bin_collection.get_bin_data import AbstractGetBinDataClass
|
5
7
|
|
@@ -12,15 +14,26 @@ class CouncilClass(AbstractGetBinDataClass):
|
|
12
14
|
"""
|
13
15
|
|
14
16
|
def parse_data(self, page: str, **kwargs) -> dict:
|
15
|
-
|
16
|
-
|
17
|
+
user_url = kwargs.get("url")
|
18
|
+
|
19
|
+
headers = {
|
20
|
+
"Origin": "https://www.nelincs.gov.uk",
|
21
|
+
"Referer": "https://www.nelincs.gov.uk",
|
22
|
+
"User-Agent": "Mozilla/5.0",
|
23
|
+
}
|
24
|
+
|
25
|
+
# Make the GET request
|
26
|
+
response = requests.get(user_url, headers=headers)
|
27
|
+
|
28
|
+
# Parse the HTML
|
29
|
+
soup = BeautifulSoup(response.content, "html.parser")
|
17
30
|
soup.prettify()
|
18
31
|
|
19
32
|
data = {"bins": []}
|
20
33
|
|
21
34
|
# Get list items that can be seen on page
|
22
35
|
for element in soup.find_all(
|
23
|
-
"li", {"class": "list-group-item p-
|
36
|
+
"li", {"class": "border-0 list-group-item p-3 bg-light rounded p-2"}
|
24
37
|
):
|
25
38
|
element_text = element.text.strip().split("\n\n")
|
26
39
|
element_text = [x.strip() for x in element_text]
|
@@ -35,9 +48,7 @@ class CouncilClass(AbstractGetBinDataClass):
|
|
35
48
|
data["bins"].append(dict_data)
|
36
49
|
|
37
50
|
# Get hidden list items too
|
38
|
-
for element in soup.find_all(
|
39
|
-
"li", {"class": "list-group-item p-0 p-3 bin-collection-item d-none"}
|
40
|
-
):
|
51
|
+
for element in soup.find_all("li", {"class": "border-0 list-group-item p-3"}):
|
41
52
|
element_text = element.text.strip().split("\n\n")
|
42
53
|
element_text = [x.strip() for x in element_text]
|
43
54
|
|
@@ -1,5 +1,3 @@
|
|
1
|
-
import time
|
2
|
-
|
3
1
|
import requests
|
4
2
|
from bs4 import BeautifulSoup
|
5
3
|
|
@@ -17,76 +15,79 @@ class CouncilClass(AbstractGetBinDataClass):
|
|
17
15
|
|
18
16
|
def parse_data(self, page: str, **kwargs) -> dict:
|
19
17
|
|
20
|
-
|
21
|
-
|
18
|
+
user_postcode = kwargs.get("postcode")
|
19
|
+
user_paon = kwargs.get("paon")
|
20
|
+
check_postcode(user_postcode)
|
21
|
+
check_paon(user_paon)
|
22
22
|
bindata = {"bins": []}
|
23
23
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
24
|
+
URI = "https://bnr-wrp.whitespacews.com/"
|
25
|
+
|
26
|
+
session = requests.Session()
|
27
|
+
|
28
|
+
# get link from first page as has some kind of unique hash
|
29
|
+
r = session.get(
|
30
|
+
URI,
|
31
|
+
)
|
32
|
+
r.raise_for_status()
|
33
|
+
soup = BeautifulSoup(r.text, features="html.parser")
|
34
|
+
|
35
|
+
alink = soup.find("a", text="View my collections")
|
36
|
+
|
37
|
+
if alink is None:
|
38
|
+
raise Exception("Initial page did not load correctly")
|
39
|
+
|
40
|
+
# greplace 'seq' query string to skip next step
|
41
|
+
nextpageurl = alink["href"].replace("seq=1", "seq=2")
|
42
|
+
|
43
|
+
data = {
|
44
|
+
"address_name_number": user_paon,
|
45
|
+
"address_postcode": user_postcode,
|
36
46
|
}
|
37
47
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
soup = BeautifulSoup(
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
for bin in bin_types:
|
71
|
-
collections.append(
|
72
|
-
(
|
73
|
-
bin.capitalize(),
|
74
|
-
datetime.strptime(strong[1].text.strip(), date_format),
|
75
|
-
)
|
76
|
-
)
|
77
|
-
i += 2
|
78
|
-
|
79
|
-
if len(strong) > 3:
|
80
|
-
collections.append(
|
81
|
-
("Garden", datetime.strptime(strong[4].text.strip(), date_format))
|
82
|
-
)
|
83
|
-
|
84
|
-
ordered_data = sorted(collections, key=lambda x: x[1])
|
85
|
-
for item in ordered_data:
|
48
|
+
# get list of addresses
|
49
|
+
r = session.post(nextpageurl, data)
|
50
|
+
r.raise_for_status()
|
51
|
+
|
52
|
+
soup = BeautifulSoup(r.text, features="html.parser")
|
53
|
+
|
54
|
+
# get first address (if you don't enter enough argument values this won't find the right address)
|
55
|
+
alink = soup.find("div", id="property_list").find("a")
|
56
|
+
|
57
|
+
if alink is None:
|
58
|
+
raise Exception("Address not found")
|
59
|
+
|
60
|
+
nextpageurl = URI + alink["href"]
|
61
|
+
|
62
|
+
# get collection page
|
63
|
+
r = session.get(
|
64
|
+
nextpageurl,
|
65
|
+
)
|
66
|
+
r.raise_for_status()
|
67
|
+
soup = BeautifulSoup(r.text, features="html.parser")
|
68
|
+
|
69
|
+
if soup.find("span", id="waste-hint"):
|
70
|
+
raise Exception("No scheduled services at this address")
|
71
|
+
|
72
|
+
u1s = soup.find("section", id="scheduled-collections").find_all("u1")
|
73
|
+
|
74
|
+
for u1 in u1s:
|
75
|
+
lis = u1.find_all("li", recursive=False)
|
76
|
+
|
77
|
+
date = lis[1].text.replace("\n", "")
|
78
|
+
bin_type = lis[2].text.replace("\n", "")
|
79
|
+
|
86
80
|
dict_data = {
|
87
|
-
"type":
|
88
|
-
"collectionDate":
|
81
|
+
"type": bin_type,
|
82
|
+
"collectionDate": datetime.strptime(
|
83
|
+
date,
|
84
|
+
"%d/%m/%Y",
|
85
|
+
).strftime(date_format),
|
89
86
|
}
|
90
87
|
bindata["bins"].append(dict_data)
|
91
88
|
|
89
|
+
bindata["bins"].sort(
|
90
|
+
key=lambda x: datetime.strptime(x.get("collectionDate"), date_format)
|
91
|
+
)
|
92
|
+
|
92
93
|
return bindata
|
@@ -1,23 +1,29 @@
|
|
1
|
+
import re
|
2
|
+
import urllib.parse
|
3
|
+
|
4
|
+
import requests
|
1
5
|
from bs4 import BeautifulSoup
|
6
|
+
|
2
7
|
from uk_bin_collection.uk_bin_collection.common import *
|
3
8
|
from uk_bin_collection.uk_bin_collection.get_bin_data import AbstractGetBinDataClass
|
4
9
|
|
5
|
-
from bs4 import BeautifulSoup
|
6
|
-
import urllib.parse
|
7
|
-
import requests
|
8
|
-
import re
|
9
|
-
|
10
10
|
|
11
11
|
class CouncilClass(AbstractGetBinDataClass):
|
12
12
|
def parse_data(self, page: str, **kwargs) -> dict:
|
13
13
|
|
14
14
|
data = {"bins": []}
|
15
15
|
|
16
|
+
headers = {
|
17
|
+
"Origin": "https://www.nuneatonandbedworth.gov.uk/",
|
18
|
+
"Referer": "https://www.nuneatonandbedworth.gov.uk/",
|
19
|
+
"User-Agent": "Mozilla/5.0",
|
20
|
+
}
|
21
|
+
|
16
22
|
street = urllib.parse.quote_plus(kwargs.get("paon"))
|
17
23
|
base_url = "https://www.nuneatonandbedworth.gov.uk/"
|
18
24
|
search_query = f"directory/search?directoryID=3&showInMap=&keywords={street}&search=Search+directory"
|
19
25
|
|
20
|
-
search_response = requests.get(base_url + search_query)
|
26
|
+
search_response = requests.get(base_url + search_query, headers=headers)
|
21
27
|
|
22
28
|
if search_response.status_code == 200:
|
23
29
|
soup = BeautifulSoup(search_response.content, "html.parser")
|
@@ -56,7 +62,13 @@ class CouncilClass(AbstractGetBinDataClass):
|
|
56
62
|
|
57
63
|
def get_bin_data(self, url) -> dict:
|
58
64
|
|
59
|
-
|
65
|
+
headers = {
|
66
|
+
"Origin": "https://www.nuneatonandbedworth.gov.uk/",
|
67
|
+
"Referer": "https://www.nuneatonandbedworth.gov.uk/",
|
68
|
+
"User-Agent": "Mozilla/5.0",
|
69
|
+
}
|
70
|
+
|
71
|
+
bin_day_response = requests.get(url, headers=headers)
|
60
72
|
|
61
73
|
if bin_day_response.status_code == 200:
|
62
74
|
|
@@ -21,10 +21,16 @@ class CouncilClass(AbstractGetBinDataClass):
|
|
21
21
|
check_uprn(user_uprn)
|
22
22
|
bindata = {"bins": []}
|
23
23
|
|
24
|
+
headers = {
|
25
|
+
"Origin": "https://www.runnymede.gov.uk",
|
26
|
+
"Referer": "https://www.runnymede.gov.uk",
|
27
|
+
"User-Agent": "Mozilla/5.0",
|
28
|
+
}
|
29
|
+
|
24
30
|
URI = f"https://www.runnymede.gov.uk/homepage/150/check-your-bin-collection-day?address={user_uprn}"
|
25
31
|
|
26
32
|
# Make the GET request
|
27
|
-
response = requests.get(URI)
|
33
|
+
response = requests.get(URI, headers=headers)
|
28
34
|
|
29
35
|
soup = BeautifulSoup(response.text, "html.parser")
|
30
36
|
|
@@ -77,6 +77,10 @@ class CouncilClass(AbstractGetBinDataClass):
|
|
77
77
|
)
|
78
78
|
submit.click()
|
79
79
|
|
80
|
+
WebDriverWait(driver, 10).until(
|
81
|
+
EC.presence_of_element_located((By.CLASS_NAME, "bin-collection__month"))
|
82
|
+
)
|
83
|
+
|
80
84
|
soup = BeautifulSoup(driver.page_source, features="html.parser")
|
81
85
|
|
82
86
|
# Quit Selenium webdriver to release session
|
@@ -1,3 +1,5 @@
|
|
1
|
+
import re
|
2
|
+
|
1
3
|
from bs4 import BeautifulSoup
|
2
4
|
|
3
5
|
from uk_bin_collection.uk_bin_collection.common import *
|
@@ -91,40 +93,56 @@ class CouncilClass(AbstractGetBinDataClass):
|
|
91
93
|
|
92
94
|
soup = BeautifulSoup(response.text, features="html.parser")
|
93
95
|
soup.prettify()
|
94
|
-
|
96
|
+
# print(soup)
|
95
97
|
# Find all the bits of the current calendar that contain an event
|
96
|
-
|
98
|
+
resultscontainer = soup.find_all("div", {"class": "results-container"})
|
97
99
|
|
98
|
-
for
|
99
|
-
|
100
|
-
|
101
|
-
event.find_next("a").attrs.get("data-original-datetext"),
|
102
|
-
"%A %d %B, %Y",
|
100
|
+
for result in resultscontainer:
|
101
|
+
rows = result.find_all(
|
102
|
+
"div", {"class": "col-12 col-sm-6 col-md-4 col-lg-4 mb-4"}
|
103
103
|
)
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
104
|
+
for row in rows:
|
105
|
+
cardcollectionday = row.find(
|
106
|
+
"span", {"class": "card-collection-day"}
|
107
|
+
)
|
108
|
+
cardcollectiondate = row.find(
|
109
|
+
"span", {"class": "card-collection-date"}
|
110
|
+
)
|
111
|
+
cardcollectionmonth = row.find(
|
112
|
+
"span", {"class": "card-collection-month"}
|
113
|
+
)
|
114
|
+
bin_type = row.find(
|
115
|
+
"li", {"class": re.compile(r"collection-type-...$")}
|
116
|
+
).text
|
117
|
+
|
118
|
+
collection_date = f"{cardcollectionday.text}{cardcollectiondate.text}{cardcollectionmonth.text}"
|
119
|
+
bin_date = datetime.strptime(
|
120
|
+
collection_date,
|
121
|
+
"%A %d %B %Y",
|
122
|
+
)
|
123
|
+
|
124
|
+
if bin_date.date() >= datetime.now().date():
|
125
|
+
# Split the really long type up into two separate bins
|
126
|
+
if (
|
127
|
+
bin_type
|
128
|
+
== "Mixed dry recycling (blue lidded bin) and glass (black box or basket)"
|
129
|
+
):
|
130
|
+
collections.append(
|
131
|
+
(
|
132
|
+
"Mixed dry recycling (blue lidded bin)",
|
133
|
+
datetime.strftime(bin_date, date_format),
|
134
|
+
)
|
135
|
+
)
|
136
|
+
collections.append(
|
137
|
+
(
|
138
|
+
"Glass (black box or basket)",
|
139
|
+
datetime.strftime(bin_date, date_format),
|
140
|
+
)
|
116
141
|
)
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
"Glass (black box or basket)",
|
121
|
-
datetime.strftime(bin_date, date_format),
|
142
|
+
else:
|
143
|
+
collections.append(
|
144
|
+
(bin_type, datetime.strftime(bin_date, date_format))
|
122
145
|
)
|
123
|
-
)
|
124
|
-
else:
|
125
|
-
collections.append(
|
126
|
-
(bin_type, datetime.strftime(bin_date, date_format))
|
127
|
-
)
|
128
146
|
|
129
147
|
data = {"bins": []}
|
130
148
|
|
@@ -7,7 +7,7 @@ uk_bin_collection/tests/council_feature_input_parity.py,sha256=DO6Mk4ImYgM5ZCZ-c
|
|
7
7
|
uk_bin_collection/tests/features/environment.py,sha256=VQZjJdJI_kZn08M0j5cUgvKT4k3iTw8icJge1DGOkoA,127
|
8
8
|
uk_bin_collection/tests/features/validate_council_outputs.feature,sha256=SJK-Vc737hrf03tssxxbeg_JIvAH-ddB8f6gU1LTbuQ,251
|
9
9
|
uk_bin_collection/tests/generate_map_test_results.py,sha256=CKnGK2ZgiSXomRGkomX90DitgMP-X7wkHhyKORDcL2E,1144
|
10
|
-
uk_bin_collection/tests/input.json,sha256=
|
10
|
+
uk_bin_collection/tests/input.json,sha256=Yc2-jsV8WUduGHCTWgUug9KYzIkGt5hrLlETgfgP-0w,132782
|
11
11
|
uk_bin_collection/tests/output.schema,sha256=ZwKQBwYyTDEM4G2hJwfLUVM-5v1vKRvRK9W9SS1sd18,1086
|
12
12
|
uk_bin_collection/tests/step_defs/step_helpers/file_handler.py,sha256=Ygzi4V0S1MIHqbdstUlIqtRIwnynvhu4UtpweJ6-5N8,1474
|
13
13
|
uk_bin_collection/tests/step_defs/test_validate_council.py,sha256=VZ0a81sioJULD7syAYHjvK_-nT_Rd36tUyzPetSA0gk,3475
|
@@ -46,7 +46,7 @@ uk_bin_collection/uk_bin_collection/councils/BlabyDistrictCouncil.py,sha256=MT1b
|
|
46
46
|
uk_bin_collection/uk_bin_collection/councils/BlackburnCouncil.py,sha256=ZLA2V3qPsJTom7SeQdGDhF4tJSfgIV5Qi202QvGKJZ0,4477
|
47
47
|
uk_bin_collection/uk_bin_collection/councils/BlaenauGwentCountyBoroughCouncil.py,sha256=Fp83gwF6RQieDgELpAdurjm6tDF4C6pBBukfPQSBHtc,6190
|
48
48
|
uk_bin_collection/uk_bin_collection/councils/BolsoverCouncil.py,sha256=_NZuSvSblS0NlxIhrzqbB9GNnY0xjT4SrIBi9bQ6UC8,10354
|
49
|
-
uk_bin_collection/uk_bin_collection/councils/BoltonCouncil.py,sha256=
|
49
|
+
uk_bin_collection/uk_bin_collection/councils/BoltonCouncil.py,sha256=wnw_q0A42SUJAdtzAWG2tga3p67egv5v1p2IY0oLPBk,4111
|
50
50
|
uk_bin_collection/uk_bin_collection/councils/BostonBoroughCouncil.py,sha256=8xv6FMNj8Qgwn5K0nMdB5X8hkcNFzhcJ48DMordflJY,5631
|
51
51
|
uk_bin_collection/uk_bin_collection/councils/BracknellForestCouncil.py,sha256=Llo1rULaAZ8rChVYZqXFFLo7CN6vbT0ULUJD6ActouY,9015
|
52
52
|
uk_bin_collection/uk_bin_collection/councils/BradfordMDC.py,sha256=qtCGHIwKDJQw0SNvQr0EZub21PFPDsdcxABOPv_MC6s,6114
|
@@ -60,7 +60,7 @@ uk_bin_collection/uk_bin_collection/councils/BromleyBoroughCouncil.py,sha256=dii
|
|
60
60
|
uk_bin_collection/uk_bin_collection/councils/BromsgroveDistrictCouncil.py,sha256=PUfxP8j5Oh9wFHkdjbrJzQli9UzMHZzwrZ2hkThrvhI,1781
|
61
61
|
uk_bin_collection/uk_bin_collection/councils/BroxbourneCouncil.py,sha256=GRneTbNNj0RPuzE7XdaWPBeEyek1hI6grAqV9ad1ck8,5030
|
62
62
|
uk_bin_collection/uk_bin_collection/councils/BroxtoweBoroughCouncil.py,sha256=-Facq-ToQkcWUePpKBwq90LZUFxgUSydNL2sYaLX4yw,4473
|
63
|
-
uk_bin_collection/uk_bin_collection/councils/BuckinghamshireCouncil.py,sha256=
|
63
|
+
uk_bin_collection/uk_bin_collection/councils/BuckinghamshireCouncil.py,sha256=qZk3tsDKp5EvER3JT4Mrq0wI5c3tPOrSZJntjCSB7_w,3419
|
64
64
|
uk_bin_collection/uk_bin_collection/councils/BurnleyBoroughCouncil.py,sha256=GJf1OPvUVj3vqsR3KjG0DFHZrSBu4ogIz_MJeVV8tNA,3192
|
65
65
|
uk_bin_collection/uk_bin_collection/councils/BuryCouncil.py,sha256=H7wAxO1nfxkewVoRRolumq8bBJG04siE3jieFH3RGpQ,2632
|
66
66
|
uk_bin_collection/uk_bin_collection/councils/CalderdaleCouncil.py,sha256=OJZcHYlvZDzmBpjjPPm3J8CRK9Twc49vRj7O9c5fyQ4,4971
|
@@ -106,7 +106,7 @@ uk_bin_collection/uk_bin_collection/councils/EalingCouncil.py,sha256=UhNXGi-_6NY
|
|
106
106
|
uk_bin_collection/uk_bin_collection/councils/EastAyrshireCouncil.py,sha256=i3AcWkeAnk7rD59nOm0QCSH7AggqjUAdwsXuSIC8ZJE,1614
|
107
107
|
uk_bin_collection/uk_bin_collection/councils/EastCambridgeshireCouncil.py,sha256=aYUVE5QqTxdj8FHhCB4EiFVDJahWJD9Pq0d1upBEvXg,1501
|
108
108
|
uk_bin_collection/uk_bin_collection/councils/EastDevonDC.py,sha256=5aZ4C2t-RBuygtqTRdcpGutjqJ2udrpKbW4F8RQ9r3M,3825
|
109
|
-
uk_bin_collection/uk_bin_collection/councils/EastHertsCouncil.py,sha256=
|
109
|
+
uk_bin_collection/uk_bin_collection/councils/EastHertsCouncil.py,sha256=enESYQCaqZ5miaHCmeQUWw3VIE5HfD8K7Oq8gxUVYDA,3901
|
110
110
|
uk_bin_collection/uk_bin_collection/councils/EastLindseyDistrictCouncil.py,sha256=Laf-j0LLr7M4xmKhk8kjPNTtt66oXKYWm0ppxdUX3F0,4326
|
111
111
|
uk_bin_collection/uk_bin_collection/councils/EastLothianCouncil.py,sha256=5IqDnO5dvnOMNb3gNP1xp14xdPwFG3mb7MBhnSq2npI,2882
|
112
112
|
uk_bin_collection/uk_bin_collection/councils/EastRenfrewshireCouncil.py,sha256=rWUQOWsiGIFffei5o-92jBHNhmcfyV72EnSy2Yd-B4c,4910
|
@@ -154,12 +154,12 @@ uk_bin_collection/uk_bin_collection/councils/HertsmereBoroughCouncil.py,sha256=Z
|
|
154
154
|
uk_bin_collection/uk_bin_collection/councils/HighPeakCouncil.py,sha256=x7dfy8mdt2iGl8qJxHb-uBh4u0knmi9MJ6irOJw9WYA,4805
|
155
155
|
uk_bin_collection/uk_bin_collection/councils/HighlandCouncil.py,sha256=GNxDU65QuZHV5va2IrKtcJ6TQoDdwmV03JvkVqOauP4,3291
|
156
156
|
uk_bin_collection/uk_bin_collection/councils/Hillingdon.py,sha256=2OUp0iYO1YeZuTq0XRUalgoay5JRZgfHKKEwYzdMAU0,11291
|
157
|
-
uk_bin_collection/uk_bin_collection/councils/HinckleyandBosworthBoroughCouncil.py,sha256=
|
157
|
+
uk_bin_collection/uk_bin_collection/councils/HinckleyandBosworthBoroughCouncil.py,sha256=v7s_Rp51IyXcj2MphGlECzaknPEl4lTzndgoc6m1sQg,2558
|
158
158
|
uk_bin_collection/uk_bin_collection/councils/HorshamDistrictCouncil.py,sha256=U8WelJiHivT7CS3meUVcLURWOLRKes1pKZ81tcqKarM,4446
|
159
159
|
uk_bin_collection/uk_bin_collection/councils/HullCityCouncil.py,sha256=UHcesBoctFVcXDYuwfag43KbcJcopkEDzJ-54NxtK0Q,1851
|
160
160
|
uk_bin_collection/uk_bin_collection/councils/HuntingdonDistrictCouncil.py,sha256=TXDIlVvYMwWECiXXBmzUjm36L5Pmn3GHciUuRaKmfF0,2059
|
161
161
|
uk_bin_collection/uk_bin_collection/councils/HyndburnBoroughCouncil.py,sha256=_lJ__EMcUBbE4QZvH-c1nCGeKxZTn5hhcpjVAYBbJZc,5403
|
162
|
-
uk_bin_collection/uk_bin_collection/councils/IpswichBoroughCouncil.py,sha256=
|
162
|
+
uk_bin_collection/uk_bin_collection/councils/IpswichBoroughCouncil.py,sha256=J9iQzZ4dc0VZhU_gTtMyiqpef6UYAPY_B7hQO5tY3Wg,2836
|
163
163
|
uk_bin_collection/uk_bin_collection/councils/IslingtonCouncil.py,sha256=xavzL6ZIU9DG8Xro3vN0CEnYmNU31OGnOvnq78wgpQc,1258
|
164
164
|
uk_bin_collection/uk_bin_collection/councils/KingsLynnandWestNorfolkBC.py,sha256=Shj18R-7NW4ivqJJFVJOLmf-EeN6hXP2Of30oI-SeAQ,1932
|
165
165
|
uk_bin_collection/uk_bin_collection/councils/KingstonUponThamesCouncil.py,sha256=8kKRhvdqs1hCymqmTtbi0FPJp2kd47JVmKTgRaWOGeY,3573
|
@@ -169,7 +169,7 @@ uk_bin_collection/uk_bin_collection/councils/LancasterCityCouncil.py,sha256=FmHT
|
|
169
169
|
uk_bin_collection/uk_bin_collection/councils/LeedsCityCouncil.py,sha256=VWdhw6qvCTj3EhFHf046xPWgc6szeFW2Xbt6W2J0e6w,4371
|
170
170
|
uk_bin_collection/uk_bin_collection/councils/LeicesterCityCouncil.py,sha256=o3kE8sjThQa4_AvSK5NH8VH7jWFO9MMPgoqLOTjyh0w,1851
|
171
171
|
uk_bin_collection/uk_bin_collection/councils/LewesDistrictCouncil.py,sha256=WZAxQ6TOGqQYYsRiL5SdzKdRA4k3GH5ygbKnau5KtDA,2658
|
172
|
-
uk_bin_collection/uk_bin_collection/councils/LichfieldDistrictCouncil.py,sha256=
|
172
|
+
uk_bin_collection/uk_bin_collection/councils/LichfieldDistrictCouncil.py,sha256=qO-z5nl2Deairo_afpcTyHr-fg_pqOGWyM516KjgUoU,2012
|
173
173
|
uk_bin_collection/uk_bin_collection/councils/LincolnCouncil.py,sha256=aUCqjHuk0sLtx83a-2agcLIMgEbfqjltXRCBRXT9J-8,3733
|
174
174
|
uk_bin_collection/uk_bin_collection/councils/LisburnCastlereaghCityCouncil.py,sha256=vSOzdEwp9ZeUhed7E3eVv9ReD-2XgbSkpyAbVnfc-Gk,3309
|
175
175
|
uk_bin_collection/uk_bin_collection/councils/LiverpoolCityCouncil.py,sha256=qo02eDHHSFSCN7xqKjLoKNZo-RjZPSUy3TVyJNpfg2Q,3069
|
@@ -212,7 +212,7 @@ uk_bin_collection/uk_bin_collection/councils/NewportCityCouncil.py,sha256=dAcl5P
|
|
212
212
|
uk_bin_collection/uk_bin_collection/councils/NorthAyrshireCouncil.py,sha256=o8zv40Wt19d51mrN5lsgLMCKMokMPmI1cMHBNT5yAho,1976
|
213
213
|
uk_bin_collection/uk_bin_collection/councils/NorthDevonCountyCouncil.py,sha256=tgJKIvu7nnCAHu_HImfG5SQABD6ygKFqrZU-ZoC6ObY,6260
|
214
214
|
uk_bin_collection/uk_bin_collection/councils/NorthEastDerbyshireDistrictCouncil.py,sha256=BfNpYcjG3z0Yz8OYN6NkfzvZ5k1FI-80D-rv211kPPU,5449
|
215
|
-
uk_bin_collection/uk_bin_collection/councils/NorthEastLincs.py,sha256=
|
215
|
+
uk_bin_collection/uk_bin_collection/councils/NorthEastLincs.py,sha256=GAAWNksi_-mLT8os7xE4K9_5X--WvVBPz5_a0h-4lgc,2097
|
216
216
|
uk_bin_collection/uk_bin_collection/councils/NorthHertfordshireDistrictCouncil.py,sha256=vwskZOfnUrSmKiezzt6TgP6_EIym0hDe-qaoLC9hWuU,12307
|
217
217
|
uk_bin_collection/uk_bin_collection/councils/NorthKestevenDistrictCouncil.py,sha256=vYOCerJXr9LTP6F2wm4vpYNYbQaWNZ6yfHEQ33N_hTw,1681
|
218
218
|
uk_bin_collection/uk_bin_collection/councils/NorthLanarkshireCouncil.py,sha256=npK1V8D3SLNTSSKkfEpEPvVgXDFyhH_tAsuGogsVKQY,1763
|
@@ -224,9 +224,9 @@ uk_bin_collection/uk_bin_collection/councils/NorthTynesideCouncil.py,sha256=yqyc
|
|
224
224
|
uk_bin_collection/uk_bin_collection/councils/NorthWestLeicestershire.py,sha256=gJj0dyQc5QUefqusKGk2LLXfWbG5tlEXUOh8KAPh3RI,4584
|
225
225
|
uk_bin_collection/uk_bin_collection/councils/NorthYorkshire.py,sha256=rwW6y5yhRiuYk3lVS7YFZxLaY_yfojdcn2dxiWaP4YA,2013
|
226
226
|
uk_bin_collection/uk_bin_collection/councils/NorthumberlandCouncil.py,sha256=7kCoBqLkt4UmLQNOnuC6jWrSgJLwavzgfJTR6EWINQU,6409
|
227
|
-
uk_bin_collection/uk_bin_collection/councils/NorwichCityCouncil.py,sha256=
|
227
|
+
uk_bin_collection/uk_bin_collection/councils/NorwichCityCouncil.py,sha256=mf2qB_YQlYUN_YLxC4JHNqpB3yAuUiFbVT1pFichZB4,2839
|
228
228
|
uk_bin_collection/uk_bin_collection/councils/NottinghamCityCouncil.py,sha256=panTCjnsBOQ98-TBO9xVZk_jcT_gjMhx3Gg5oWxBRLo,1254
|
229
|
-
uk_bin_collection/uk_bin_collection/councils/NuneatonBedworthBoroughCouncil.py,sha256=
|
229
|
+
uk_bin_collection/uk_bin_collection/councils/NuneatonBedworthBoroughCouncil.py,sha256=thcKPPUgSFrr2_an4jWsFzlwNzVCVvRLGNPK5jSXgd0,38192
|
230
230
|
uk_bin_collection/uk_bin_collection/councils/OadbyAndWigstonBoroughCouncil.py,sha256=Kgy5HA0xZ9hR4_cAydPfOfskhGUB4j93AQF2-9Fj-Cg,2179
|
231
231
|
uk_bin_collection/uk_bin_collection/councils/OldhamCouncil.py,sha256=9dlesCxNoVXlmQaqZj7QFh00smnJbm1Gnjkr_Uvzurs,1771
|
232
232
|
uk_bin_collection/uk_bin_collection/councils/OxfordCityCouncil.py,sha256=a6bPDZDh0RKcbyDoidI-PiIM5lw7Tr0AlApP4_hTbxQ,2419
|
@@ -249,7 +249,7 @@ uk_bin_collection/uk_bin_collection/councils/RotherDistrictCouncil.py,sha256=-fd
|
|
249
249
|
uk_bin_collection/uk_bin_collection/councils/RotherhamCouncil.py,sha256=dfAqXtmbptHGZGGWkurjY9snaVm1aH5CGjhzdtoe4JM,2058
|
250
250
|
uk_bin_collection/uk_bin_collection/councils/RoyalBoroughofGreenwich.py,sha256=AziuKhP6wKu_316MA4xXRN-ayDU6RSB21EfSWjmMqU8,3800
|
251
251
|
uk_bin_collection/uk_bin_collection/councils/RugbyBoroughCouncil.py,sha256=WlmOD-xHJFdowI9fGuGDHOpnAVHGUWxGZqmJ6z4fGXs,5687
|
252
|
-
uk_bin_collection/uk_bin_collection/councils/RunnymedeBoroughCouncil.py,sha256
|
252
|
+
uk_bin_collection/uk_bin_collection/councils/RunnymedeBoroughCouncil.py,sha256=-ZKQfpxviEcHM0j3QBGrKqJ-FbSouFHPuRnQSCoG5J0,1816
|
253
253
|
uk_bin_collection/uk_bin_collection/councils/RushcliffeBoroughCouncil.py,sha256=nWo8xeER71FEbnMTX8W9bcwZNpLEExWzPvgRT7DmcMc,4221
|
254
254
|
uk_bin_collection/uk_bin_collection/councils/RushmoorCouncil.py,sha256=ZsGnXjoEaOS6U7fI0w7-uqxayAHdNVKsJi2fqIWEls8,3375
|
255
255
|
uk_bin_collection/uk_bin_collection/councils/SalfordCityCouncil.py,sha256=XUGemp2cdzsvkWjnv2m4YKTMcoKDUfIlVy3YucX-_o4,2601
|
@@ -280,7 +280,7 @@ uk_bin_collection/uk_bin_collection/councils/SpelthorneBoroughCouncil.py,sha256=
|
|
280
280
|
uk_bin_collection/uk_bin_collection/councils/StAlbansCityAndDistrictCouncil.py,sha256=mPZz6Za6kTSkrfHnj0OfwtnpRYR1dKvxbuFEKnWsiL8,1451
|
281
281
|
uk_bin_collection/uk_bin_collection/councils/StHelensBC.py,sha256=X9dvnQTNn7QUO8gv1A587e1aDI92TWN4iNLATTn3H3w,4777
|
282
282
|
uk_bin_collection/uk_bin_collection/councils/StaffordBoroughCouncil.py,sha256=9Qj4HJI7Dbiqb2mVSG2UtkBe27Y7wvQ5SYFTwGzJ5g0,2292
|
283
|
-
uk_bin_collection/uk_bin_collection/councils/StaffordshireMoorlandsDistrictCouncil.py,sha256=
|
283
|
+
uk_bin_collection/uk_bin_collection/councils/StaffordshireMoorlandsDistrictCouncil.py,sha256=VrPoRr5bl8T7ZMPbYVHg-4tq9OCfW5dPe9uhKiRjm9o,4507
|
284
284
|
uk_bin_collection/uk_bin_collection/councils/StevenageBoroughCouncil.py,sha256=EiDIyOlHhdiJ-YYjo7T5uA5sN2jzNoysu6FctjuAjBI,3549
|
285
285
|
uk_bin_collection/uk_bin_collection/councils/StirlingCouncil.py,sha256=QaUw5oP_mmFAXo98EdHhI6lWo4OjF2E8zY2M7HQo2bk,6308
|
286
286
|
uk_bin_collection/uk_bin_collection/councils/StockportBoroughCouncil.py,sha256=v0HmioNVRoU1-9OnLJl2V3M5pVR1aVu1BgOLHFR1Sf4,1429
|
@@ -330,7 +330,7 @@ uk_bin_collection/uk_bin_collection/councils/WestNorthamptonshireCouncil.py,sha2
|
|
330
330
|
uk_bin_collection/uk_bin_collection/councils/WestOxfordshireDistrictCouncil.py,sha256=LLgpBE-yZFTpyZ5StGPVYtiBGxzttZt4f4YEqiYqocE,4858
|
331
331
|
uk_bin_collection/uk_bin_collection/councils/WestSuffolkCouncil.py,sha256=9i8AQHh-qIRPZ_5Ad97_h04-qgyLQDPV064obBzab1Y,2587
|
332
332
|
uk_bin_collection/uk_bin_collection/councils/WiganBoroughCouncil.py,sha256=W9FGN47bTHvzARa6UInXEB3X6cToqfgzTkNlROzHgcM,3743
|
333
|
-
uk_bin_collection/uk_bin_collection/councils/WiltshireCouncil.py,sha256=
|
333
|
+
uk_bin_collection/uk_bin_collection/councils/WiltshireCouncil.py,sha256=HjNy1a9-RokuGKEXcBW8bAwDlsf4C_KpudjzVJvrnsA,6458
|
334
334
|
uk_bin_collection/uk_bin_collection/councils/WinchesterCityCouncil.py,sha256=W2k00N5n9-1MzjMEqsNjldsQdOJPEPMjK7OGSinZm5Y,4335
|
335
335
|
uk_bin_collection/uk_bin_collection/councils/WindsorAndMaidenheadCouncil.py,sha256=VWtFgypXL1wKQ63NmV-_O9odOkbDmv3uCQwrv8g9lMI,2294
|
336
336
|
uk_bin_collection/uk_bin_collection/councils/WirralCouncil.py,sha256=X_e9zXEZAl_Mp6nPORHc9CTmf3QHdoMY3BCnKrXEr1I,2131
|
@@ -346,8 +346,8 @@ uk_bin_collection/uk_bin_collection/councils/YorkCouncil.py,sha256=I2kBYMlsD4bId
|
|
346
346
|
uk_bin_collection/uk_bin_collection/councils/council_class_template/councilclasstemplate.py,sha256=QD4v4xpsEE0QheR_fGaNOIRMc2FatcUfKkkhAhseyVU,1159
|
347
347
|
uk_bin_collection/uk_bin_collection/create_new_council.py,sha256=m-IhmWmeWQlFsTZC4OxuFvtw5ZtB8EAJHxJTH4O59lQ,1536
|
348
348
|
uk_bin_collection/uk_bin_collection/get_bin_data.py,sha256=Qb76X46V0UMZJwO8zMNPvnVY7jNa-bmTlrirDi1tuJA,4553
|
349
|
-
uk_bin_collection-0.
|
350
|
-
uk_bin_collection-0.
|
351
|
-
uk_bin_collection-0.
|
352
|
-
uk_bin_collection-0.
|
353
|
-
uk_bin_collection-0.
|
349
|
+
uk_bin_collection-0.153.0.dist-info/LICENSE,sha256=vABBUOzcrgfaTKpzeo-si9YVEun6juDkndqA8RKdKGs,1071
|
350
|
+
uk_bin_collection-0.153.0.dist-info/METADATA,sha256=YQIxmkkmazvaTXCHyd2xKgJqkCcAEuG7AUBjlWZeZlM,26688
|
351
|
+
uk_bin_collection-0.153.0.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
|
352
|
+
uk_bin_collection-0.153.0.dist-info/entry_points.txt,sha256=36WCSGMWSc916S3Hi1ZkazzDKHaJ6CD-4fCEFm5MIao,90
|
353
|
+
uk_bin_collection-0.153.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|
{uk_bin_collection-0.152.11.dist-info → uk_bin_collection-0.153.0.dist-info}/entry_points.txt
RENAMED
File without changes
|