uk_bin_collection 0.140.0__py3-none-any.whl → 0.141.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- uk_bin_collection/tests/input.json +9 -0
- uk_bin_collection/uk_bin_collection/councils/PeterboroughCityCouncil.py +167 -0
- {uk_bin_collection-0.140.0.dist-info → uk_bin_collection-0.141.0.dist-info}/METADATA +1 -1
- {uk_bin_collection-0.140.0.dist-info → uk_bin_collection-0.141.0.dist-info}/RECORD +7 -6
- {uk_bin_collection-0.140.0.dist-info → uk_bin_collection-0.141.0.dist-info}/LICENSE +0 -0
- {uk_bin_collection-0.140.0.dist-info → uk_bin_collection-0.141.0.dist-info}/WHEEL +0 -0
- {uk_bin_collection-0.140.0.dist-info → uk_bin_collection-0.141.0.dist-info}/entry_points.txt +0 -0
@@ -1493,6 +1493,15 @@
|
|
1493
1493
|
"wiki_name": "Oxford City Council",
|
1494
1494
|
"wiki_note": "You will need to use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find the UPRN."
|
1495
1495
|
},
|
1496
|
+
"PeterboroughCityCouncil": {
|
1497
|
+
"house_number": "7 Arundel Road, Peterborough, PE4 6JJ",
|
1498
|
+
"postcode": "PE4 6JJ",
|
1499
|
+
"skip_get_url": true,
|
1500
|
+
"url": "https://report.peterborough.gov.uk/waste",
|
1501
|
+
"web_driver": "http://selenium:4444",
|
1502
|
+
"wiki_name": "Peterborough City Council",
|
1503
|
+
"wiki_note": "Pass the full address as it appears o nthe Peterborough website and postcode in their respective parameters. This parser requires a Selenium webdriver."
|
1504
|
+
},
|
1496
1505
|
"PerthAndKinrossCouncil": {
|
1497
1506
|
"uprn": "124032322",
|
1498
1507
|
"url": "https://www.pkc.gov.uk",
|
@@ -0,0 +1,167 @@
|
|
1
|
+
import time
|
2
|
+
|
3
|
+
from bs4 import BeautifulSoup
|
4
|
+
from selenium.webdriver.common.by import By
|
5
|
+
from selenium.webdriver.support import expected_conditions as EC
|
6
|
+
from selenium.webdriver.support.ui import Select, WebDriverWait
|
7
|
+
|
8
|
+
from uk_bin_collection.uk_bin_collection.common import *
|
9
|
+
from uk_bin_collection.uk_bin_collection.get_bin_data import AbstractGetBinDataClass
|
10
|
+
|
11
|
+
|
12
|
+
# import the wonderful Beautiful Soup and the URL grabber
|
13
|
+
class CouncilClass(AbstractGetBinDataClass):
|
14
|
+
"""
|
15
|
+
Concrete classes have to implement all abstract operations of the
|
16
|
+
base class. They can also override some operations with a default
|
17
|
+
implementation.
|
18
|
+
"""
|
19
|
+
|
20
|
+
def parse_data(self, page: str, **kwargs) -> dict:
|
21
|
+
driver = None
|
22
|
+
try:
|
23
|
+
user_poan = kwargs.get("paon")
|
24
|
+
user_postcode = kwargs.get("postcode")
|
25
|
+
if not user_postcode:
|
26
|
+
raise ValueError("No postcode provided.")
|
27
|
+
check_postcode(user_postcode)
|
28
|
+
|
29
|
+
headless = kwargs.get("headless")
|
30
|
+
web_driver = kwargs.get("web_driver")
|
31
|
+
driver = create_webdriver(web_driver, headless, None, __name__)
|
32
|
+
page = "https://report.peterborough.gov.uk/waste"
|
33
|
+
|
34
|
+
driver.get(page)
|
35
|
+
|
36
|
+
wait = WebDriverWait(driver, 30)
|
37
|
+
|
38
|
+
try:
|
39
|
+
# Cookies confirmed working in selenium
|
40
|
+
accept_cookies_button = wait.until(
|
41
|
+
EC.element_to_be_clickable(
|
42
|
+
(
|
43
|
+
By.XPATH,
|
44
|
+
"//button/span[contains(text(), 'I Accept Cookies')]",
|
45
|
+
)
|
46
|
+
)
|
47
|
+
)
|
48
|
+
accept_cookies_button.click()
|
49
|
+
except:
|
50
|
+
print(
|
51
|
+
"Accept cookies banner not found or clickable within the specified time."
|
52
|
+
)
|
53
|
+
pass
|
54
|
+
|
55
|
+
postcode_input = wait.until(
|
56
|
+
EC.presence_of_element_located((By.XPATH, '//input[@id="postcode"]'))
|
57
|
+
)
|
58
|
+
|
59
|
+
postcode_input.send_keys(user_postcode)
|
60
|
+
|
61
|
+
postcode_go_button = wait.until(
|
62
|
+
EC.element_to_be_clickable((By.XPATH, '//input[@id="go"]'))
|
63
|
+
)
|
64
|
+
|
65
|
+
postcode_go_button.click()
|
66
|
+
|
67
|
+
# Wait for the select address drop down to be present
|
68
|
+
select_address_input = wait.until(
|
69
|
+
EC.presence_of_element_located((By.XPATH, '//input[@id="address"]'))
|
70
|
+
)
|
71
|
+
|
72
|
+
select_address_input.click()
|
73
|
+
time.sleep(2)
|
74
|
+
|
75
|
+
select_address_input_item = wait.until(
|
76
|
+
EC.presence_of_element_located(
|
77
|
+
(By.XPATH, f"//li[contains(text(), '{user_poan}')]")
|
78
|
+
)
|
79
|
+
)
|
80
|
+
|
81
|
+
select_address_input_item.click()
|
82
|
+
|
83
|
+
address_continue_button = wait.until(
|
84
|
+
EC.element_to_be_clickable((By.XPATH, '//input[@value="Continue"]'))
|
85
|
+
)
|
86
|
+
|
87
|
+
address_continue_button.click()
|
88
|
+
|
89
|
+
your_collections_heading = wait.until(
|
90
|
+
EC.presence_of_element_located(
|
91
|
+
(By.XPATH, "//h2[contains(text(), 'Your collections')]")
|
92
|
+
)
|
93
|
+
)
|
94
|
+
|
95
|
+
results_page = wait.until(
|
96
|
+
EC.presence_of_element_located(
|
97
|
+
(By.XPATH, "//div[@class='waste__collections']")
|
98
|
+
)
|
99
|
+
)
|
100
|
+
|
101
|
+
soup = BeautifulSoup(results_page.get_attribute("innerHTML"), "html.parser")
|
102
|
+
|
103
|
+
data = {"bins": []}
|
104
|
+
output_date_format = "%d/%m/%Y"
|
105
|
+
input_date_format = "%A, %d %B %Y" # Expect: Thursday, 17 April 2025
|
106
|
+
|
107
|
+
# Each bin section is within a waste-service-wrapper div
|
108
|
+
collection_panels = soup.find_all("div", class_="waste-service-wrapper")
|
109
|
+
|
110
|
+
for panel in collection_panels:
|
111
|
+
try:
|
112
|
+
# Bin type
|
113
|
+
bin_type_tag = panel.find("h3", class_="waste-service-name")
|
114
|
+
if not bin_type_tag:
|
115
|
+
continue
|
116
|
+
bin_type = bin_type_tag.get_text(strip=True)
|
117
|
+
|
118
|
+
# Get 'Next collection' date
|
119
|
+
rows = panel.find_all("div", class_="govuk-summary-list__row")
|
120
|
+
next_collection = None
|
121
|
+
for row in rows:
|
122
|
+
key = row.find("dt", class_="govuk-summary-list__key")
|
123
|
+
value = row.find("dd", class_="govuk-summary-list__value")
|
124
|
+
if key and value and "Next collection" in key.get_text():
|
125
|
+
raw_date = " ".join(value.get_text().split())
|
126
|
+
|
127
|
+
# ✅ Remove st/nd/rd/th suffix from the day (e.g. 17th → 17)
|
128
|
+
cleaned_date = re.sub(
|
129
|
+
r"(\d{1,2})(st|nd|rd|th)", r"\1", raw_date
|
130
|
+
)
|
131
|
+
next_collection = cleaned_date
|
132
|
+
break
|
133
|
+
|
134
|
+
if not next_collection:
|
135
|
+
continue
|
136
|
+
|
137
|
+
print(f"Found next collection for {bin_type}: '{next_collection}'")
|
138
|
+
|
139
|
+
parsed_date = datetime.strptime(next_collection, input_date_format)
|
140
|
+
formatted_date = parsed_date.strftime(output_date_format)
|
141
|
+
|
142
|
+
data["bins"].append(
|
143
|
+
{
|
144
|
+
"type": bin_type,
|
145
|
+
"collectionDate": formatted_date,
|
146
|
+
}
|
147
|
+
)
|
148
|
+
|
149
|
+
except Exception as e:
|
150
|
+
print(
|
151
|
+
f"Error processing panel for bin '{bin_type if 'bin_type' in locals() else 'unknown'}': {e}"
|
152
|
+
)
|
153
|
+
|
154
|
+
# Sort the data
|
155
|
+
data["bins"].sort(
|
156
|
+
key=lambda x: datetime.strptime(x["collectionDate"], output_date_format)
|
157
|
+
)
|
158
|
+
except Exception as e:
|
159
|
+
# Here you can log the exception if needed
|
160
|
+
print(f"An error occurred: {e}")
|
161
|
+
# Optionally, re-raise the exception if you want it to propagate
|
162
|
+
raise
|
163
|
+
finally:
|
164
|
+
# This block ensures that the driver is closed regardless of an exception
|
165
|
+
if driver:
|
166
|
+
driver.quit()
|
167
|
+
return data
|
@@ -3,7 +3,7 @@ uk_bin_collection/tests/check_selenium_url_in_input.json.py,sha256=Iecdja0I3XIiY
|
|
3
3
|
uk_bin_collection/tests/council_feature_input_parity.py,sha256=DO6Mk4ImYgM5ZCZ-cutwz5RoYYWZRLYx2tr6zIs_9Rc,3843
|
4
4
|
uk_bin_collection/tests/features/environment.py,sha256=VQZjJdJI_kZn08M0j5cUgvKT4k3iTw8icJge1DGOkoA,127
|
5
5
|
uk_bin_collection/tests/features/validate_council_outputs.feature,sha256=SJK-Vc737hrf03tssxxbeg_JIvAH-ddB8f6gU1LTbuQ,251
|
6
|
-
uk_bin_collection/tests/input.json,sha256=
|
6
|
+
uk_bin_collection/tests/input.json,sha256=uvi5_CrjVy26H4gkWdoRXCJ1wsJPgntzJB26hXwC5jI,120556
|
7
7
|
uk_bin_collection/tests/output.schema,sha256=ZwKQBwYyTDEM4G2hJwfLUVM-5v1vKRvRK9W9SS1sd18,1086
|
8
8
|
uk_bin_collection/tests/step_defs/step_helpers/file_handler.py,sha256=Ygzi4V0S1MIHqbdstUlIqtRIwnynvhu4UtpweJ6-5N8,1474
|
9
9
|
uk_bin_collection/tests/step_defs/test_validate_council.py,sha256=VZ0a81sioJULD7syAYHjvK_-nT_Rd36tUyzPetSA0gk,3475
|
@@ -216,6 +216,7 @@ uk_bin_collection/uk_bin_collection/councils/OadbyAndWigstonBoroughCouncil.py,sh
|
|
216
216
|
uk_bin_collection/uk_bin_collection/councils/OldhamCouncil.py,sha256=9dlesCxNoVXlmQaqZj7QFh00smnJbm1Gnjkr_Uvzurs,1771
|
217
217
|
uk_bin_collection/uk_bin_collection/councils/OxfordCityCouncil.py,sha256=d_bY0cXRDH4kSoWGGCTNN61MNErapSOf2WSTYDJr2r8,2318
|
218
218
|
uk_bin_collection/uk_bin_collection/councils/PerthAndKinrossCouncil.py,sha256=Kos5GzN2co3Ij3tSHOXB9S71Yt78RROCfVRtnh7M1VU,3657
|
219
|
+
uk_bin_collection/uk_bin_collection/councils/PeterboroughCityCouncil.py,sha256=lOrDD4jfJ-_C5UwCGqRcQ1G-U1F5X6rf255ypzYEBcg,6300
|
219
220
|
uk_bin_collection/uk_bin_collection/councils/PlymouthCouncil.py,sha256=FJqpJ0GJhpjYeyZ9ioZPkKGl-zrqMD3y5iKa07e_i30,3202
|
220
221
|
uk_bin_collection/uk_bin_collection/councils/PortsmouthCityCouncil.py,sha256=xogNgVvwM5FljCziiNLgZ_wzkOnrQkifi1dkPMDRMtg,5588
|
221
222
|
uk_bin_collection/uk_bin_collection/councils/PowysCouncil.py,sha256=db3Y5FJz-LFDqmVZqPdzcBxh0Q26OFPrbUxlQ7r4vsQ,5896
|
@@ -325,8 +326,8 @@ uk_bin_collection/uk_bin_collection/councils/YorkCouncil.py,sha256=I2kBYMlsD4bId
|
|
325
326
|
uk_bin_collection/uk_bin_collection/councils/council_class_template/councilclasstemplate.py,sha256=EQWRhZ2pEejlvm0fPyOTsOHKvUZmPnxEYO_OWRGKTjs,1158
|
326
327
|
uk_bin_collection/uk_bin_collection/create_new_council.py,sha256=m-IhmWmeWQlFsTZC4OxuFvtw5ZtB8EAJHxJTH4O59lQ,1536
|
327
328
|
uk_bin_collection/uk_bin_collection/get_bin_data.py,sha256=YvmHfZqanwrJ8ToGch34x-L-7yPe31nB_x77_Mgl_vo,4545
|
328
|
-
uk_bin_collection-0.
|
329
|
-
uk_bin_collection-0.
|
330
|
-
uk_bin_collection-0.
|
331
|
-
uk_bin_collection-0.
|
332
|
-
uk_bin_collection-0.
|
329
|
+
uk_bin_collection-0.141.0.dist-info/LICENSE,sha256=vABBUOzcrgfaTKpzeo-si9YVEun6juDkndqA8RKdKGs,1071
|
330
|
+
uk_bin_collection-0.141.0.dist-info/METADATA,sha256=wkZzAu4PUwGpBcnep3fvKUVjYSPYKVf4_wlShHwzfXM,19851
|
331
|
+
uk_bin_collection-0.141.0.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
|
332
|
+
uk_bin_collection-0.141.0.dist-info/entry_points.txt,sha256=36WCSGMWSc916S3Hi1ZkazzDKHaJ6CD-4fCEFm5MIao,90
|
333
|
+
uk_bin_collection-0.141.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|
{uk_bin_collection-0.140.0.dist-info → uk_bin_collection-0.141.0.dist-info}/entry_points.txt
RENAMED
File without changes
|