uk_bin_collection 0.124.4__py3-none-any.whl → 0.125.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- uk_bin_collection/tests/input.json +23 -0
- uk_bin_collection/uk_bin_collection/councils/BlaenauGwentCountyBoroughCouncil.py +113 -0
- uk_bin_collection/uk_bin_collection/councils/BroxbourneCouncil.py +2 -1
- uk_bin_collection/uk_bin_collection/councils/LondonBoroughSutton.py +8 -4
- uk_bin_collection/uk_bin_collection/councils/MertonCouncil.py +15 -3
- uk_bin_collection/uk_bin_collection/councils/RedditchBoroughCouncil.py +73 -0
- uk_bin_collection/uk_bin_collection/councils/SalfordCityCouncil.py +7 -6
- uk_bin_collection/uk_bin_collection/councils/SwaleBoroughCouncil.py +42 -18
- uk_bin_collection/uk_bin_collection/councils/WandsworthCouncil.py +74 -0
- uk_bin_collection/uk_bin_collection/councils/WiltshireCouncil.py +1 -0
- {uk_bin_collection-0.124.4.dist-info → uk_bin_collection-0.125.1.dist-info}/METADATA +1 -1
- {uk_bin_collection-0.124.4.dist-info → uk_bin_collection-0.125.1.dist-info}/RECORD +15 -12
- {uk_bin_collection-0.124.4.dist-info → uk_bin_collection-0.125.1.dist-info}/LICENSE +0 -0
- {uk_bin_collection-0.124.4.dist-info → uk_bin_collection-0.125.1.dist-info}/WHEEL +0 -0
- {uk_bin_collection-0.124.4.dist-info → uk_bin_collection-0.125.1.dist-info}/entry_points.txt +0 -0
@@ -194,6 +194,15 @@
|
|
194
194
|
"wiki_name": "Blackburn Council",
|
195
195
|
"wiki_note": "You will need to use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find the UPRN."
|
196
196
|
},
|
197
|
+
"BlaenauGwentCountyBoroughCouncil": {
|
198
|
+
"uprn": "100100471367",
|
199
|
+
"postcode": "NP23 7TE",
|
200
|
+
"skip_get_url": false,
|
201
|
+
"url": "https://www.blaenau-gwent.gov.uk",
|
202
|
+
"web_driver": "http://selenium:4444",
|
203
|
+
"wiki_name": "Blaenau Gwent County Borough Council",
|
204
|
+
"wiki_note": "You will need to use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find the UPRN."
|
205
|
+
},
|
197
206
|
"BoltonCouncil": {
|
198
207
|
"postcode": "BL1 5PQ",
|
199
208
|
"skip_get_url": true,
|
@@ -1403,6 +1412,13 @@
|
|
1403
1412
|
"wiki_name": "Reading Borough Council",
|
1404
1413
|
"wiki_note": "Replace XXXXXXXX with your property's UPRN."
|
1405
1414
|
},
|
1415
|
+
"RedditchBoroughCouncil": {
|
1416
|
+
"url": "https://redditchbc.gov.uk",
|
1417
|
+
"wiki_command_url_override": "https://redditchbc.gov.uk",
|
1418
|
+
"uprn": "10094557691",
|
1419
|
+
"wiki_name": "Redditch Borough Council",
|
1420
|
+
"wiki_note": "You will need to use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find the UPRN."
|
1421
|
+
},
|
1406
1422
|
"ReigateAndBansteadBoroughCouncil": {
|
1407
1423
|
"skip_get_url": true,
|
1408
1424
|
"uprn": "68134867",
|
@@ -1904,6 +1920,13 @@
|
|
1904
1920
|
"wiki_name": "Waltham Forest",
|
1905
1921
|
"wiki_note": "Use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find your UPRN."
|
1906
1922
|
},
|
1923
|
+
"WandsworthCouncil": {
|
1924
|
+
"url": "https://www.wandsworth.gov.uk",
|
1925
|
+
"wiki_command_url_override": "https://www.wandsworth.gov.uk",
|
1926
|
+
"uprn": "100022684035",
|
1927
|
+
"wiki_name": "Wandsworth Council",
|
1928
|
+
"wiki_note": "You will need to use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find the UPRN."
|
1929
|
+
},
|
1907
1930
|
"WarringtonBoroughCouncil": {
|
1908
1931
|
"url": "https://www.warrington.gov.uk",
|
1909
1932
|
"wiki_command_url_override": "https://www.warrington.gov.uk",
|
@@ -0,0 +1,113 @@
|
|
1
|
+
from bs4 import BeautifulSoup
|
2
|
+
from selenium.webdriver.common.by import By
|
3
|
+
from selenium.webdriver.support import expected_conditions as EC
|
4
|
+
from selenium.webdriver.support.ui import Select
|
5
|
+
from selenium.webdriver.support.wait import WebDriverWait
|
6
|
+
|
7
|
+
from uk_bin_collection.uk_bin_collection.common import *
|
8
|
+
from uk_bin_collection.uk_bin_collection.get_bin_data import AbstractGetBinDataClass
|
9
|
+
|
10
|
+
|
11
|
+
# import the wonderful Beautiful Soup and the URL grabber
|
12
|
+
class CouncilClass(AbstractGetBinDataClass):
|
13
|
+
"""
|
14
|
+
Concrete classes have to implement all abstract operations of the
|
15
|
+
base class. They can also override some operations with a default
|
16
|
+
implementation.
|
17
|
+
"""
|
18
|
+
|
19
|
+
def parse_data(self, page: str, **kwargs) -> dict:
|
20
|
+
driver = None
|
21
|
+
try:
|
22
|
+
data = {"bins": []}
|
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
|
+
check_postcode(user_postcode)
|
29
|
+
|
30
|
+
# Create Selenium webdriver
|
31
|
+
driver = create_webdriver(web_driver, headless, None, __name__)
|
32
|
+
driver.get(
|
33
|
+
"https://iportal.itouchvision.com/icollectionday/collection-day/?uuid=238D5F9796C12643D190E3505931401A8C003F0D&lang=en"
|
34
|
+
)
|
35
|
+
|
36
|
+
# Wait for the postcode field to appear then populate it
|
37
|
+
inputElement_postcode = WebDriverWait(driver, 10).until(
|
38
|
+
EC.presence_of_element_located((By.ID, "postcodeSearch"))
|
39
|
+
)
|
40
|
+
inputElement_postcode.send_keys(user_postcode)
|
41
|
+
|
42
|
+
# Click search button
|
43
|
+
findAddress = WebDriverWait(driver, 10).until(
|
44
|
+
EC.presence_of_element_located(
|
45
|
+
(By.XPATH, '//button[@class="govuk-button mt-4"]')
|
46
|
+
)
|
47
|
+
)
|
48
|
+
findAddress.click()
|
49
|
+
|
50
|
+
# Wait for the dropdown to be visible
|
51
|
+
WebDriverWait(driver, 10).until(
|
52
|
+
EC.presence_of_element_located((By.ID, "addressSelect"))
|
53
|
+
)
|
54
|
+
|
55
|
+
dropdown = Select(driver.find_element(By.ID, "addressSelect"))
|
56
|
+
dropdown.select_by_value(user_uprn)
|
57
|
+
|
58
|
+
# Wait for the collections table to appear
|
59
|
+
WebDriverWait(driver, 10).until(
|
60
|
+
EC.presence_of_element_located(
|
61
|
+
(
|
62
|
+
By.XPATH,
|
63
|
+
'//div[@class="ant-row d-flex justify-content-between mb-4 mt-2 css-2rgkd4"]',
|
64
|
+
)
|
65
|
+
)
|
66
|
+
)
|
67
|
+
|
68
|
+
soup = BeautifulSoup(driver.page_source, features="html.parser")
|
69
|
+
|
70
|
+
recyclingcalendar = soup.find(
|
71
|
+
"div",
|
72
|
+
{
|
73
|
+
"class": "ant-row d-flex justify-content-between mb-4 mt-2 css-2rgkd4"
|
74
|
+
},
|
75
|
+
)
|
76
|
+
|
77
|
+
rows = recyclingcalendar.find_all(
|
78
|
+
"div",
|
79
|
+
{
|
80
|
+
"class": "ant-col ant-col-xs-12 ant-col-sm-12 ant-col-md-12 ant-col-lg-12 ant-col-xl-12 css-2rgkd4"
|
81
|
+
},
|
82
|
+
)
|
83
|
+
|
84
|
+
current_year = datetime.now().year
|
85
|
+
current_month = datetime.now().month
|
86
|
+
|
87
|
+
for row in rows:
|
88
|
+
BinType = row.find("h3").text
|
89
|
+
collectiondate = datetime.strptime(
|
90
|
+
row.find("div", {"class": "text-white fw-bold"}).text,
|
91
|
+
"%A %d %B",
|
92
|
+
)
|
93
|
+
if (current_month > 10) and (collectiondate.month < 3):
|
94
|
+
collectiondate = collectiondate.replace(year=(current_year + 1))
|
95
|
+
else:
|
96
|
+
collectiondate = collectiondate.replace(year=current_year)
|
97
|
+
|
98
|
+
dict_data = {
|
99
|
+
"type": BinType,
|
100
|
+
"collectionDate": collectiondate.strftime("%d/%m/%Y"),
|
101
|
+
}
|
102
|
+
data["bins"].append(dict_data)
|
103
|
+
|
104
|
+
except Exception as e:
|
105
|
+
# Here you can log the exception if needed
|
106
|
+
print(f"An error occurred: {e}")
|
107
|
+
# Optionally, re-raise the exception if you want it to propagate
|
108
|
+
raise
|
109
|
+
finally:
|
110
|
+
# This block ensures that the driver is closed regardless of an exception
|
111
|
+
if driver:
|
112
|
+
driver.quit()
|
113
|
+
return data
|
@@ -43,6 +43,7 @@ class CouncilClass(AbstractGetBinDataClass):
|
|
43
43
|
rows = table.find_all("tr")
|
44
44
|
|
45
45
|
current_year = datetime.now().year
|
46
|
+
current_month = datetime.now().month
|
46
47
|
|
47
48
|
# Process each row into a list of dictionaries
|
48
49
|
for row in rows[1:]: # Skip the header row
|
@@ -56,7 +57,7 @@ class CouncilClass(AbstractGetBinDataClass):
|
|
56
57
|
if collection_date_text:
|
57
58
|
try:
|
58
59
|
collection_date = datetime.strptime(collection_date_text, "%a %d %b")
|
59
|
-
if collection_date.month == 1:
|
60
|
+
if collection_date.month == 1 and current_month != 1:
|
60
61
|
collection_date = collection_date.replace(year=current_year + 1)
|
61
62
|
else:
|
62
63
|
collection_date = collection_date.replace(year=current_year)
|
@@ -42,14 +42,18 @@ class CouncilClass(AbstractGetBinDataClass):
|
|
42
42
|
bin_type = service.get_text(
|
43
43
|
strip=True
|
44
44
|
) # Bin type name (e.g., 'Food waste', 'Mixed recycling')
|
45
|
-
if bin_type == "Bulky
|
45
|
+
if bin_type == "Bulky Waste":
|
46
46
|
continue
|
47
47
|
service_details = service.find_next("div", class_="govuk-grid-row")
|
48
48
|
|
49
49
|
next_collection = (
|
50
|
-
|
51
|
-
|
52
|
-
|
50
|
+
(
|
51
|
+
service_details.find("dt", string="Next collection")
|
52
|
+
.find_next_sibling("dd")
|
53
|
+
.get_text(strip=True)
|
54
|
+
)
|
55
|
+
.replace("(this collection has been adjusted from its usual time)", "")
|
56
|
+
.strip()
|
53
57
|
)
|
54
58
|
|
55
59
|
next_collection = datetime.strptime(
|
@@ -1,5 +1,6 @@
|
|
1
1
|
# This script pulls (in one hit) the data from Merton Council Bins Data
|
2
2
|
from bs4 import BeautifulSoup
|
3
|
+
|
3
4
|
from uk_bin_collection.uk_bin_collection.common import *
|
4
5
|
from uk_bin_collection.uk_bin_collection.get_bin_data import AbstractGetBinDataClass
|
5
6
|
|
@@ -33,6 +34,11 @@ class CouncilClass(AbstractGetBinDataClass):
|
|
33
34
|
),
|
34
35
|
)
|
35
36
|
|
37
|
+
possible_formats = [
|
38
|
+
"%d %B %Y",
|
39
|
+
"%A %d %B %Y",
|
40
|
+
]
|
41
|
+
|
36
42
|
# Loops the Rows
|
37
43
|
for row in rows:
|
38
44
|
# Get all the cells
|
@@ -40,9 +46,15 @@ class CouncilClass(AbstractGetBinDataClass):
|
|
40
46
|
# First cell is the bin_type
|
41
47
|
bin_type = cells[0].get_text().strip()
|
42
48
|
# Date is on the second cell, second paragraph, wrapped in p
|
43
|
-
collectionDate =
|
44
|
-
|
45
|
-
|
49
|
+
collectionDate = None
|
50
|
+
for date_format in possible_formats:
|
51
|
+
try:
|
52
|
+
collectionDate = datetime.strptime(
|
53
|
+
cells[1].select("p > b")[2].get_text(strip=True), date_format
|
54
|
+
)
|
55
|
+
break # Exit the loop if parsing is successful
|
56
|
+
except ValueError:
|
57
|
+
continue
|
46
58
|
|
47
59
|
# Add each collection to the list as a tuple
|
48
60
|
collections.append((bin_type, collectionDate))
|
@@ -0,0 +1,73 @@
|
|
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 = "https://bincollections.redditchbc.gov.uk/BinCollections/Details"
|
23
|
+
|
24
|
+
data = {"UPRN": user_uprn}
|
25
|
+
|
26
|
+
# Make the GET request
|
27
|
+
response = requests.post(URI, data=data)
|
28
|
+
|
29
|
+
# Parse the HTML
|
30
|
+
soup = BeautifulSoup(response.content, "html.parser")
|
31
|
+
|
32
|
+
# Find all collection containers
|
33
|
+
collection_containers = soup.find_all("div", class_="collection-container")
|
34
|
+
|
35
|
+
# Parse each collection container
|
36
|
+
for container in collection_containers:
|
37
|
+
# Extract bin type (from heading or image alt attribute)
|
38
|
+
bin_type = container.find("img")["alt"]
|
39
|
+
|
40
|
+
# Extract the next collection date (from the caption paragraph)
|
41
|
+
next_collection = (
|
42
|
+
container.find("p", class_="caption")
|
43
|
+
.text.replace("Next collection ", "")
|
44
|
+
.strip()
|
45
|
+
)
|
46
|
+
|
47
|
+
# Extract additional future collection dates (from the list items)
|
48
|
+
future_dates = [li.text.strip() for li in container.find_all("li")]
|
49
|
+
|
50
|
+
dict_data = {
|
51
|
+
"type": bin_type,
|
52
|
+
"collectionDate": datetime.strptime(
|
53
|
+
next_collection,
|
54
|
+
"%A, %d %B %Y",
|
55
|
+
).strftime("%d/%m/%Y"),
|
56
|
+
}
|
57
|
+
bindata["bins"].append(dict_data)
|
58
|
+
|
59
|
+
for date in future_dates: # Add to the schedule
|
60
|
+
dict_data = {
|
61
|
+
"type": bin_type,
|
62
|
+
"collectionDate": datetime.strptime(
|
63
|
+
date,
|
64
|
+
"%A, %d %B %Y",
|
65
|
+
).strftime("%d/%m/%Y"),
|
66
|
+
}
|
67
|
+
bindata["bins"].append(dict_data)
|
68
|
+
|
69
|
+
bindata["bins"].sort(
|
70
|
+
key=lambda x: datetime.strptime(x.get("collectionDate"), "%d/%m/%Y")
|
71
|
+
)
|
72
|
+
|
73
|
+
return bindata
|
@@ -1,6 +1,7 @@
|
|
1
1
|
from datetime import datetime
|
2
2
|
|
3
3
|
from bs4 import BeautifulSoup
|
4
|
+
|
4
5
|
from uk_bin_collection.uk_bin_collection.common import *
|
5
6
|
from uk_bin_collection.uk_bin_collection.get_bin_data import AbstractGetBinDataClass
|
6
7
|
|
@@ -14,20 +15,20 @@ class CouncilClass(AbstractGetBinDataClass):
|
|
14
15
|
"""
|
15
16
|
|
16
17
|
def parse_data(self, page: str, **kwargs) -> dict:
|
17
|
-
api_url = "https://www.salford.gov.uk/bins-and-recycling/bin-collection-days/your-bin-collections"
|
18
18
|
user_uprn = kwargs.get("uprn")
|
19
|
-
|
20
19
|
# Check the UPRN is valid
|
21
20
|
check_uprn(user_uprn)
|
22
21
|
|
23
|
-
|
24
|
-
|
25
|
-
|
22
|
+
api_url = f"https://www.salford.gov.uk/bins-and-recycling/bin-collection-days/your-bin-collections/?UPRN={user_uprn}"
|
23
|
+
|
24
|
+
headers = {
|
25
|
+
"User-Agent": "Mozilla/5.0",
|
26
|
+
"Referer": "https://www.salford.gov.uk/bins-and-recycling/bin-collection-days/",
|
26
27
|
}
|
27
28
|
|
28
29
|
# Make a request to the API
|
29
30
|
requests.packages.urllib3.disable_warnings()
|
30
|
-
response = requests.get(api_url,
|
31
|
+
response = requests.get(api_url, headers=headers)
|
31
32
|
|
32
33
|
# Make a BS4 object
|
33
34
|
soup = BeautifulSoup(response.text, features="html.parser")
|
@@ -26,7 +26,7 @@ class CouncilClass(AbstractGetBinDataClass):
|
|
26
26
|
check_paon(user_paon)
|
27
27
|
|
28
28
|
# Build URL to parse
|
29
|
-
council_url = "https://swale.gov.uk/bins-littering-and-the-environment/bins/
|
29
|
+
council_url = "https://swale.gov.uk/bins-littering-and-the-environment/bins/check-your-bin-day"
|
30
30
|
|
31
31
|
# Create Selenium webdriver
|
32
32
|
driver = create_webdriver(web_driver, headless, None, __name__)
|
@@ -35,7 +35,7 @@ class CouncilClass(AbstractGetBinDataClass):
|
|
35
35
|
# Wait for the postcode field to appear then populate it
|
36
36
|
try:
|
37
37
|
inputElement_postcode = WebDriverWait(driver, 10).until(
|
38
|
-
EC.presence_of_element_located((By.ID, "
|
38
|
+
EC.presence_of_element_located((By.ID, "q485476_q1"))
|
39
39
|
)
|
40
40
|
inputElement_postcode.send_keys(user_postcode)
|
41
41
|
except Exception:
|
@@ -43,7 +43,7 @@ class CouncilClass(AbstractGetBinDataClass):
|
|
43
43
|
|
44
44
|
# Click search button
|
45
45
|
findAddress = WebDriverWait(driver, 10).until(
|
46
|
-
EC.presence_of_element_located((By.ID, "
|
46
|
+
EC.presence_of_element_located((By.ID, "form_email_485465_submit"))
|
47
47
|
)
|
48
48
|
driver.execute_script("arguments[0].click();", findAddress)
|
49
49
|
|
@@ -52,7 +52,7 @@ class CouncilClass(AbstractGetBinDataClass):
|
|
52
52
|
EC.element_to_be_clickable(
|
53
53
|
(
|
54
54
|
By.XPATH,
|
55
|
-
"//select[@
|
55
|
+
"//select[@name='q485480:q1']//option[contains(., '"
|
56
56
|
+ user_paon
|
57
57
|
+ "')]",
|
58
58
|
)
|
@@ -61,12 +61,12 @@ class CouncilClass(AbstractGetBinDataClass):
|
|
61
61
|
|
62
62
|
# Click search button
|
63
63
|
getBins = WebDriverWait(driver, 10).until(
|
64
|
-
EC.presence_of_element_located((By.ID, "
|
64
|
+
EC.presence_of_element_located((By.ID, "form_email_485465_submit"))
|
65
65
|
)
|
66
66
|
driver.execute_script("arguments[0].click();", getBins)
|
67
67
|
|
68
68
|
BinTable = WebDriverWait(driver, 30).until(
|
69
|
-
EC.presence_of_element_located((By.ID, "
|
69
|
+
EC.presence_of_element_located((By.ID, "SBCYBDSummary"))
|
70
70
|
)
|
71
71
|
|
72
72
|
soup = BeautifulSoup(driver.page_source, features="html.parser")
|
@@ -74,17 +74,41 @@ class CouncilClass(AbstractGetBinDataClass):
|
|
74
74
|
|
75
75
|
data = {"bins": []}
|
76
76
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
77
|
+
next_collection_date = soup.find(
|
78
|
+
"strong", id="SBC-YBD-collectionDate"
|
79
|
+
).text.strip()
|
80
|
+
|
81
|
+
# Extract bins for the next collection
|
82
|
+
next_bins = [li.text.strip() for li in soup.select("#SBCFirstBins ul li")]
|
83
|
+
|
84
|
+
# Extract future collection details
|
85
|
+
future_collection_date_tag = soup.find(
|
86
|
+
"p", text=lambda t: t and "starting from" in t
|
87
|
+
)
|
88
|
+
future_collection_date = (
|
89
|
+
future_collection_date_tag.text.split("starting from")[-1].strip()
|
90
|
+
if future_collection_date_tag
|
91
|
+
else "No future date found"
|
92
|
+
)
|
93
|
+
|
94
|
+
future_bins = [li.text.strip() for li in soup.select("#FirstFutureBins li")]
|
95
|
+
|
96
|
+
for bin in next_bins:
|
97
|
+
dict_data = {
|
98
|
+
"type": bin,
|
99
|
+
"collectionDate": datetime.strptime(
|
100
|
+
next_collection_date, "%A, %d %B"
|
101
|
+
).strftime(date_format),
|
102
|
+
}
|
103
|
+
data["bins"].append(dict_data)
|
104
|
+
|
105
|
+
for bin in future_bins:
|
106
|
+
dict_data = {
|
107
|
+
"type": bin,
|
108
|
+
"collectionDate": datetime.strptime(
|
109
|
+
future_collection_date, "%A, %d %B"
|
110
|
+
).strftime(date_format),
|
111
|
+
}
|
112
|
+
data["bins"].append(dict_data)
|
89
113
|
|
90
114
|
return data
|
@@ -0,0 +1,74 @@
|
|
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://www.wandsworth.gov.uk/my-property/?UPRN={user_uprn}"
|
23
|
+
|
24
|
+
# Make the GET request
|
25
|
+
response = requests.get(URI)
|
26
|
+
|
27
|
+
soup = BeautifulSoup(response.content, features="html.parser")
|
28
|
+
soup.prettify()
|
29
|
+
|
30
|
+
# Find all collection types
|
31
|
+
collection_types = soup.find_all("h4", class_="collection-heading")
|
32
|
+
|
33
|
+
# Iterate over each collection type
|
34
|
+
for collection_type in collection_types:
|
35
|
+
bin_types = collection_type.text.strip().split("/")
|
36
|
+
collections = collection_type.find_next_sibling("div", class_="collections")
|
37
|
+
|
38
|
+
# Extract next and previous collections
|
39
|
+
next_collection = collections.find_all("div", class_="collection")
|
40
|
+
|
41
|
+
# Parse each collection
|
42
|
+
for collection in next_collection:
|
43
|
+
# Extract the collection type (Next or Previous)
|
44
|
+
strong_tag = collection.find("strong")
|
45
|
+
collection_type = (
|
46
|
+
strong_tag.text.strip(":") if strong_tag else "Unknown"
|
47
|
+
)
|
48
|
+
|
49
|
+
# Extract the date
|
50
|
+
date_text = (
|
51
|
+
strong_tag.next_sibling.strip()
|
52
|
+
if strong_tag and strong_tag.next_sibling
|
53
|
+
else "No date found"
|
54
|
+
)
|
55
|
+
|
56
|
+
if date_text == "No date found":
|
57
|
+
continue
|
58
|
+
|
59
|
+
for bin_type in bin_types:
|
60
|
+
# Append to the schedule
|
61
|
+
dict_data = {
|
62
|
+
"type": bin_type,
|
63
|
+
"collectionDate": datetime.strptime(
|
64
|
+
date_text,
|
65
|
+
"%A %d %B %Y",
|
66
|
+
).strftime(date_format),
|
67
|
+
}
|
68
|
+
bindata["bins"].append(dict_data)
|
69
|
+
|
70
|
+
bindata["bins"].sort(
|
71
|
+
key=lambda x: datetime.strptime(x.get("collectionDate"), date_format)
|
72
|
+
)
|
73
|
+
|
74
|
+
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=qDLpDG3LuoOhCLAevSKI4FrALTaLu6IHzmiAv827Jqk,112991
|
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
|
@@ -37,6 +37,7 @@ uk_bin_collection/uk_bin_collection/councils/BexleyCouncil.py,sha256=wqqCQZzu_q_
|
|
37
37
|
uk_bin_collection/uk_bin_collection/councils/BirminghamCityCouncil.py,sha256=now2xgpfshYM33UWC18j6xa6BuBydO5Sl7OrDQOo6b0,4687
|
38
38
|
uk_bin_collection/uk_bin_collection/councils/BlabyDistrictCouncil.py,sha256=xqWkQz3HDLkP5TgxQqVJziHJF2yl-q9PcV3Rv-38xDU,1941
|
39
39
|
uk_bin_collection/uk_bin_collection/councils/BlackburnCouncil.py,sha256=ZLA2V3qPsJTom7SeQdGDhF4tJSfgIV5Qi202QvGKJZ0,4477
|
40
|
+
uk_bin_collection/uk_bin_collection/councils/BlaenauGwentCountyBoroughCouncil.py,sha256=C5Fi19t5HJcrOHhWnt_6pttgRL2IWIYnwYlF9MdSPR0,4330
|
40
41
|
uk_bin_collection/uk_bin_collection/councils/BoltonCouncil.py,sha256=WI68r8jB0IHPUT4CgmZMtng899AAMFTxkyTdPg9yLF8,4117
|
41
42
|
uk_bin_collection/uk_bin_collection/councils/BracknellForestCouncil.py,sha256=Llo1rULaAZ8rChVYZqXFFLo7CN6vbT0ULUJD6ActouY,9015
|
42
43
|
uk_bin_collection/uk_bin_collection/councils/BradfordMDC.py,sha256=BEWS2c62cOsf26jqn1AkNUvVmc5AlUADYLaQuPn9RY4,5456
|
@@ -46,7 +47,7 @@ uk_bin_collection/uk_bin_collection/councils/BrightonandHoveCityCouncil.py,sha25
|
|
46
47
|
uk_bin_collection/uk_bin_collection/councils/BristolCityCouncil.py,sha256=kJmmDJz_kQ45DHmG7ocrUpNJonEn0kuXYEDQyZaf9ks,5576
|
47
48
|
uk_bin_collection/uk_bin_collection/councils/BromleyBoroughCouncil.py,sha256=_bAFykZWZkEVUB-QKeVLfWO8plG6nRgn71QF2BUN2rk,4329
|
48
49
|
uk_bin_collection/uk_bin_collection/councils/BromsgroveDistrictCouncil.py,sha256=PUfxP8j5Oh9wFHkdjbrJzQli9UzMHZzwrZ2hkThrvhI,1781
|
49
|
-
uk_bin_collection/uk_bin_collection/councils/BroxbourneCouncil.py,sha256=
|
50
|
+
uk_bin_collection/uk_bin_collection/councils/BroxbourneCouncil.py,sha256=NR1FoxLF0Ne61cJJmlVJhGfxjZ2sj60aLlOHBWWxtrM,2921
|
50
51
|
uk_bin_collection/uk_bin_collection/councils/BroxtoweBoroughCouncil.py,sha256=-Facq-ToQkcWUePpKBwq90LZUFxgUSydNL2sYaLX4yw,4473
|
51
52
|
uk_bin_collection/uk_bin_collection/councils/BuckinghamshireCouncil.py,sha256=_ELVUM5VLp1nwDxRpvpsp6n8SzLJvp_UyMp-i_MXYuo,4383
|
52
53
|
uk_bin_collection/uk_bin_collection/councils/BurnleyBoroughCouncil.py,sha256=GJf1OPvUVj3vqsR3KjG0DFHZrSBu4ogIz_MJeVV8tNA,3192
|
@@ -145,13 +146,13 @@ uk_bin_collection/uk_bin_collection/councils/LondonBoroughHounslow.py,sha256=UOe
|
|
145
146
|
uk_bin_collection/uk_bin_collection/councils/LondonBoroughLambeth.py,sha256=r9D5lHe5kIRStCd5lRIax16yhb4KTFzzfYEFv1bacWw,2009
|
146
147
|
uk_bin_collection/uk_bin_collection/councils/LondonBoroughLewisham.py,sha256=d8rlJDTbY3nj-Zjg6iwvwfe-X13Gq86DGGW6QkQAUW0,5310
|
147
148
|
uk_bin_collection/uk_bin_collection/councils/LondonBoroughRedbridge.py,sha256=A_6Sis5hsF53Th04KeadHRasGbpAm6aoaWJ6X8eC4Y8,6604
|
148
|
-
uk_bin_collection/uk_bin_collection/councils/LondonBoroughSutton.py,sha256=
|
149
|
+
uk_bin_collection/uk_bin_collection/councils/LondonBoroughSutton.py,sha256=GAE51GfLk6lBWBiHzon7Egvlcds63bL_nK2jBlAMzs8,2530
|
149
150
|
uk_bin_collection/uk_bin_collection/councils/LutonBoroughCouncil.py,sha256=vScUi_R8FnBddii2_zLlZBLxuh85mKmCm8nKW3zxky0,2758
|
150
151
|
uk_bin_collection/uk_bin_collection/councils/MaldonDistrictCouncil.py,sha256=PMVt2XFggttPmbWyrBrHJ-W6R_6-0ux1BkY1kj1IKzg,1997
|
151
152
|
uk_bin_collection/uk_bin_collection/councils/MalvernHillsDC.py,sha256=iQG0EkX2npBicvsGKQRYyBGSBvKVUbKvUvvwrC9xV1A,2100
|
152
153
|
uk_bin_collection/uk_bin_collection/councils/ManchesterCityCouncil.py,sha256=RY301_82z3-xInGai5ocT7rzoV75ATbf0N7uxn8Z9LE,3110
|
153
154
|
uk_bin_collection/uk_bin_collection/councils/MansfieldDistrictCouncil.py,sha256=F5AiTxImrnjE1k3ry96bfstOf5XSNBJS_4qqmymmh3w,1386
|
154
|
-
uk_bin_collection/uk_bin_collection/councils/MertonCouncil.py,sha256=
|
155
|
+
uk_bin_collection/uk_bin_collection/councils/MertonCouncil.py,sha256=VGN4L7rq9D_nJ7i15aMioyZsoiA0Bu0RhZToBiajkr0,2350
|
155
156
|
uk_bin_collection/uk_bin_collection/councils/MidAndEastAntrimBoroughCouncil.py,sha256=oOWwU5FSgGej2Mv7FQ66N-EzS5nZgmGsd0WnfLWUc1I,5238
|
156
157
|
uk_bin_collection/uk_bin_collection/councils/MidDevonCouncil.py,sha256=RjBZ7R3_Pax9p1d2DCygqryjV1RP4BYvqb-rT_KyOEg,3322
|
157
158
|
uk_bin_collection/uk_bin_collection/councils/MidSuffolkDistrictCouncil.py,sha256=h6M-v5jVYe7OlQ47Vf-0pEgECZLOOacK3_XE6zbpsM4,6329
|
@@ -193,6 +194,7 @@ uk_bin_collection/uk_bin_collection/councils/PortsmouthCityCouncil.py,sha256=xog
|
|
193
194
|
uk_bin_collection/uk_bin_collection/councils/PowysCouncil.py,sha256=E6AGmbU3GfmScrpS-hrnCz4uOwucmckq4R-hLmq80b8,5004
|
194
195
|
uk_bin_collection/uk_bin_collection/councils/PrestonCityCouncil.py,sha256=3Nuin2hQsiEsbJR_kHldtzRhzmnPFctH7C7MFG7thj8,3838
|
195
196
|
uk_bin_collection/uk_bin_collection/councils/ReadingBoroughCouncil.py,sha256=ZlQjU0IeKylGE9VlivSMh4XKwoLgntESPiylSOYkuD4,1009
|
197
|
+
uk_bin_collection/uk_bin_collection/councils/RedditchBoroughCouncil.py,sha256=8QmcpStCT7c-CLhmiQ8ZeEyvtysU110VDiMQdfQTErk,2469
|
196
198
|
uk_bin_collection/uk_bin_collection/councils/ReigateAndBansteadBoroughCouncil.py,sha256=HMLKdRUO5DdMJe1d1X5qtKtQsf6d5TAPViIZpMzAfes,3251
|
197
199
|
uk_bin_collection/uk_bin_collection/councils/RenfrewshireCouncil.py,sha256=VlWm-w4d-UchoENe_hCTCGlfSHiMlS4wNEeMvxuNR2U,5109
|
198
200
|
uk_bin_collection/uk_bin_collection/councils/RhonddaCynonTaffCouncil.py,sha256=wInyVG_0wRrX_dRO9qbAzPhlXDseXapj2zQhsISw8gg,3233
|
@@ -204,7 +206,7 @@ uk_bin_collection/uk_bin_collection/councils/RoyalBoroughofGreenwich.py,sha256=B
|
|
204
206
|
uk_bin_collection/uk_bin_collection/councils/RugbyBoroughCouncil.py,sha256=a5ySLmFvvY56QMA7-bk6MVBxRp5tPBIBg4navH0eYas,4306
|
205
207
|
uk_bin_collection/uk_bin_collection/councils/RushcliffeBoroughCouncil.py,sha256=wMtiYRirT585vtsEOIyXHugk7aEj3pvyVWBaAePdqtE,4005
|
206
208
|
uk_bin_collection/uk_bin_collection/councils/RushmoorCouncil.py,sha256=ZsGnXjoEaOS6U7fI0w7-uqxayAHdNVKsJi2fqIWEls8,3375
|
207
|
-
uk_bin_collection/uk_bin_collection/councils/SalfordCityCouncil.py,sha256=
|
209
|
+
uk_bin_collection/uk_bin_collection/councils/SalfordCityCouncil.py,sha256=XUGemp2cdzsvkWjnv2m4YKTMcoKDUfIlVy3YucX-_o4,2601
|
208
210
|
uk_bin_collection/uk_bin_collection/councils/SandwellBoroughCouncil.py,sha256=shJhvqDcha2ypDCSfhss59G95jNaWBuMnVIxJiZXcY8,3110
|
209
211
|
uk_bin_collection/uk_bin_collection/councils/SeftonCouncil.py,sha256=XUEz2li0oHrRhdkls5qzlZNZ0GuwSG7r0dwsL-qdoFA,2480
|
210
212
|
uk_bin_collection/uk_bin_collection/councils/SevenoaksDistrictCouncil.py,sha256=qqrrRaSVm9CYAtm0rB2ZnyH_nLwaReuacoUxZpo597k,4260
|
@@ -236,7 +238,7 @@ uk_bin_collection/uk_bin_collection/councils/StokeOnTrentCityCouncil.py,sha256=K
|
|
236
238
|
uk_bin_collection/uk_bin_collection/councils/StratfordUponAvonCouncil.py,sha256=DMTAcXT_lay8Cl1hBbzf_LN7-GwTDGxT3Ug9QJkaF9Y,3936
|
237
239
|
uk_bin_collection/uk_bin_collection/councils/StroudDistrictCouncil.py,sha256=9bYWppi7ViLGHL4VEg--nFn28MLYJYbiEntull1uZxU,3561
|
238
240
|
uk_bin_collection/uk_bin_collection/councils/SunderlandCityCouncil.py,sha256=4DnKyyu56_AwuchD6_oL1dvpDStMvkkxQtYN79rUKOs,3825
|
239
|
-
uk_bin_collection/uk_bin_collection/councils/SwaleBoroughCouncil.py,sha256=
|
241
|
+
uk_bin_collection/uk_bin_collection/councils/SwaleBoroughCouncil.py,sha256=wxoUAaeng1pf9nJ3Q12Xthcz0_LoS7SI86y0Hfv8hsM,4107
|
240
242
|
uk_bin_collection/uk_bin_collection/councils/SwanseaCouncil.py,sha256=nmVPoPhnFgVi--vczX2i4Sf3bqM5RWJuwfhioRUr5XE,2303
|
241
243
|
uk_bin_collection/uk_bin_collection/councils/SwindonBoroughCouncil.py,sha256=lSIykpkBjVwQSf3rrnrNuh7YRepgnkKQLbf1iErMuJs,1932
|
242
244
|
uk_bin_collection/uk_bin_collection/councils/TamesideMBCouncil.py,sha256=k2TAAZG7n2S1BWVyxbE_-4-lZuzhOimCNz4yimUCOGk,1995
|
@@ -258,6 +260,7 @@ uk_bin_collection/uk_bin_collection/councils/ValeofWhiteHorseCouncil.py,sha256=K
|
|
258
260
|
uk_bin_collection/uk_bin_collection/councils/WakefieldCityCouncil.py,sha256=vRfIU0Uloi1bgXqjOCpdb-EQ4oY-aismcANZRwOIFkc,4914
|
259
261
|
uk_bin_collection/uk_bin_collection/councils/WalsallCouncil.py,sha256=_anovUnXMr40lZLHyX3opIP73BwauCllKy-Z2SBrzPw,2076
|
260
262
|
uk_bin_collection/uk_bin_collection/councils/WalthamForest.py,sha256=P7MMw0EhpRmDbbnHb25tY5_yvYuZUFwJ1br4TOv24sY,4997
|
263
|
+
uk_bin_collection/uk_bin_collection/councils/WandsworthCouncil.py,sha256=aQoJpC7YkhKewQyZlsv5m4__2IPoKRsOrPxjNH5xRNo,2594
|
261
264
|
uk_bin_collection/uk_bin_collection/councils/WarringtonBoroughCouncil.py,sha256=AB9mrV1v4pKKhfsBS8MpjO8XXBifqojSk53J9Q74Guk,1583
|
262
265
|
uk_bin_collection/uk_bin_collection/councils/WarwickDistrictCouncil.py,sha256=DAL_f0BcIxFj7Ngkms5Q80kgSGp9y5zB35wRPudayz8,1644
|
263
266
|
uk_bin_collection/uk_bin_collection/councils/WatfordBoroughCouncil.py,sha256=zFkXmF1X5g8pjv7II_jXBdrHJu16gy_PowVWVdaDg7A,2657
|
@@ -273,7 +276,7 @@ uk_bin_collection/uk_bin_collection/councils/WestNorthamptonshireCouncil.py,sha2
|
|
273
276
|
uk_bin_collection/uk_bin_collection/councils/WestOxfordshireDistrictCouncil.py,sha256=bkE7BUwRIEJQyfOHyXYeaJB1ruGTFu9LHIGursIBEIQ,4859
|
274
277
|
uk_bin_collection/uk_bin_collection/councils/WestSuffolkCouncil.py,sha256=9i8AQHh-qIRPZ_5Ad97_h04-qgyLQDPV064obBzab1Y,2587
|
275
278
|
uk_bin_collection/uk_bin_collection/councils/WiganBoroughCouncil.py,sha256=3gqFA4-BVx_In6QOu3KUNqPN4Fkn9iMlZTeopMK9p6A,3746
|
276
|
-
uk_bin_collection/uk_bin_collection/councils/WiltshireCouncil.py,sha256=
|
279
|
+
uk_bin_collection/uk_bin_collection/councils/WiltshireCouncil.py,sha256=Q0ooHTQb9ynMXpSNBPk7XXEjI7zcHst3id4wxGdmVx4,5698
|
277
280
|
uk_bin_collection/uk_bin_collection/councils/WinchesterCityCouncil.py,sha256=W2k00N5n9-1MzjMEqsNjldsQdOJPEPMjK7OGSinZm5Y,4335
|
278
281
|
uk_bin_collection/uk_bin_collection/councils/WindsorAndMaidenheadCouncil.py,sha256=7Qhznj95ktAQjpWm5C8pbD5UcvfXm7Mwb7_DQxwjGSM,1777
|
279
282
|
uk_bin_collection/uk_bin_collection/councils/WirralCouncil.py,sha256=X_e9zXEZAl_Mp6nPORHc9CTmf3QHdoMY3BCnKrXEr1I,2131
|
@@ -288,8 +291,8 @@ uk_bin_collection/uk_bin_collection/councils/YorkCouncil.py,sha256=I2kBYMlsD4bId
|
|
288
291
|
uk_bin_collection/uk_bin_collection/councils/council_class_template/councilclasstemplate.py,sha256=EQWRhZ2pEejlvm0fPyOTsOHKvUZmPnxEYO_OWRGKTjs,1158
|
289
292
|
uk_bin_collection/uk_bin_collection/create_new_council.py,sha256=m-IhmWmeWQlFsTZC4OxuFvtw5ZtB8EAJHxJTH4O59lQ,1536
|
290
293
|
uk_bin_collection/uk_bin_collection/get_bin_data.py,sha256=YvmHfZqanwrJ8ToGch34x-L-7yPe31nB_x77_Mgl_vo,4545
|
291
|
-
uk_bin_collection-0.
|
292
|
-
uk_bin_collection-0.
|
293
|
-
uk_bin_collection-0.
|
294
|
-
uk_bin_collection-0.
|
295
|
-
uk_bin_collection-0.
|
294
|
+
uk_bin_collection-0.125.1.dist-info/LICENSE,sha256=vABBUOzcrgfaTKpzeo-si9YVEun6juDkndqA8RKdKGs,1071
|
295
|
+
uk_bin_collection-0.125.1.dist-info/METADATA,sha256=RqQZJY1B8okVHVvD-cb2gifYlxj1PEc_OoR60DY-LCc,17574
|
296
|
+
uk_bin_collection-0.125.1.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
|
297
|
+
uk_bin_collection-0.125.1.dist-info/entry_points.txt,sha256=36WCSGMWSc916S3Hi1ZkazzDKHaJ6CD-4fCEFm5MIao,90
|
298
|
+
uk_bin_collection-0.125.1.dist-info/RECORD,,
|
File without changes
|
File without changes
|
{uk_bin_collection-0.124.4.dist-info → uk_bin_collection-0.125.1.dist-info}/entry_points.txt
RENAMED
File without changes
|