uk_bin_collection 0.120.0__py3-none-any.whl → 0.121.1__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of uk_bin_collection might be problematic. Click here for more details.
- uk_bin_collection/tests/input.json +80 -7
- uk_bin_collection/uk_bin_collection/councils/CheltenhamBoroughCouncil.py +102 -0
- uk_bin_collection/uk_bin_collection/councils/CotswoldDistrictCouncil.py +3 -3
- uk_bin_collection/uk_bin_collection/councils/EastAyrshireCouncil.py +11 -8
- uk_bin_collection/uk_bin_collection/councils/FolkstoneandHytheDistrictCouncil.py +81 -0
- uk_bin_collection/uk_bin_collection/councils/HackneyCouncil.py +85 -0
- uk_bin_collection/uk_bin_collection/councils/KingsLynnandWestNorfolkBC.py +59 -0
- uk_bin_collection/uk_bin_collection/councils/LondonBoroughLewisham.py +140 -0
- uk_bin_collection/uk_bin_collection/councils/MorayCouncil.py +65 -0
- uk_bin_collection/uk_bin_collection/councils/RoyalBoroughofGreenwich.py +113 -0
- uk_bin_collection/uk_bin_collection/councils/SandwellBoroughCouncil.py +87 -0
- uk_bin_collection/uk_bin_collection/councils/ThurrockCouncil.py +93 -0
- uk_bin_collection/uk_bin_collection/councils/WestNorthamptonshireCouncil.py +12 -10
- uk_bin_collection/uk_bin_collection/councils/WyreForestDistrictCouncil.py +65 -0
- {uk_bin_collection-0.120.0.dist-info → uk_bin_collection-0.121.1.dist-info}/METADATA +1 -1
- {uk_bin_collection-0.120.0.dist-info → uk_bin_collection-0.121.1.dist-info}/RECORD +19 -9
- {uk_bin_collection-0.120.0.dist-info → uk_bin_collection-0.121.1.dist-info}/LICENSE +0 -0
- {uk_bin_collection-0.120.0.dist-info → uk_bin_collection-0.121.1.dist-info}/WHEEL +0 -0
- {uk_bin_collection-0.120.0.dist-info → uk_bin_collection-0.121.1.dist-info}/entry_points.txt +0 -0
@@ -364,6 +364,14 @@
|
|
364
364
|
"wiki_name": "Chelmsford City Council",
|
365
365
|
"wiki_note": "Follow the instructions [here](https://www.chelmsford.gov.uk/myhome/) until you get the page listing your address, then copy the entire address text and use that in the house number field."
|
366
366
|
},
|
367
|
+
"CheltenhamBoroughCouncil": {
|
368
|
+
"skip_get_url": true,
|
369
|
+
"house_number": "Monday",
|
370
|
+
"postcode": "Week 1",
|
371
|
+
"url": "https://www.cheltenham.gov.uk",
|
372
|
+
"wiki_name": "Cheltenham Borough Council",
|
373
|
+
"wiki_note": "Use the House Number field to pass the DAY of the week for your collections. [Monday/Tuesday/Wednesday/Thursday/Friday]. Use the 'postcode' field to pass the WEEK (wrapped in quotes) for your collections. [Week 1/Week 2]."
|
374
|
+
},
|
367
375
|
"CheshireEastCouncil": {
|
368
376
|
"url": "https://online.cheshireeast.gov.uk/MyCollectionDay/SearchByAjax/GetBartecJobList?uprn=100012791226&onelineaddress=3%20COBBLERS%20YARD,%20SK9%207DZ&_=1689413260149",
|
369
377
|
"wiki_command_url_override": "https://online.cheshireeast.gov.uk/MyCollectionDay/SearchByAjax/GetBartecJobList?uprn=XXXXXXXX&onelineaddress=XXXXXXXX&_=1689413260149",
|
@@ -723,6 +731,13 @@
|
|
723
731
|
"wiki_name": "Flintshire County Council",
|
724
732
|
"wiki_note": "You will need to use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find the UPRN."
|
725
733
|
},
|
734
|
+
"FolkstoneandHytheDistrictCouncil": {
|
735
|
+
"skip_get_url": true,
|
736
|
+
"uprn": "50032097",
|
737
|
+
"url": "https://www.folkestone-hythe.gov.uk",
|
738
|
+
"wiki_name": "Folkstone and Hythe District Council",
|
739
|
+
"wiki_note": "Use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find your UPRN."
|
740
|
+
},
|
726
741
|
"ForestOfDeanDistrictCouncil": {
|
727
742
|
"house_number": "ELMOGAL, PARKEND ROAD, BREAM, LYDNEY",
|
728
743
|
"postcode": "GL15 6JT",
|
@@ -781,6 +796,13 @@
|
|
781
796
|
"wiki_name": "Guildford Council",
|
782
797
|
"wiki_note": "If the bin day is 'today' then the collectionDate will only show today's date if before 7 AM; else the date will be in 'previousCollectionDate'. To get the UPRN, you will need to use [FindMyAddress](https://www.findmyaddress.co.uk/search)."
|
783
798
|
},
|
799
|
+
"HackneyCouncil": {
|
800
|
+
"house_number": "101",
|
801
|
+
"postcode": "N16 9AS",
|
802
|
+
"url": "https://www.hackney.gov.uk",
|
803
|
+
"wiki_name": "Hackney Council",
|
804
|
+
"wiki_note": "Pass the postcode and house number in their respective arguments, both wrapped in quotes."
|
805
|
+
},
|
784
806
|
"HaltonBoroughCouncil": {
|
785
807
|
"house_number": "12",
|
786
808
|
"postcode": "WA7 4HA",
|
@@ -879,6 +901,12 @@
|
|
879
901
|
"wiki_name": "Islington Council",
|
880
902
|
"wiki_note": "Replace XXXXXXXX with your UPRN."
|
881
903
|
},
|
904
|
+
"KingsLynnandWestNorfolkBC": {
|
905
|
+
"uprn": "10023636886",
|
906
|
+
"url": "https://www.west-norfolk.gov.uk/",
|
907
|
+
"wiki_name": "Kings Lynn and West Norfolk Borough Council",
|
908
|
+
"wiki_note": "Provide your UPRN. Find your UPRN using [FindMyAddress](https://www.findmyaddress.co.uk/search)."
|
909
|
+
},
|
882
910
|
"KingstonUponThamesCouncil": {
|
883
911
|
"url": "https://waste-services.kingston.gov.uk/waste/2701097",
|
884
912
|
"wiki_command_url_override": "https://waste-services.kingston.gov.uk/waste/XXXXXXX",
|
@@ -984,6 +1012,15 @@
|
|
984
1012
|
"wiki_name": "London Borough Lambeth",
|
985
1013
|
"wiki_note": "Pass the UPRN. You can find it using [FindMyAddress](https://www.findmyaddress.co.uk/search)."
|
986
1014
|
},
|
1015
|
+
"LondonBoroughLewisham": {
|
1016
|
+
"postcode": "SE12 9QF",
|
1017
|
+
"skip_get_url": true,
|
1018
|
+
"uprn": "100021954849",
|
1019
|
+
"url": "https://www.lewisham.gov.uk",
|
1020
|
+
"web_driver": "http://selenium:4444",
|
1021
|
+
"wiki_name": "London Borough Lewisham",
|
1022
|
+
"wiki_note": "Pass the UPRN and postcode. To get the UPRN, you can use [FindMyAddress](https://www.findmyaddress.co.uk/search)."
|
1023
|
+
},
|
987
1024
|
"LondonBoroughRedbridge": {
|
988
1025
|
"postcode": "IG2 6LQ",
|
989
1026
|
"uprn": "10023770353",
|
@@ -1095,6 +1132,12 @@
|
|
1095
1132
|
"wiki_name": "Mole Valley District Council",
|
1096
1133
|
"wiki_note": "UPRN can only be parsed with a valid postcode."
|
1097
1134
|
},
|
1135
|
+
"MorayCouncil": {
|
1136
|
+
"uprn": "28841",
|
1137
|
+
"url": "https://bindayfinder.moray.gov.uk/",
|
1138
|
+
"wiki_name": "Moray Council",
|
1139
|
+
"wiki_note": "Find your property ID by going to (https://bindayfinder.moray.gov.uk), search for your property and extracting the ID from the URL. i.e. (https://bindayfinder.moray.gov.uk/disp_bins.php?id=00028841)"
|
1140
|
+
},
|
1098
1141
|
"NeathPortTalbotCouncil": {
|
1099
1142
|
"house_number": "2",
|
1100
1143
|
"postcode": "SA13 3BA",
|
@@ -1392,6 +1435,14 @@
|
|
1392
1435
|
"wiki_command_url_override": "https://www.rotherham.gov.uk/bin-collections?address=XXXXXXXXX&submit=Submit",
|
1393
1436
|
"wiki_note": "Replace `XXXXXXXXX` with your UPRN in the URL. You can find your UPRN using [FindMyAddress](https://www.findmyaddress.co.uk/search)."
|
1394
1437
|
},
|
1438
|
+
"RoyalBoroughofGreenwich": {
|
1439
|
+
"house_number": "57",
|
1440
|
+
"postcode": "BR7 6DN",
|
1441
|
+
"skip_get_url": true,
|
1442
|
+
"url": "https://www.royalgreenwich.gov.uk",
|
1443
|
+
"wiki_name": "Royal Borough of Greenwich",
|
1444
|
+
"wiki_note": "Provide your house number in the `house_number` parameter and your postcode in the `postcode` parameter."
|
1445
|
+
},
|
1395
1446
|
"RugbyBoroughCouncil": {
|
1396
1447
|
"postcode": "CV22 6LA",
|
1397
1448
|
"skip_get_url": true,
|
@@ -1422,6 +1473,13 @@
|
|
1422
1473
|
"wiki_name": "Salford City Council",
|
1423
1474
|
"wiki_note": "Provide your UPRN. You can find it using [FindMyAddress](https://www.findmyaddress.co.uk/search)."
|
1424
1475
|
},
|
1476
|
+
"SandwellBoroughCouncil": {
|
1477
|
+
"uprn": "10008755549",
|
1478
|
+
"skip_get_url": true,
|
1479
|
+
"url": "https://www.sandwell.gov.uk",
|
1480
|
+
"wiki_name": "Sandwell Borough Council",
|
1481
|
+
"wiki_note": "Pass the UPRN. You will need to use [FindMyAddress](https://www.findmyaddress.co.uk/search)."
|
1482
|
+
},
|
1425
1483
|
"SeftonCouncil": {
|
1426
1484
|
"house_number": "1",
|
1427
1485
|
"postcode": "L20 6GG",
|
@@ -1537,10 +1595,10 @@
|
|
1537
1595
|
"wiki_note": "You will need to use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find your UPRN."
|
1538
1596
|
},
|
1539
1597
|
"SouthStaffordshireDistrictCouncil": {
|
1540
|
-
|
1541
|
-
|
1542
|
-
|
1543
|
-
|
1598
|
+
"uprn": "200004523954",
|
1599
|
+
"url": "https://www.sstaffs.gov.uk/where-i-live?uprn=200004523954",
|
1600
|
+
"wiki_name": "South Staffordshire District Council",
|
1601
|
+
"wiki_note": "The URL needs to be `https://www.sstaffs.gov.uk/where-i-live?uprn=<Your_UPRN>`. Replace `<Your_UPRN>` with your UPRN."
|
1544
1602
|
},
|
1545
1603
|
"SouthTynesideCouncil": {
|
1546
1604
|
"house_number": "1",
|
@@ -1739,6 +1797,14 @@
|
|
1739
1797
|
"wiki_name": "Three Rivers District Council",
|
1740
1798
|
"wiki_note": "Provide your UPRN and postcode. Find your UPRN using [FindMyAddress](https://www.findmyaddress.co.uk/search)."
|
1741
1799
|
},
|
1800
|
+
"ThurrockCouncil": {
|
1801
|
+
"skip_get_url": true,
|
1802
|
+
"house_number": "Monday",
|
1803
|
+
"postcode": "Round A",
|
1804
|
+
"url": "https://www.thurrock.gov.uk",
|
1805
|
+
"wiki_name": "Thurrock Council",
|
1806
|
+
"wiki_note": "Use the House Number field to pass the DAY of the week for your collections. [Monday/Tuesday/Wednesday/Thursday/Friday]. Use the 'postcode' field to pass the ROUND (wrapped in quotes) for your collections. [Round A/Round B]."
|
1807
|
+
},
|
1742
1808
|
"TonbridgeAndMallingBC": {
|
1743
1809
|
"postcode": "ME19 4JS",
|
1744
1810
|
"skip_get_url": true,
|
@@ -1909,11 +1975,11 @@
|
|
1909
1975
|
"wiki_note": "Provide your UPRN. You can find your UPRN using [FindMyAddress](https://www.findmyaddress.co.uk/search)."
|
1910
1976
|
},
|
1911
1977
|
"WestNorthamptonshireCouncil": {
|
1912
|
-
"
|
1978
|
+
"uprn": "28056796",
|
1913
1979
|
"skip_get_url": true,
|
1914
|
-
"url": "https://www.
|
1980
|
+
"url": "https://www.westnorthants.gov.uk",
|
1915
1981
|
"wiki_name": "West Northamptonshire Council",
|
1916
|
-
"wiki_note": "Provide your
|
1982
|
+
"wiki_note": "Provide your UPRN. You can find your UPRN using [FindMyAddress](https://www.findmyaddress.co.uk/search)."
|
1917
1983
|
},
|
1918
1984
|
"WestOxfordshireDistrictCouncil": {
|
1919
1985
|
"house_number": "24",
|
@@ -2028,6 +2094,13 @@
|
|
2028
2094
|
"wiki_name": "Wyre Council",
|
2029
2095
|
"wiki_note": "Provide your UPRN and postcode. Find your UPRN using [FindMyAddress](https://www.findmyaddress.co.uk/search). The postcode should be wrapped in double quotes with a space in the middle."
|
2030
2096
|
},
|
2097
|
+
"WyreForestDistrictCouncil": {
|
2098
|
+
"skip_get_url": true,
|
2099
|
+
"house_number": "Monday",
|
2100
|
+
"url": "https://www.wyreforestdc.gov.uk",
|
2101
|
+
"wiki_name": "Wyre Forest District Council",
|
2102
|
+
"wiki_note": "Use the House Number field to pass the DAY of the week for your collections. [Monday/Tuesday/Wednesday/Thursday/Friday/Saturday/Sunday]."
|
2103
|
+
},
|
2031
2104
|
"YorkCouncil": {
|
2032
2105
|
"skip_get_url": true,
|
2033
2106
|
"uprn": "100050535540",
|
@@ -0,0 +1,102 @@
|
|
1
|
+
import re
|
2
|
+
import time
|
3
|
+
|
4
|
+
import requests
|
5
|
+
from bs4 import BeautifulSoup
|
6
|
+
from selenium.webdriver.common.by import By
|
7
|
+
from selenium.webdriver.support import expected_conditions as EC
|
8
|
+
from selenium.webdriver.support.ui import Select
|
9
|
+
from selenium.webdriver.support.wait import WebDriverWait
|
10
|
+
|
11
|
+
from uk_bin_collection.uk_bin_collection.common import *
|
12
|
+
from uk_bin_collection.uk_bin_collection.get_bin_data import AbstractGetBinDataClass
|
13
|
+
|
14
|
+
|
15
|
+
# import the wonderful Beautiful Soup and the URL grabber
|
16
|
+
class CouncilClass(AbstractGetBinDataClass):
|
17
|
+
"""
|
18
|
+
Concrete classes have to implement all abstract operations of the
|
19
|
+
base class. They can also override some operations with a default
|
20
|
+
implementation.
|
21
|
+
"""
|
22
|
+
|
23
|
+
def parse_data(self, page: str, **kwargs) -> dict:
|
24
|
+
|
25
|
+
collection_day = kwargs.get("paon")
|
26
|
+
collection_week = kwargs.get("postcode")
|
27
|
+
bindata = {"bins": []}
|
28
|
+
|
29
|
+
days_of_week = [
|
30
|
+
"Monday",
|
31
|
+
"Tuesday",
|
32
|
+
"Wednesday",
|
33
|
+
"Thursday",
|
34
|
+
"Friday",
|
35
|
+
"Saturday",
|
36
|
+
"Sunday",
|
37
|
+
]
|
38
|
+
|
39
|
+
week = ["Week 1", "Week 2"]
|
40
|
+
|
41
|
+
offset_days = days_of_week.index(collection_day)
|
42
|
+
collection_week = week.index(collection_week)
|
43
|
+
|
44
|
+
if collection_week == 0:
|
45
|
+
refusestartDate = datetime(2024, 11, 25)
|
46
|
+
recyclingstartDate = datetime(2024, 11, 18)
|
47
|
+
else:
|
48
|
+
refusestartDate = datetime(2024, 11, 18)
|
49
|
+
recyclingstartDate = datetime(2024, 11, 25)
|
50
|
+
|
51
|
+
refuse_dates = get_dates_every_x_days(refusestartDate, 14, 28)
|
52
|
+
recycling_dates = get_dates_every_x_days(recyclingstartDate, 14, 28)
|
53
|
+
food_dates = get_dates_every_x_days(recyclingstartDate, 7, 56)
|
54
|
+
|
55
|
+
for refuseDate in refuse_dates:
|
56
|
+
|
57
|
+
collection_date = (
|
58
|
+
datetime.strptime(refuseDate, "%d/%m/%Y") + timedelta(days=offset_days)
|
59
|
+
).strftime("%d/%m/%Y")
|
60
|
+
|
61
|
+
dict_data = {
|
62
|
+
"type": "Refuse Bin",
|
63
|
+
"collectionDate": collection_date,
|
64
|
+
}
|
65
|
+
bindata["bins"].append(dict_data)
|
66
|
+
|
67
|
+
for recyclingDate in recycling_dates:
|
68
|
+
|
69
|
+
collection_date = (
|
70
|
+
datetime.strptime(recyclingDate, "%d/%m/%Y")
|
71
|
+
+ timedelta(days=offset_days)
|
72
|
+
).strftime("%d/%m/%Y")
|
73
|
+
|
74
|
+
dict_data = {
|
75
|
+
"type": "Recycling Bin",
|
76
|
+
"collectionDate": collection_date,
|
77
|
+
}
|
78
|
+
bindata["bins"].append(dict_data)
|
79
|
+
|
80
|
+
dict_data = {
|
81
|
+
"type": "Garden Waste Bin",
|
82
|
+
"collectionDate": collection_date,
|
83
|
+
}
|
84
|
+
bindata["bins"].append(dict_data)
|
85
|
+
|
86
|
+
for food_date in food_dates:
|
87
|
+
|
88
|
+
collection_date = (
|
89
|
+
datetime.strptime(food_date, "%d/%m/%Y") + timedelta(days=offset_days)
|
90
|
+
).strftime("%d/%m/%Y")
|
91
|
+
|
92
|
+
dict_data = {
|
93
|
+
"type": "Food Waste Bin",
|
94
|
+
"collectionDate": collection_date,
|
95
|
+
}
|
96
|
+
bindata["bins"].append(dict_data)
|
97
|
+
|
98
|
+
bindata["bins"].sort(
|
99
|
+
key=lambda x: datetime.strptime(x.get("collectionDate"), "%d/%m/%Y")
|
100
|
+
)
|
101
|
+
|
102
|
+
return bindata
|
@@ -42,14 +42,14 @@ class CouncilClass(AbstractGetBinDataClass):
|
|
42
42
|
wait = WebDriverWait(driver, 60)
|
43
43
|
address_entry_field = wait.until(
|
44
44
|
EC.presence_of_element_located(
|
45
|
-
(By.XPATH, '//*[@id="combobox-input-
|
45
|
+
(By.XPATH, '//*[@id="combobox-input-20"]')
|
46
46
|
)
|
47
47
|
)
|
48
48
|
|
49
49
|
address_entry_field.send_keys(str(full_address))
|
50
50
|
|
51
51
|
address_entry_field = wait.until(
|
52
|
-
EC.element_to_be_clickable((By.XPATH, '//*[@id="combobox-input-
|
52
|
+
EC.element_to_be_clickable((By.XPATH, '//*[@id="combobox-input-20"]'))
|
53
53
|
)
|
54
54
|
address_entry_field.click()
|
55
55
|
address_entry_field.send_keys(Keys.BACKSPACE)
|
@@ -57,7 +57,7 @@ class CouncilClass(AbstractGetBinDataClass):
|
|
57
57
|
|
58
58
|
first_found_address = wait.until(
|
59
59
|
EC.element_to_be_clickable(
|
60
|
-
(By.XPATH, '//*[@id="dropdown-element-
|
60
|
+
(By.XPATH, '//*[@id="dropdown-element-20"]/ul')
|
61
61
|
)
|
62
62
|
)
|
63
63
|
|
@@ -30,14 +30,17 @@ class CouncilClass(AbstractGetBinDataClass):
|
|
30
30
|
# Find each <time> element in the schedule
|
31
31
|
for entry in soup.find_all("time"):
|
32
32
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
"
|
38
|
-
|
39
|
-
|
40
|
-
|
33
|
+
ScheduleItems = entry.find_all(class_="ScheduleItem")
|
34
|
+
|
35
|
+
for ScheduleItem in ScheduleItems:
|
36
|
+
dict_data = {
|
37
|
+
"type": ScheduleItem.text.strip(),
|
38
|
+
"collectionDate": datetime.strptime(
|
39
|
+
entry["datetime"],
|
40
|
+
"%Y-%m-%d",
|
41
|
+
).strftime("%d/%m/%Y"),
|
42
|
+
}
|
43
|
+
bindata["bins"].append(dict_data)
|
41
44
|
|
42
45
|
bindata["bins"].sort(
|
43
46
|
key=lambda x: datetime.strptime(x.get("collectionDate"), "%d/%m/%Y")
|
@@ -0,0 +1,81 @@
|
|
1
|
+
import requests
|
2
|
+
from bs4 import BeautifulSoup
|
3
|
+
|
4
|
+
from uk_bin_collection.uk_bin_collection.common import *
|
5
|
+
from uk_bin_collection.uk_bin_collection.get_bin_data import AbstractGetBinDataClass
|
6
|
+
|
7
|
+
|
8
|
+
# import the wonderful Beautiful Soup and the URL grabber
|
9
|
+
class CouncilClass(AbstractGetBinDataClass):
|
10
|
+
"""
|
11
|
+
Concrete classes have to implement all abstract operations of the
|
12
|
+
base class. They can also override some operations with a default
|
13
|
+
implementation.
|
14
|
+
"""
|
15
|
+
|
16
|
+
def parse_data(self, page: str, **kwargs) -> dict:
|
17
|
+
|
18
|
+
user_uprn = kwargs.get("uprn")
|
19
|
+
check_uprn(user_uprn)
|
20
|
+
bindata = {"bins": []}
|
21
|
+
|
22
|
+
URI = f"https://service.folkestone-hythe.gov.uk/webapp/myarea/index.php?uprn={user_uprn}"
|
23
|
+
|
24
|
+
# Make the GET request
|
25
|
+
response = requests.get(URI)
|
26
|
+
|
27
|
+
soup = BeautifulSoup(response.content, "html.parser")
|
28
|
+
|
29
|
+
soup = soup.find("div", {"id": "bincollections"})
|
30
|
+
|
31
|
+
# Find the Recycling and Non-Recyclables sections
|
32
|
+
bin_schedule = {}
|
33
|
+
|
34
|
+
# Extract the recycling schedule
|
35
|
+
recycling_section = soup.find("span", text=lambda x: x and "Recycling" in x)
|
36
|
+
if recycling_section:
|
37
|
+
bin_types = recycling_section.text.replace("Recycling: ", "").split(" / ")
|
38
|
+
recycling_dates = recycling_section.find_next("ul").find_all("li")
|
39
|
+
bin_schedule["Recycling"] = [date.text.strip() for date in recycling_dates]
|
40
|
+
for date in recycling_dates:
|
41
|
+
for bin_type in bin_types:
|
42
|
+
dict_data = {
|
43
|
+
"type": bin_type.strip(),
|
44
|
+
"collectionDate": datetime.strptime(
|
45
|
+
remove_ordinal_indicator_from_date_string(
|
46
|
+
date.text.strip()
|
47
|
+
),
|
48
|
+
"%A %d %B %Y",
|
49
|
+
).strftime("%d/%m/%Y"),
|
50
|
+
}
|
51
|
+
bindata["bins"].append(dict_data)
|
52
|
+
|
53
|
+
# Extract the non-recyclables schedule
|
54
|
+
non_recyclables_section = soup.find(
|
55
|
+
"span", text=lambda x: x and "Non-Recyclables" in x
|
56
|
+
)
|
57
|
+
if non_recyclables_section:
|
58
|
+
bin_types = non_recyclables_section.text.replace(
|
59
|
+
"Non-Recyclables: ", ""
|
60
|
+
).split(" / ")
|
61
|
+
non_recyclables_dates = non_recyclables_section.find_next("ul").find_all(
|
62
|
+
"li"
|
63
|
+
)
|
64
|
+
for date in non_recyclables_dates:
|
65
|
+
for bin_type in bin_types:
|
66
|
+
dict_data = {
|
67
|
+
"type": bin_type.strip(),
|
68
|
+
"collectionDate": datetime.strptime(
|
69
|
+
remove_ordinal_indicator_from_date_string(
|
70
|
+
date.text.strip()
|
71
|
+
),
|
72
|
+
"%A %d %B %Y",
|
73
|
+
).strftime("%d/%m/%Y"),
|
74
|
+
}
|
75
|
+
bindata["bins"].append(dict_data)
|
76
|
+
|
77
|
+
bindata["bins"].sort(
|
78
|
+
key=lambda x: datetime.strptime(x.get("collectionDate"), "%d/%m/%Y")
|
79
|
+
)
|
80
|
+
|
81
|
+
return bindata
|
@@ -0,0 +1,85 @@
|
|
1
|
+
import time
|
2
|
+
|
3
|
+
import requests
|
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
|
+
|
19
|
+
user_paon = kwargs.get("paon")
|
20
|
+
user_postcode = kwargs.get("postcode")
|
21
|
+
check_postcode(user_postcode)
|
22
|
+
check_paon(user_paon)
|
23
|
+
bindata = {"bins": []}
|
24
|
+
|
25
|
+
URI = "https://waste-api-hackney-live.ieg4.net/f806d91c-e133-43a6-ba9a-c0ae4f4cccf6/property/opensearch"
|
26
|
+
|
27
|
+
data = {
|
28
|
+
"Postcode": user_postcode,
|
29
|
+
}
|
30
|
+
headers = {"Content-Type": "application/json"}
|
31
|
+
|
32
|
+
# Make the GET request
|
33
|
+
response = requests.post(URI, json=data, headers=headers)
|
34
|
+
|
35
|
+
addresses = response.json()
|
36
|
+
|
37
|
+
for address in addresses["addressSummaries"]:
|
38
|
+
summary = address["summary"]
|
39
|
+
if user_paon in summary:
|
40
|
+
systemId = address["systemId"]
|
41
|
+
if systemId:
|
42
|
+
URI = f"https://waste-api-hackney-live.ieg4.net/f806d91c-e133-43a6-ba9a-c0ae4f4cccf6/alloywastepages/getproperty/{systemId}"
|
43
|
+
|
44
|
+
response = requests.get(URI)
|
45
|
+
|
46
|
+
address = response.json()
|
47
|
+
|
48
|
+
binIDs = address["providerSpecificFields"][
|
49
|
+
"attributes_wasteContainersAssignableWasteContainers"
|
50
|
+
]
|
51
|
+
for binID in binIDs.split(","):
|
52
|
+
URI = f"https://waste-api-hackney-live.ieg4.net/f806d91c-e133-43a6-ba9a-c0ae4f4cccf6/alloywastepages/getbin/{binID}"
|
53
|
+
response = requests.get(URI)
|
54
|
+
getBin = response.json()
|
55
|
+
|
56
|
+
bin_type = getBin["subTitle"]
|
57
|
+
|
58
|
+
URI = f"https://waste-api-hackney-live.ieg4.net/f806d91c-e133-43a6-ba9a-c0ae4f4cccf6/alloywastepages/getcollection/{binID}"
|
59
|
+
response = requests.get(URI)
|
60
|
+
getcollection = response.json()
|
61
|
+
|
62
|
+
collectionID = getcollection["scheduleCodeWorkflowID"]
|
63
|
+
|
64
|
+
URI = f"https://waste-api-hackney-live.ieg4.net/f806d91c-e133-43a6-ba9a-c0ae4f4cccf6/alloywastepages/getworkflow/{collectionID}"
|
65
|
+
response = requests.get(URI)
|
66
|
+
collection_dates = response.json()
|
67
|
+
|
68
|
+
dates = collection_dates["trigger"]["dates"]
|
69
|
+
|
70
|
+
for date in dates:
|
71
|
+
parsed_datetime = datetime.strptime(
|
72
|
+
date, "%Y-%m-%dT%H:%M:%SZ"
|
73
|
+
).strftime(date_format)
|
74
|
+
|
75
|
+
dict_data = {
|
76
|
+
"type": bin_type.strip(),
|
77
|
+
"collectionDate": parsed_datetime,
|
78
|
+
}
|
79
|
+
bindata["bins"].append(dict_data)
|
80
|
+
|
81
|
+
bindata["bins"].sort(
|
82
|
+
key=lambda x: datetime.strptime(x.get("collectionDate"), "%d/%m/%Y")
|
83
|
+
)
|
84
|
+
|
85
|
+
return bindata
|
@@ -0,0 +1,59 @@
|
|
1
|
+
import requests
|
2
|
+
from bs4 import BeautifulSoup
|
3
|
+
|
4
|
+
from uk_bin_collection.uk_bin_collection.common import *
|
5
|
+
from uk_bin_collection.uk_bin_collection.get_bin_data import AbstractGetBinDataClass
|
6
|
+
|
7
|
+
|
8
|
+
# import the wonderful Beautiful Soup and the URL grabber
|
9
|
+
class CouncilClass(AbstractGetBinDataClass):
|
10
|
+
"""
|
11
|
+
Concrete classes have to implement all abstract operations of the
|
12
|
+
base class. They can also override some operations with a default
|
13
|
+
implementation.
|
14
|
+
"""
|
15
|
+
|
16
|
+
def parse_data(self, page: str, **kwargs) -> dict:
|
17
|
+
|
18
|
+
user_uprn = kwargs.get("uprn")
|
19
|
+
check_uprn(user_uprn)
|
20
|
+
user_uprn = user_uprn.zfill(12)
|
21
|
+
bindata = {"bins": []}
|
22
|
+
|
23
|
+
URI = "https://www.west-norfolk.gov.uk/info/20174/bins_and_recycling_collection_dates"
|
24
|
+
|
25
|
+
headers = {"Cookie": f"bcklwn_uprn={user_uprn}"}
|
26
|
+
|
27
|
+
# Make the GET request
|
28
|
+
response = requests.get(URI, headers=headers)
|
29
|
+
|
30
|
+
soup = BeautifulSoup(response.content, features="html.parser")
|
31
|
+
soup.prettify()
|
32
|
+
|
33
|
+
# Find all bin_date_container divs
|
34
|
+
bin_date_containers = soup.find_all("div", class_="bin_date_container")
|
35
|
+
|
36
|
+
# Loop through each bin_date_container
|
37
|
+
for container in bin_date_containers:
|
38
|
+
# Extract the collection date
|
39
|
+
date = (
|
40
|
+
container.find("h3", class_="collectiondate").text.strip().rstrip(":")
|
41
|
+
)
|
42
|
+
|
43
|
+
# Extract the bin type from the alt attribute of the img tag
|
44
|
+
bin_type = container.find("img")["alt"]
|
45
|
+
|
46
|
+
dict_data = {
|
47
|
+
"type": bin_type,
|
48
|
+
"collectionDate": datetime.strptime(
|
49
|
+
date,
|
50
|
+
"%A %d %B %Y",
|
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
|
+
)
|
58
|
+
|
59
|
+
return bindata
|
@@ -0,0 +1,140 @@
|
|
1
|
+
import re
|
2
|
+
import time
|
3
|
+
|
4
|
+
from bs4 import BeautifulSoup
|
5
|
+
from selenium.webdriver.common.by import By
|
6
|
+
from selenium.webdriver.support import expected_conditions as EC
|
7
|
+
from selenium.webdriver.support.ui import Select, WebDriverWait
|
8
|
+
|
9
|
+
from uk_bin_collection.uk_bin_collection.common import *
|
10
|
+
from uk_bin_collection.uk_bin_collection.get_bin_data import AbstractGetBinDataClass
|
11
|
+
|
12
|
+
|
13
|
+
# import the wonderful Beautiful Soup and the URL grabber
|
14
|
+
class CouncilClass(AbstractGetBinDataClass):
|
15
|
+
"""
|
16
|
+
Concrete classes have to implement all abstract operations of the
|
17
|
+
base class. They can also override some operations with a default
|
18
|
+
implementation.
|
19
|
+
"""
|
20
|
+
|
21
|
+
def parse_data(self, page: str, **kwargs) -> dict:
|
22
|
+
|
23
|
+
user_uprn = kwargs.get("uprn")
|
24
|
+
user_postcode = kwargs.get("postcode")
|
25
|
+
web_driver = kwargs.get("web_driver")
|
26
|
+
headless = kwargs.get("headless")
|
27
|
+
check_uprn(user_uprn)
|
28
|
+
bindata = {"bins": []}
|
29
|
+
|
30
|
+
# Initialize the WebDriver (Chrome in this case)
|
31
|
+
with create_webdriver(
|
32
|
+
web_driver,
|
33
|
+
headless,
|
34
|
+
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36",
|
35
|
+
__name__,
|
36
|
+
) as driver:
|
37
|
+
|
38
|
+
# Step 1: Navigate to the form page
|
39
|
+
driver.get(
|
40
|
+
"https://lewisham.gov.uk/myservices/recycling-and-rubbish/your-bins/collection"
|
41
|
+
)
|
42
|
+
|
43
|
+
try:
|
44
|
+
cookie_accept_button = WebDriverWait(driver, 5).until(
|
45
|
+
EC.element_to_be_clickable(
|
46
|
+
(By.ID, "CybotCookiebotDialogBodyLevelButtonLevelOptinAllowAll")
|
47
|
+
)
|
48
|
+
)
|
49
|
+
cookie_accept_button.click()
|
50
|
+
except Exception:
|
51
|
+
print("No cookie consent banner found or already dismissed.")
|
52
|
+
|
53
|
+
# Wait for the form to load
|
54
|
+
WebDriverWait(driver, 10).until(
|
55
|
+
EC.presence_of_element_located((By.CLASS_NAME, "address-finder"))
|
56
|
+
)
|
57
|
+
|
58
|
+
# Step 2: Locate the input field for the postcode
|
59
|
+
postcode_input = driver.find_element(
|
60
|
+
By.CLASS_NAME, "js-address-finder-input"
|
61
|
+
)
|
62
|
+
|
63
|
+
# Enter the postcode
|
64
|
+
postcode_input.send_keys(
|
65
|
+
user_postcode
|
66
|
+
) # Replace with your desired postcode
|
67
|
+
time.sleep(1) # Optional: Wait for the UI to react
|
68
|
+
|
69
|
+
# Step 4: Click the "Find address" button with retry logic
|
70
|
+
find_button = WebDriverWait(driver, 10).until(
|
71
|
+
EC.element_to_be_clickable(
|
72
|
+
(By.CLASS_NAME, "js-address-finder-step-address")
|
73
|
+
)
|
74
|
+
)
|
75
|
+
find_button.click()
|
76
|
+
|
77
|
+
# Wait for the address selector to appear and options to load
|
78
|
+
WebDriverWait(driver, 10).until(
|
79
|
+
lambda d: len(
|
80
|
+
d.find_element(By.ID, "address-selector").find_elements(
|
81
|
+
By.TAG_NAME, "option"
|
82
|
+
)
|
83
|
+
)
|
84
|
+
> 1
|
85
|
+
)
|
86
|
+
|
87
|
+
# Select the dropdown and print available options
|
88
|
+
address_selector = driver.find_element(By.ID, "address-selector")
|
89
|
+
|
90
|
+
# Use Select class to interact with the dropdown
|
91
|
+
select = Select(address_selector)
|
92
|
+
if len(select.options) > 1:
|
93
|
+
select.select_by_value(user_uprn)
|
94
|
+
else:
|
95
|
+
print("No additional addresses available to select")
|
96
|
+
|
97
|
+
# Wait until the URL contains the expected substring
|
98
|
+
WebDriverWait(driver, 10).until(
|
99
|
+
EC.url_contains("/find-your-collection-day-result")
|
100
|
+
)
|
101
|
+
|
102
|
+
# Parse the HTML
|
103
|
+
soup = BeautifulSoup(driver.page_source, "html.parser")
|
104
|
+
|
105
|
+
# Extract the main container
|
106
|
+
collection_result = soup.find("div", class_="js-find-collection-result")
|
107
|
+
|
108
|
+
# Extract each collection type and its frequency/day
|
109
|
+
for strong_tag in collection_result.find_all("strong"):
|
110
|
+
bin_type = strong_tag.text.strip() # e.g., "Food waste"
|
111
|
+
# Extract the sibling text
|
112
|
+
schedule_text = (
|
113
|
+
strong_tag.next_sibling.next_sibling.next_sibling.text.strip()
|
114
|
+
.replace("\n", " ")
|
115
|
+
.replace("\t", " ")
|
116
|
+
)
|
117
|
+
|
118
|
+
# Extract the day using regex
|
119
|
+
print(schedule_text)
|
120
|
+
day_match = re.search(r"on\s*(\w+day)", schedule_text)
|
121
|
+
print(day_match)
|
122
|
+
day = day_match.group(1) if day_match else None
|
123
|
+
|
124
|
+
# Extract the next collection date using regex
|
125
|
+
date_match = re.search(
|
126
|
+
r"Your next collection date is\s*(\d{2}/\d{2}/\d{4})(.?)",
|
127
|
+
schedule_text,
|
128
|
+
)
|
129
|
+
if date_match:
|
130
|
+
next_collection_date = date_match.group(1)
|
131
|
+
else:
|
132
|
+
next_collection_date = get_next_day_of_week(day, date_format)
|
133
|
+
|
134
|
+
dict_data = {
|
135
|
+
"type": bin_type,
|
136
|
+
"collectionDate": next_collection_date,
|
137
|
+
}
|
138
|
+
bindata["bins"].append(dict_data)
|
139
|
+
|
140
|
+
return bindata
|
@@ -0,0 +1,65 @@
|
|
1
|
+
import requests
|
2
|
+
from bs4 import BeautifulSoup
|
3
|
+
|
4
|
+
from uk_bin_collection.uk_bin_collection.common import *
|
5
|
+
from uk_bin_collection.uk_bin_collection.get_bin_data import AbstractGetBinDataClass
|
6
|
+
|
7
|
+
|
8
|
+
# import the wonderful Beautiful Soup and the URL grabber
|
9
|
+
class CouncilClass(AbstractGetBinDataClass):
|
10
|
+
"""
|
11
|
+
Concrete classes have to implement all abstract operations of the
|
12
|
+
base class. They can also override some operations with a default
|
13
|
+
implementation.
|
14
|
+
"""
|
15
|
+
|
16
|
+
def parse_data(self, page: str, **kwargs) -> dict:
|
17
|
+
|
18
|
+
user_uprn = kwargs.get("uprn")
|
19
|
+
bindata = {"bins": []}
|
20
|
+
|
21
|
+
user_uprn = user_uprn.zfill(8)
|
22
|
+
|
23
|
+
year = datetime.today().year
|
24
|
+
response = requests.get(
|
25
|
+
f"https://bindayfinder.moray.gov.uk/cal_{year}_view.php",
|
26
|
+
params={"id": user_uprn},
|
27
|
+
)
|
28
|
+
if response.status_code != 200:
|
29
|
+
# fall back to known good calendar URL
|
30
|
+
response = requests.get(
|
31
|
+
"https://bindayfinder.moray.gov.uk/cal_2024_view.php",
|
32
|
+
params={"id": user_uprn},
|
33
|
+
)
|
34
|
+
soup = BeautifulSoup(response.text, "html.parser")
|
35
|
+
|
36
|
+
bin_types = {
|
37
|
+
"G": "Green",
|
38
|
+
"B": "Brown",
|
39
|
+
"P": "Purple",
|
40
|
+
"C": "Blue",
|
41
|
+
"O": "Orange",
|
42
|
+
}
|
43
|
+
|
44
|
+
for month_container in soup.findAll("div", class_="month-container"):
|
45
|
+
for div in month_container.findAll("div"):
|
46
|
+
if "month-header" in div["class"]:
|
47
|
+
month = div.text
|
48
|
+
elif div["class"] and div["class"][0] in ["B", "GPOC", "GBPOC"]:
|
49
|
+
bins = div["class"][0]
|
50
|
+
dom = int(div.text)
|
51
|
+
for i in bins:
|
52
|
+
dict_data = {
|
53
|
+
"type": bin_types.get(i),
|
54
|
+
"collectionDate": datetime.strptime(
|
55
|
+
f"{dom} {month} {year}",
|
56
|
+
"%d %B %Y",
|
57
|
+
).strftime("%d/%m/%Y"),
|
58
|
+
}
|
59
|
+
bindata["bins"].append(dict_data)
|
60
|
+
|
61
|
+
bindata["bins"].sort(
|
62
|
+
key=lambda x: datetime.strptime(x.get("collectionDate"), "%d/%m/%Y")
|
63
|
+
)
|
64
|
+
|
65
|
+
return bindata
|
@@ -0,0 +1,113 @@
|
|
1
|
+
import time
|
2
|
+
|
3
|
+
import requests
|
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
|
+
|
19
|
+
user_postcode = kwargs.get("postcode")
|
20
|
+
user_paon = kwargs.get("paon")
|
21
|
+
check_postcode(user_postcode)
|
22
|
+
check_paon(user_paon)
|
23
|
+
bindata = {"bins": []}
|
24
|
+
|
25
|
+
user_postcode = user_postcode.replace(" ", "+")
|
26
|
+
|
27
|
+
URI = f"https://www.royalgreenwich.gov.uk/site/custom_scripts/apps/waste-collection/new2023/source.php?term={user_postcode}"
|
28
|
+
|
29
|
+
# Make the GET request
|
30
|
+
response = requests.get(URI)
|
31
|
+
|
32
|
+
for address in response.json():
|
33
|
+
if user_paon in address:
|
34
|
+
collection_address = address
|
35
|
+
break
|
36
|
+
|
37
|
+
URI = "https://www.royalgreenwich.gov.uk/site/custom_scripts/repo/apps/waste-collection/new2023/ajax-response-uprn.php"
|
38
|
+
|
39
|
+
data = {"address": collection_address}
|
40
|
+
|
41
|
+
response = requests.post(URI, data=data)
|
42
|
+
|
43
|
+
response = response.json()
|
44
|
+
|
45
|
+
collection_day = response["Day"]
|
46
|
+
week = response["Frequency"]
|
47
|
+
|
48
|
+
days_of_week = [
|
49
|
+
"Monday",
|
50
|
+
"Tuesday",
|
51
|
+
"Wednesday",
|
52
|
+
"Thursday",
|
53
|
+
"Friday",
|
54
|
+
"Saturday",
|
55
|
+
"Sunday",
|
56
|
+
]
|
57
|
+
collectionweek = ["Week A", "Week B"]
|
58
|
+
|
59
|
+
offset_days = days_of_week.index(collection_day)
|
60
|
+
week = collectionweek.index(week)
|
61
|
+
|
62
|
+
greenstartDate = datetime(2024, 11, 25)
|
63
|
+
bluestartDate = datetime(2024, 11, 25)
|
64
|
+
if week == 0:
|
65
|
+
blackstartDate = datetime(2024, 11, 18)
|
66
|
+
elif week == 1:
|
67
|
+
blackstartDate = datetime(2024, 11, 25)
|
68
|
+
|
69
|
+
green_dates = get_dates_every_x_days(greenstartDate, 7, 100)
|
70
|
+
blue_dates = get_dates_every_x_days(bluestartDate, 7, 100)
|
71
|
+
black_dates = get_dates_every_x_days(blackstartDate, 14, 50)
|
72
|
+
|
73
|
+
for greenDate in green_dates:
|
74
|
+
|
75
|
+
collection_date = (
|
76
|
+
datetime.strptime(greenDate, "%d/%m/%Y") + timedelta(days=offset_days)
|
77
|
+
).strftime("%d/%m/%Y")
|
78
|
+
|
79
|
+
dict_data = {
|
80
|
+
"type": "Green Bin",
|
81
|
+
"collectionDate": collection_date,
|
82
|
+
}
|
83
|
+
bindata["bins"].append(dict_data)
|
84
|
+
|
85
|
+
for blueDate in blue_dates:
|
86
|
+
|
87
|
+
collection_date = (
|
88
|
+
datetime.strptime(blueDate, "%d/%m/%Y") + timedelta(days=offset_days)
|
89
|
+
).strftime("%d/%m/%Y")
|
90
|
+
|
91
|
+
dict_data = {
|
92
|
+
"type": "Blue Bin",
|
93
|
+
"collectionDate": collection_date,
|
94
|
+
}
|
95
|
+
bindata["bins"].append(dict_data)
|
96
|
+
|
97
|
+
for blackDate in black_dates:
|
98
|
+
|
99
|
+
collection_date = (
|
100
|
+
datetime.strptime(blackDate, "%d/%m/%Y") + timedelta(days=offset_days)
|
101
|
+
).strftime("%d/%m/%Y")
|
102
|
+
|
103
|
+
dict_data = {
|
104
|
+
"type": "Black Bin",
|
105
|
+
"collectionDate": collection_date,
|
106
|
+
}
|
107
|
+
bindata["bins"].append(dict_data)
|
108
|
+
|
109
|
+
bindata["bins"].sort(
|
110
|
+
key=lambda x: datetime.strptime(x.get("collectionDate"), "%d/%m/%Y")
|
111
|
+
)
|
112
|
+
|
113
|
+
return bindata
|
@@ -0,0 +1,87 @@
|
|
1
|
+
import time
|
2
|
+
|
3
|
+
import requests
|
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
|
+
|
19
|
+
user_uprn = kwargs.get("uprn")
|
20
|
+
check_uprn(user_uprn)
|
21
|
+
bindata = {"bins": []}
|
22
|
+
|
23
|
+
SESSION_URL = "https://my.sandwell.gov.uk/authapi/isauthenticated?uri=https%253A%252F%252Fmy.sandwell.gov.uk%252Fen%252FAchieveForms%252F%253Fform_uri%253Dsandbox-publish%253A%252F%252FAF-Process-ebaa26a2-393c-4a3c-84f5-e61564192a8a%252FAF-Stage-e4c2cb32-db55-4ff5-845c-8b27f87346c4%252Fdefinition.json%2526redirectlink%253D%25252Fen%2526cancelRedirectLink%253D%25252Fen%2526consentMessage%253Dyes&hostname=my.sandwell.gov.uk&withCredentials=true"
|
24
|
+
|
25
|
+
API_URL = "https://my.sandwell.gov.uk/apibroker/runLookup"
|
26
|
+
|
27
|
+
headers = {
|
28
|
+
"Content-Type": "application/json",
|
29
|
+
"Accept": "application/json",
|
30
|
+
"User-Agent": "Mozilla/5.0",
|
31
|
+
"X-Requested-With": "XMLHttpRequest",
|
32
|
+
"Referer": "https://my.sandwell.gov.uk/fillform/?iframe_id=fillform-frame-1&db_id=",
|
33
|
+
}
|
34
|
+
s = requests.session()
|
35
|
+
r = s.get(SESSION_URL)
|
36
|
+
r.raise_for_status()
|
37
|
+
session_data = r.json()
|
38
|
+
sid = session_data["auth-session"]
|
39
|
+
|
40
|
+
data = {
|
41
|
+
"formValues": {
|
42
|
+
"Property details": {
|
43
|
+
"Uprn": {
|
44
|
+
"value": user_uprn,
|
45
|
+
},
|
46
|
+
"NextCollectionFromDate": {
|
47
|
+
"value": datetime.now().strftime("%Y-%m-%d"),
|
48
|
+
},
|
49
|
+
},
|
50
|
+
},
|
51
|
+
}
|
52
|
+
|
53
|
+
params = {
|
54
|
+
"id": "58a1a71694992",
|
55
|
+
"repeat_against": "",
|
56
|
+
"noRetry": "false",
|
57
|
+
"getOnlyTokens": "undefined",
|
58
|
+
"log_id": "",
|
59
|
+
"app_name": "AF-Renderer::Self",
|
60
|
+
# unix_timestamp
|
61
|
+
"_": str(int(time.time() * 1000)),
|
62
|
+
"sid": sid,
|
63
|
+
}
|
64
|
+
|
65
|
+
r = s.post(API_URL, json=data, headers=headers, params=params)
|
66
|
+
r.raise_for_status()
|
67
|
+
|
68
|
+
data = r.json()
|
69
|
+
rows_data = data["integration"]["transformed"]["rows_data"]
|
70
|
+
if not isinstance(rows_data, dict):
|
71
|
+
raise ValueError("Invalid data returned from API")
|
72
|
+
bin_types = {
|
73
|
+
"Recycling (Blue)",
|
74
|
+
"Household Waste (Grey)",
|
75
|
+
"Food Waste (Brown)",
|
76
|
+
"Garden Waste (Green)",
|
77
|
+
}
|
78
|
+
for row in rows_data.items():
|
79
|
+
date = row[1]["DWDate"]
|
80
|
+
for bin_type in bin_types:
|
81
|
+
dict_data = {
|
82
|
+
"type": bin_type,
|
83
|
+
"collectionDate": date,
|
84
|
+
}
|
85
|
+
bindata["bins"].append(dict_data)
|
86
|
+
|
87
|
+
return bindata
|
@@ -0,0 +1,93 @@
|
|
1
|
+
from uk_bin_collection.uk_bin_collection.common import *
|
2
|
+
from uk_bin_collection.uk_bin_collection.get_bin_data import AbstractGetBinDataClass
|
3
|
+
|
4
|
+
|
5
|
+
# import the wonderful Beautiful Soup and the URL grabber
|
6
|
+
class CouncilClass(AbstractGetBinDataClass):
|
7
|
+
"""
|
8
|
+
Concrete classes have to implement all abstract operations of the
|
9
|
+
base class. They can also override some operations with a default
|
10
|
+
implementation.
|
11
|
+
"""
|
12
|
+
|
13
|
+
def parse_data(self, page: str, **kwargs) -> dict:
|
14
|
+
|
15
|
+
collection_day = kwargs.get("paon")
|
16
|
+
round = kwargs.get("postcode")
|
17
|
+
|
18
|
+
bindata = {"bins": []}
|
19
|
+
|
20
|
+
days_of_week = [
|
21
|
+
"Monday",
|
22
|
+
"Tuesday",
|
23
|
+
"Wednesday",
|
24
|
+
"Thursday",
|
25
|
+
"Friday",
|
26
|
+
"Saturday",
|
27
|
+
"Sunday",
|
28
|
+
]
|
29
|
+
|
30
|
+
round_week = ["Round A", "Round B"]
|
31
|
+
|
32
|
+
offset_days = days_of_week.index(collection_day)
|
33
|
+
round_collection = round_week.index(round)
|
34
|
+
|
35
|
+
if round_collection == 0:
|
36
|
+
bluebrownstartDate = datetime(2024, 10, 21)
|
37
|
+
greengreystartDate = datetime(2024, 10, 28)
|
38
|
+
else:
|
39
|
+
greengreystartDate = datetime(2024, 10, 21)
|
40
|
+
bluebrownstartDate = datetime(2024, 10, 28)
|
41
|
+
|
42
|
+
greengrey_dates = get_dates_every_x_days(greengreystartDate, 14, 28)
|
43
|
+
bluebrown_dates = get_dates_every_x_days(bluebrownstartDate, 14, 28)
|
44
|
+
food_dates = get_dates_every_x_days(greengreystartDate, 7, 56)
|
45
|
+
|
46
|
+
for greengrey_date in greengrey_dates:
|
47
|
+
|
48
|
+
collection_date = (
|
49
|
+
datetime.strptime(greengrey_date, "%d/%m/%Y")
|
50
|
+
+ timedelta(days=offset_days)
|
51
|
+
).strftime("%d/%m/%Y")
|
52
|
+
|
53
|
+
dict_data = {
|
54
|
+
"type": "Green/Grey Bin",
|
55
|
+
"collectionDate": collection_date,
|
56
|
+
}
|
57
|
+
bindata["bins"].append(dict_data)
|
58
|
+
|
59
|
+
for bluebrown_date in bluebrown_dates:
|
60
|
+
|
61
|
+
collection_date = (
|
62
|
+
datetime.strptime(bluebrown_date, "%d/%m/%Y")
|
63
|
+
+ timedelta(days=offset_days)
|
64
|
+
).strftime("%d/%m/%Y")
|
65
|
+
|
66
|
+
dict_data = {
|
67
|
+
"type": "Blue Bin",
|
68
|
+
"collectionDate": collection_date,
|
69
|
+
}
|
70
|
+
bindata["bins"].append(dict_data)
|
71
|
+
dict_data = {
|
72
|
+
"type": "Brown Bin",
|
73
|
+
"collectionDate": collection_date,
|
74
|
+
}
|
75
|
+
bindata["bins"].append(dict_data)
|
76
|
+
|
77
|
+
for food_date in food_dates:
|
78
|
+
|
79
|
+
collection_date = (
|
80
|
+
datetime.strptime(food_date, "%d/%m/%Y") + timedelta(days=offset_days)
|
81
|
+
).strftime("%d/%m/%Y")
|
82
|
+
|
83
|
+
dict_data = {
|
84
|
+
"type": "Food Bin",
|
85
|
+
"collectionDate": collection_date,
|
86
|
+
}
|
87
|
+
bindata["bins"].append(dict_data)
|
88
|
+
|
89
|
+
bindata["bins"].sort(
|
90
|
+
key=lambda x: datetime.strptime(x.get("collectionDate"), "%d/%m/%Y")
|
91
|
+
)
|
92
|
+
|
93
|
+
return bindata
|
@@ -15,20 +15,22 @@ class CouncilClass(AbstractGetBinDataClass):
|
|
15
15
|
"""
|
16
16
|
|
17
17
|
def parse_data(self, page: str, **kwargs) -> dict:
|
18
|
-
|
19
|
-
|
18
|
+
user_uprn = kwargs.get("uprn")
|
19
|
+
check_uprn(user_uprn)
|
20
20
|
|
21
|
-
api_url = f"https://
|
21
|
+
api_url = f"https://api.westnorthants.digital/openapi/v1/unified-waste-collections/{user_uprn}"
|
22
22
|
json_data = requests.get(api_url).json()
|
23
23
|
|
24
24
|
data = {"bins": []}
|
25
25
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
26
|
+
collections = json_data["collectionItems"]
|
27
|
+
for collection in collections:
|
28
|
+
dict_data = {
|
29
|
+
"type": collection["type"].capitalize(),
|
30
|
+
"collectionDate": datetime.strptime(
|
31
|
+
collection["date"], "%Y-%m-%d"
|
32
|
+
).strftime(date_format),
|
33
|
+
}
|
34
|
+
data["bins"].append(dict_data)
|
33
35
|
|
34
36
|
return data
|
@@ -0,0 +1,65 @@
|
|
1
|
+
from uk_bin_collection.uk_bin_collection.common import *
|
2
|
+
from uk_bin_collection.uk_bin_collection.get_bin_data import AbstractGetBinDataClass
|
3
|
+
|
4
|
+
|
5
|
+
# import the wonderful Beautiful Soup and the URL grabber
|
6
|
+
class CouncilClass(AbstractGetBinDataClass):
|
7
|
+
"""
|
8
|
+
Concrete classes have to implement all abstract operations of the
|
9
|
+
base class. They can also override some operations with a default
|
10
|
+
implementation.
|
11
|
+
"""
|
12
|
+
|
13
|
+
def parse_data(self, page: str, **kwargs) -> dict:
|
14
|
+
|
15
|
+
collection_day = kwargs.get("paon")
|
16
|
+
bindata = {"bins": []}
|
17
|
+
|
18
|
+
days_of_week = [
|
19
|
+
"Monday",
|
20
|
+
"Tuesday",
|
21
|
+
"Wednesday",
|
22
|
+
"Thursday",
|
23
|
+
"Friday",
|
24
|
+
"Saturday",
|
25
|
+
"Sunday",
|
26
|
+
]
|
27
|
+
|
28
|
+
refusestartDate = datetime(2024, 11, 25)
|
29
|
+
recyclingstartDate = datetime(2024, 11, 18)
|
30
|
+
|
31
|
+
offset_days = days_of_week.index(collection_day)
|
32
|
+
|
33
|
+
refuse_dates = get_dates_every_x_days(refusestartDate, 14, 28)
|
34
|
+
recycling_dates = get_dates_every_x_days(recyclingstartDate, 14, 28)
|
35
|
+
|
36
|
+
for refuseDate in refuse_dates:
|
37
|
+
|
38
|
+
collection_date = (
|
39
|
+
datetime.strptime(refuseDate, "%d/%m/%Y") + timedelta(days=offset_days)
|
40
|
+
).strftime("%d/%m/%Y")
|
41
|
+
|
42
|
+
dict_data = {
|
43
|
+
"type": "Black/Grey Rubbish Bin",
|
44
|
+
"collectionDate": collection_date,
|
45
|
+
}
|
46
|
+
bindata["bins"].append(dict_data)
|
47
|
+
|
48
|
+
for recyclingDate in recycling_dates:
|
49
|
+
|
50
|
+
collection_date = (
|
51
|
+
datetime.strptime(recyclingDate, "%d/%m/%Y")
|
52
|
+
+ timedelta(days=offset_days)
|
53
|
+
).strftime("%d/%m/%Y")
|
54
|
+
|
55
|
+
dict_data = {
|
56
|
+
"type": "Green Recycling Bin",
|
57
|
+
"collectionDate": collection_date,
|
58
|
+
}
|
59
|
+
bindata["bins"].append(dict_data)
|
60
|
+
|
61
|
+
bindata["bins"].sort(
|
62
|
+
key=lambda x: datetime.strptime(x.get("collectionDate"), "%d/%m/%Y")
|
63
|
+
)
|
64
|
+
|
65
|
+
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=IfNcYfT9YNy84xy-ETXgBvdUN9vW6Pc2y3tYjq2AAyI,110958
|
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
|
@@ -59,6 +59,7 @@ uk_bin_collection/uk_bin_collection/councils/CarmarthenshireCountyCouncil.py,sha
|
|
59
59
|
uk_bin_collection/uk_bin_collection/councils/CastlepointDistrictCouncil.py,sha256=JVPYUIlU2ISgbUSr5AOOXNK6IFQFtQmhZyYIMAOedD4,3858
|
60
60
|
uk_bin_collection/uk_bin_collection/councils/CharnwoodBoroughCouncil.py,sha256=tXfzMetN6wxahuGGRp2mIyCCDSL4F2aG61HhUxw6COQ,2172
|
61
61
|
uk_bin_collection/uk_bin_collection/councils/ChelmsfordCityCouncil.py,sha256=EB88D0MNJwuDZ2GX1ENc5maGYx17mnHTCtNl6s-v11E,5090
|
62
|
+
uk_bin_collection/uk_bin_collection/councils/CheltenhamBoroughCouncil.py,sha256=z59g9h6QwdeCNzonM5AI-6NvpLKocD-DT8eSvqk8RwU,3198
|
62
63
|
uk_bin_collection/uk_bin_collection/councils/CheshireEastCouncil.py,sha256=73P5GF6Y7Ud1hNgyFypvT1d6eBWjzdBjr3h0Dsl6NWw,1679
|
63
64
|
uk_bin_collection/uk_bin_collection/councils/CheshireWestAndChesterCouncil.py,sha256=5mKZf22NgdyBY-SqV0c2q8b8IJobkoZrsfGEVUcxUyM,3544
|
64
65
|
uk_bin_collection/uk_bin_collection/councils/ChesterfieldBoroughCouncil.py,sha256=mZiM8Ugm_OP0JkC5pLaQmi4i79mAp4SNNrcIdsREjHw,7198
|
@@ -68,7 +69,7 @@ uk_bin_collection/uk_bin_collection/councils/ColchesterCityCouncil.py,sha256=Mny
|
|
68
69
|
uk_bin_collection/uk_bin_collection/councils/ConwyCountyBorough.py,sha256=el75qv2QyfWZBU09tJLvD8vLQZ9pCg73u1NBFs6ybo8,1034
|
69
70
|
uk_bin_collection/uk_bin_collection/councils/CopelandBoroughCouncil.py,sha256=JDtcJFUY47a3Ws4_7pnCYlngw_3p_A-m5MitPLdrv3w,3983
|
70
71
|
uk_bin_collection/uk_bin_collection/councils/CornwallCouncil.py,sha256=WZiz50svwyZgO8QKUCLy7hfFuy2HmAx5h-TG3yAweRA,2836
|
71
|
-
uk_bin_collection/uk_bin_collection/councils/CotswoldDistrictCouncil.py,sha256=
|
72
|
+
uk_bin_collection/uk_bin_collection/councils/CotswoldDistrictCouncil.py,sha256=Y2yvduT6XTy54bDYX17-dltjd7L36cc7GDjlx0xWskA,4896
|
72
73
|
uk_bin_collection/uk_bin_collection/councils/CoventryCityCouncil.py,sha256=kfAvA2e4MlO0W9YT70U_mW9gxVPrmr0BOGzV99Tw2Bg,2012
|
73
74
|
uk_bin_collection/uk_bin_collection/councils/CrawleyBoroughCouncil.py,sha256=Oaj5INA3zNjtzBRsfLvRTIxZzcd4E4bJfVF1ULWlrL4,4322
|
74
75
|
uk_bin_collection/uk_bin_collection/councils/CroydonCouncil.py,sha256=Vxh5ICoaXTAvx0nDOq_95XQ4He9sQKcLdI5keV2uxM4,11384
|
@@ -83,7 +84,7 @@ uk_bin_collection/uk_bin_collection/councils/DoverDistrictCouncil.py,sha256=3Zga
|
|
83
84
|
uk_bin_collection/uk_bin_collection/councils/DudleyCouncil.py,sha256=tDGfBWD5AVEzHt-XowD4qmmDcdlOLKC0oON8jkARRAI,3134
|
84
85
|
uk_bin_collection/uk_bin_collection/councils/DurhamCouncil.py,sha256=6O8bNsQVYQbrCYQE9Rp0c_rtkcXuxR3s9J6jn4MK4_s,1695
|
85
86
|
uk_bin_collection/uk_bin_collection/councils/EalingCouncil.py,sha256=UhNXGi-_6NYZu50988VEvOzmAVunxOoyJ6mz0OEaUz4,1321
|
86
|
-
uk_bin_collection/uk_bin_collection/councils/EastAyrshireCouncil.py,sha256=
|
87
|
+
uk_bin_collection/uk_bin_collection/councils/EastAyrshireCouncil.py,sha256=i3AcWkeAnk7rD59nOm0QCSH7AggqjUAdwsXuSIC8ZJE,1614
|
87
88
|
uk_bin_collection/uk_bin_collection/councils/EastCambridgeshireCouncil.py,sha256=aYUVE5QqTxdj8FHhCB4EiFVDJahWJD9Pq0d1upBEvXg,1501
|
88
89
|
uk_bin_collection/uk_bin_collection/councils/EastDevonDC.py,sha256=U0VwSNIldMv5nUoiXtFgjbE0m6Kb-8W2WZQGVCNF_WI,3261
|
89
90
|
uk_bin_collection/uk_bin_collection/councils/EastHertsCouncil.py,sha256=hjIrZXM0qe8xvHfrBqMDyXnq0_h_ySODqTfmOI5ahTc,4071
|
@@ -104,6 +105,7 @@ uk_bin_collection/uk_bin_collection/councils/FarehamBoroughCouncil.py,sha256=25Q
|
|
104
105
|
uk_bin_collection/uk_bin_collection/councils/FenlandDistrictCouncil.py,sha256=sFrnKzIE2tIcz0YrC6A9HcevzgNdf6E6_HLGMWDKtGw,2513
|
105
106
|
uk_bin_collection/uk_bin_collection/councils/FifeCouncil.py,sha256=eP_NnHtBLyflRUko9ubi_nxUPb7qg9SbaaSxqWZxNEs,2157
|
106
107
|
uk_bin_collection/uk_bin_collection/councils/FlintshireCountyCouncil.py,sha256=RvPHhGbzP3mcjgWe2rIQux43UuDH7XofJGIKs7wJRe0,2060
|
108
|
+
uk_bin_collection/uk_bin_collection/councils/FolkstoneandHytheDistrictCouncil.py,sha256=yKgZhua-2hjMihHshhncXVUBagbTOQBnNbKzdIZkWjw,3114
|
107
109
|
uk_bin_collection/uk_bin_collection/councils/ForestOfDeanDistrictCouncil.py,sha256=YWT2GM2-bQ3Zh9ps1K14XRZfanuJOlV-zHpOOYMXAXY,4893
|
108
110
|
uk_bin_collection/uk_bin_collection/councils/GatesheadCouncil.py,sha256=SRCgYhYs6rv_8C1UEDVORHZgXxcJkoZBjzdYS4Lu-ew,4531
|
109
111
|
uk_bin_collection/uk_bin_collection/councils/GedlingBoroughCouncil.py,sha256=XzfFMCwclh9zAJgsbaj4jywjdiH0wPaFicaVsLrN3ms,2297
|
@@ -111,6 +113,7 @@ uk_bin_collection/uk_bin_collection/councils/GlasgowCityCouncil.py,sha256=9N5GXR
|
|
111
113
|
uk_bin_collection/uk_bin_collection/councils/GloucesterCityCouncil.py,sha256=8Wjvmdvg5blHVrREaEnhhWZaWhYVP4v_KdDVPLIUxaU,4889
|
112
114
|
uk_bin_collection/uk_bin_collection/councils/GraveshamBoroughCouncil.py,sha256=ueQ9xFiTxMUBTGV9VjtySHA1EFWliTM0AeNePBIG9ho,4568
|
113
115
|
uk_bin_collection/uk_bin_collection/councils/GuildfordCouncil.py,sha256=9pVrmQhZcK2AD8gX8mNvP--L4L9KaY6L3B822VX6fec,5695
|
116
|
+
uk_bin_collection/uk_bin_collection/councils/HackneyCouncil.py,sha256=fJZTHCk-uXC61V_7uxiU_MhIupfeObjaUYAT0v0onLo,3100
|
114
117
|
uk_bin_collection/uk_bin_collection/councils/HaltonBoroughCouncil.py,sha256=gq_CPqi6qM2oNiHhKKF1lZC86fyKL4lPhh_DN9pJZ04,5971
|
115
118
|
uk_bin_collection/uk_bin_collection/councils/HarboroughDistrictCouncil.py,sha256=uAbCgfrqkIkEKUyLVE8l72s5tzbfMFsw775i0nVRAyc,1934
|
116
119
|
uk_bin_collection/uk_bin_collection/councils/HaringeyCouncil.py,sha256=t_6AkAu4wrv8Q0WlDhWh_82I0djl5tk531Pzs-SjWzg,2647
|
@@ -123,6 +126,7 @@ uk_bin_collection/uk_bin_collection/councils/HounslowCouncil.py,sha256=LXhJ47ruj
|
|
123
126
|
uk_bin_collection/uk_bin_collection/councils/HullCityCouncil.py,sha256=UHcesBoctFVcXDYuwfag43KbcJcopkEDzJ-54NxtK0Q,1851
|
124
127
|
uk_bin_collection/uk_bin_collection/councils/HuntingdonDistrictCouncil.py,sha256=dGyhhG6HRjQ2SPeiRwUPTGlk9dPIslagV2k0GjEOn1s,1587
|
125
128
|
uk_bin_collection/uk_bin_collection/councils/IslingtonCouncil.py,sha256=xavzL6ZIU9DG8Xro3vN0CEnYmNU31OGnOvnq78wgpQc,1258
|
129
|
+
uk_bin_collection/uk_bin_collection/councils/KingsLynnandWestNorfolkBC.py,sha256=Shj18R-7NW4ivqJJFVJOLmf-EeN6hXP2Of30oI-SeAQ,1932
|
126
130
|
uk_bin_collection/uk_bin_collection/councils/KingstonUponThamesCouncil.py,sha256=iZ7njIxccCGBhUUWWd9Azh7cxUAKaofebCm3lo-TuxA,3543
|
127
131
|
uk_bin_collection/uk_bin_collection/councils/KirkleesCouncil.py,sha256=gtAtM6FappSZ0-BKid7_pnSrnqPPjHn_UYWqMg9wQlM,4499
|
128
132
|
uk_bin_collection/uk_bin_collection/councils/KnowsleyMBCouncil.py,sha256=VdlWDESoHfr_X0r8-UMaLMUQhKZOa2BnpVPkX-1u3EQ,5605
|
@@ -137,6 +141,7 @@ uk_bin_collection/uk_bin_collection/councils/LondonBoroughHarrow.py,sha256=kzKwb
|
|
137
141
|
uk_bin_collection/uk_bin_collection/councils/LondonBoroughHavering.py,sha256=6DNX6IShdoEG4FjoyrzrY_HLEu9R2Bgl6PN0bSCbhow,2436
|
138
142
|
uk_bin_collection/uk_bin_collection/councils/LondonBoroughHounslow.py,sha256=UOeiOxGMvVMm2UFaqjmQpm7vxzqJNSSN8LM9lAUjs2c,3021
|
139
143
|
uk_bin_collection/uk_bin_collection/councils/LondonBoroughLambeth.py,sha256=r9D5lHe5kIRStCd5lRIax16yhb4KTFzzfYEFv1bacWw,2009
|
144
|
+
uk_bin_collection/uk_bin_collection/councils/LondonBoroughLewisham.py,sha256=d8rlJDTbY3nj-Zjg6iwvwfe-X13Gq86DGGW6QkQAUW0,5310
|
140
145
|
uk_bin_collection/uk_bin_collection/councils/LondonBoroughRedbridge.py,sha256=A_6Sis5hsF53Th04KeadHRasGbpAm6aoaWJ6X8eC4Y8,6604
|
141
146
|
uk_bin_collection/uk_bin_collection/councils/LondonBoroughSutton.py,sha256=c2haHOwX7Dy1phVUTv3xaQgM9VeHmFuBwdAgqGcGs8Y,2369
|
142
147
|
uk_bin_collection/uk_bin_collection/councils/LutonBoroughCouncil.py,sha256=vScUi_R8FnBddii2_zLlZBLxuh85mKmCm8nKW3zxky0,2758
|
@@ -152,6 +157,7 @@ uk_bin_collection/uk_bin_collection/councils/MidSussexDistrictCouncil.py,sha256=
|
|
152
157
|
uk_bin_collection/uk_bin_collection/councils/MidlothianCouncil.py,sha256=mM5-itJDNhjsT5UEjSFfWppmfmPFSns4u_1QblewuFU,5605
|
153
158
|
uk_bin_collection/uk_bin_collection/councils/MiltonKeynesCityCouncil.py,sha256=7e2pGBLCw24pNItHeI9jkxQ3rEOZ4WC4zVlbvKYGdXE,2600
|
154
159
|
uk_bin_collection/uk_bin_collection/councils/MoleValleyDistrictCouncil.py,sha256=xWR5S0gwQu9gXxjl788Wux1KaC0CT7ZFw0iXuRLZCEM,5599
|
160
|
+
uk_bin_collection/uk_bin_collection/councils/MorayCouncil.py,sha256=jsHCQ_aV_bG0GPfF7h6g5TP84sroplYC5k2M6iEKiTw,2265
|
155
161
|
uk_bin_collection/uk_bin_collection/councils/NeathPortTalbotCouncil.py,sha256=ychYR2nsyk2UIb8tjWaKrLUT4hxSsHN558l3RqZ0mjw,5635
|
156
162
|
uk_bin_collection/uk_bin_collection/councils/NewForestCouncil.py,sha256=ylTn9KmWITtaO9_Z8kJCN2w2ALfhrfGt3SeJ78lgw7M,5391
|
157
163
|
uk_bin_collection/uk_bin_collection/councils/NewarkAndSherwoodDC.py,sha256=lAleYfCGUWCKOi7Ye_cjgfpI3pWwTcFctlYmh0hjebM,2140
|
@@ -191,10 +197,12 @@ uk_bin_collection/uk_bin_collection/councils/RochdaleCouncil.py,sha256=UTSwSw515
|
|
191
197
|
uk_bin_collection/uk_bin_collection/councils/RochfordCouncil.py,sha256=rfhD66A9HfHL46ldF9sbxvV7fPaaoNxzIJbHjVT6A90,2621
|
192
198
|
uk_bin_collection/uk_bin_collection/councils/RotherDistrictCouncil.py,sha256=-fdLvtik9ytfwXrrhwWdBxqQOMq2N1pvrIuvShhf8PU,3090
|
193
199
|
uk_bin_collection/uk_bin_collection/councils/RotherhamCouncil.py,sha256=LtMPM8lj5bfReDR4buHEo-aRC_HTBIeo1nf8GE5-R80,1790
|
200
|
+
uk_bin_collection/uk_bin_collection/councils/RoyalBoroughofGreenwich.py,sha256=BZzLmWK_VONOmMpSrLrnKtJaOrrepm6aStfKGVcgf9Y,3487
|
194
201
|
uk_bin_collection/uk_bin_collection/councils/RugbyBoroughCouncil.py,sha256=a5ySLmFvvY56QMA7-bk6MVBxRp5tPBIBg4navH0eYas,4306
|
195
202
|
uk_bin_collection/uk_bin_collection/councils/RushcliffeBoroughCouncil.py,sha256=wMtiYRirT585vtsEOIyXHugk7aEj3pvyVWBaAePdqtE,4005
|
196
203
|
uk_bin_collection/uk_bin_collection/councils/RushmoorCouncil.py,sha256=ZsGnXjoEaOS6U7fI0w7-uqxayAHdNVKsJi2fqIWEls8,3375
|
197
204
|
uk_bin_collection/uk_bin_collection/councils/SalfordCityCouncil.py,sha256=jJjAH_dM298VIJ4-SEy7agxUe8aFJ_sEPK_ZwmWJ9cE,2506
|
205
|
+
uk_bin_collection/uk_bin_collection/councils/SandwellBoroughCouncil.py,sha256=shJhvqDcha2ypDCSfhss59G95jNaWBuMnVIxJiZXcY8,3110
|
198
206
|
uk_bin_collection/uk_bin_collection/councils/SeftonCouncil.py,sha256=XUEz2li0oHrRhdkls5qzlZNZ0GuwSG7r0dwsL-qdoFA,2480
|
199
207
|
uk_bin_collection/uk_bin_collection/councils/SevenoaksDistrictCouncil.py,sha256=qqrrRaSVm9CYAtm0rB2ZnyH_nLwaReuacoUxZpo597k,4260
|
200
208
|
uk_bin_collection/uk_bin_collection/councils/SheffieldCityCouncil.py,sha256=9g9AeiackoWyej9EVlKUzywzAtMuBVD0f93ZryAUha8,2016
|
@@ -236,6 +244,7 @@ uk_bin_collection/uk_bin_collection/councils/TendringDistrictCouncil.py,sha256=D
|
|
236
244
|
uk_bin_collection/uk_bin_collection/councils/TestValleyBoroughCouncil.py,sha256=Dtfkyrwt795W7gqFJxVGRR8t3R5WMNQZwTWJckLpZWE,8480
|
237
245
|
uk_bin_collection/uk_bin_collection/councils/ThanetDistrictCouncil.py,sha256=-opmZG9GzjB_NvmWpN6nFZ7rlkSoaRrQICU5E8T0DEQ,1659
|
238
246
|
uk_bin_collection/uk_bin_collection/councils/ThreeRiversDistrictCouncil.py,sha256=RHt3e9oeKzwxjjY-M8aC0nk-ZXhHIoyC81JzxkPVxsE,5531
|
247
|
+
uk_bin_collection/uk_bin_collection/councils/ThurrockCouncil.py,sha256=vAZMm6mcsdEcOkP15xwxWy9gdXpmLYQFH7qRifurNoY,2935
|
239
248
|
uk_bin_collection/uk_bin_collection/councils/TonbridgeAndMallingBC.py,sha256=UlgnHDoi8ecav2H5-HqKNDpqW1J3RN-c___5c08_Q7I,4859
|
240
249
|
uk_bin_collection/uk_bin_collection/councils/TorbayCouncil.py,sha256=JW_BS7wkfxFsmx6taQtPAQWdBp1AfLrxs0XRQ2XZcSw,2029
|
241
250
|
uk_bin_collection/uk_bin_collection/councils/TorridgeDistrictCouncil.py,sha256=6gOO02pYU0cbj3LAHiBVNG4zkFMyIGbkE2jAye3KcGM,6386
|
@@ -257,7 +266,7 @@ uk_bin_collection/uk_bin_collection/councils/WestLancashireBoroughCouncil.py,sha
|
|
257
266
|
uk_bin_collection/uk_bin_collection/councils/WestLindseyDistrictCouncil.py,sha256=JFWUy4w0CKulGq16PfbRDKAdQEbokVEuabwlZYigdEU,4606
|
258
267
|
uk_bin_collection/uk_bin_collection/councils/WestLothianCouncil.py,sha256=dq0jimtARvRkZiGbVFrXXZgY-BODtz3uYZ5UKn0bf64,4114
|
259
268
|
uk_bin_collection/uk_bin_collection/councils/WestMorlandAndFurness.py,sha256=jbqV3460rn9D0yTBGWjpSe1IvWWcdGur5pzgj-hJcQ4,2513
|
260
|
-
uk_bin_collection/uk_bin_collection/councils/WestNorthamptonshireCouncil.py,sha256=
|
269
|
+
uk_bin_collection/uk_bin_collection/councils/WestNorthamptonshireCouncil.py,sha256=Se3Cfn_6ADjhsUzEJI_JnGkVcIbXxSTferM4ZC6pZ0g,1166
|
261
270
|
uk_bin_collection/uk_bin_collection/councils/WestOxfordshireDistrictCouncil.py,sha256=bkE7BUwRIEJQyfOHyXYeaJB1ruGTFu9LHIGursIBEIQ,4859
|
262
271
|
uk_bin_collection/uk_bin_collection/councils/WestSuffolkCouncil.py,sha256=9i8AQHh-qIRPZ_5Ad97_h04-qgyLQDPV064obBzab1Y,2587
|
263
272
|
uk_bin_collection/uk_bin_collection/councils/WiganBoroughCouncil.py,sha256=3gqFA4-BVx_In6QOu3KUNqPN4Fkn9iMlZTeopMK9p6A,3746
|
@@ -271,12 +280,13 @@ uk_bin_collection/uk_bin_collection/councils/WolverhamptonCityCouncil.py,sha256=
|
|
271
280
|
uk_bin_collection/uk_bin_collection/councils/WorcesterCityCouncil.py,sha256=dKHB2fPSmOGOwyvfpbdR4U8XW2ctBf63gCPxX06kwKA,1867
|
272
281
|
uk_bin_collection/uk_bin_collection/councils/WychavonDistrictCouncil.py,sha256=GnNNMe33YMlK6S7rjM3c4BQkBnXelS0DKl2x5V4fb2w,5775
|
273
282
|
uk_bin_collection/uk_bin_collection/councils/WyreCouncil.py,sha256=zDDa7n4K_zm5PgDL08A26gD9yOOsOhuexI3x2seaBF4,3511
|
283
|
+
uk_bin_collection/uk_bin_collection/councils/WyreForestDistrictCouncil.py,sha256=3b7WzBXdYub6j13sqDL3jlqgICKmNyQaF4KxRxOMHWk,2000
|
274
284
|
uk_bin_collection/uk_bin_collection/councils/YorkCouncil.py,sha256=I2kBYMlsD4bIdsvmoSzBjJAvTTi6yPfJa8xjJx1ys2w,1490
|
275
285
|
uk_bin_collection/uk_bin_collection/councils/council_class_template/councilclasstemplate.py,sha256=EQWRhZ2pEejlvm0fPyOTsOHKvUZmPnxEYO_OWRGKTjs,1158
|
276
286
|
uk_bin_collection/uk_bin_collection/create_new_council.py,sha256=m-IhmWmeWQlFsTZC4OxuFvtw5ZtB8EAJHxJTH4O59lQ,1536
|
277
287
|
uk_bin_collection/uk_bin_collection/get_bin_data.py,sha256=YvmHfZqanwrJ8ToGch34x-L-7yPe31nB_x77_Mgl_vo,4545
|
278
|
-
uk_bin_collection-0.
|
279
|
-
uk_bin_collection-0.
|
280
|
-
uk_bin_collection-0.
|
281
|
-
uk_bin_collection-0.
|
282
|
-
uk_bin_collection-0.
|
288
|
+
uk_bin_collection-0.121.1.dist-info/LICENSE,sha256=vABBUOzcrgfaTKpzeo-si9YVEun6juDkndqA8RKdKGs,1071
|
289
|
+
uk_bin_collection-0.121.1.dist-info/METADATA,sha256=ZqB1SnI8jyknJKcVIK20CPMBBgHQMIV5jpHIhx1jHFM,17574
|
290
|
+
uk_bin_collection-0.121.1.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
|
291
|
+
uk_bin_collection-0.121.1.dist-info/entry_points.txt,sha256=36WCSGMWSc916S3Hi1ZkazzDKHaJ6CD-4fCEFm5MIao,90
|
292
|
+
uk_bin_collection-0.121.1.dist-info/RECORD,,
|
File without changes
|
File without changes
|
{uk_bin_collection-0.120.0.dist-info → uk_bin_collection-0.121.1.dist-info}/entry_points.txt
RENAMED
File without changes
|