uk_bin_collection 0.150.1__py3-none-any.whl → 0.152.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 +46 -8
- uk_bin_collection/uk_bin_collection/councils/AngusCouncil.py +149 -0
- uk_bin_collection/uk_bin_collection/councils/ArgyllandButeCouncil.py +0 -2
- uk_bin_collection/uk_bin_collection/councils/BarkingDagenham.py +11 -2
- uk_bin_collection/uk_bin_collection/councils/BrentCouncil.py +47 -33
- uk_bin_collection/uk_bin_collection/councils/BrightonandHoveCityCouncil.py +11 -2
- uk_bin_collection/uk_bin_collection/councils/BroadlandDistrictCouncil.py +21 -6
- uk_bin_collection/uk_bin_collection/councils/ChichesterDistrictCouncil.py +105 -53
- uk_bin_collection/uk_bin_collection/councils/FermanaghOmaghDistrictCouncil.py +102 -0
- uk_bin_collection/uk_bin_collection/councils/MaidstoneBoroughCouncil.py +115 -0
- uk_bin_collection/uk_bin_collection/councils/NorthEastDerbyshireDistrictCouncil.py +61 -39
- uk_bin_collection/uk_bin_collection/councils/RugbyBoroughCouncil.py +128 -71
- uk_bin_collection/uk_bin_collection/councils/SloughBoroughCouncil.py +140 -0
- uk_bin_collection/uk_bin_collection/councils/TewkesburyBoroughCouncil.py +40 -0
- {uk_bin_collection-0.150.1.dist-info → uk_bin_collection-0.152.0.dist-info}/METADATA +1 -1
- {uk_bin_collection-0.150.1.dist-info → uk_bin_collection-0.152.0.dist-info}/RECORD +19 -14
- {uk_bin_collection-0.150.1.dist-info → uk_bin_collection-0.152.0.dist-info}/LICENSE +0 -0
- {uk_bin_collection-0.150.1.dist-info → uk_bin_collection-0.152.0.dist-info}/WHEEL +0 -0
- {uk_bin_collection-0.150.1.dist-info → uk_bin_collection-0.152.0.dist-info}/entry_points.txt +0 -0
@@ -28,6 +28,16 @@
|
|
28
28
|
"wiki_note": "You will need to use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find the UPRN.",
|
29
29
|
"LAD24CD": "E07000032"
|
30
30
|
},
|
31
|
+
"AngusCouncil": {
|
32
|
+
"uprn": "117053733",
|
33
|
+
"skip_get_url": true,
|
34
|
+
"postcode": "DD7 7LE",
|
35
|
+
"url": "https://www.angus.gov.uk/bins_litter_and_recycling/bin_collection_days",
|
36
|
+
"web_driver": "http://selenium:4444",
|
37
|
+
"wiki_name": "Angus",
|
38
|
+
"wiki_note": "You will need to use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find the UPRN. Requires Selenium",
|
39
|
+
"LAD24CD": "S12000041"
|
40
|
+
},
|
31
41
|
"AntrimAndNewtonabbeyCouncil": {
|
32
42
|
"LAD24CD": "N09000001",
|
33
43
|
"url": "https://antrimandnewtownabbey.gov.uk/residents/bins-recycling/bins-schedule/?Id=643",
|
@@ -117,13 +127,13 @@
|
|
117
127
|
"LAD24CD": "E07000200"
|
118
128
|
},
|
119
129
|
"BarkingDagenham": {
|
120
|
-
"house_number": "19
|
130
|
+
"house_number": "19",
|
121
131
|
"postcode": "RM6 6XH",
|
122
132
|
"skip_get_url": true,
|
123
133
|
"web_driver": "http://selenium:4444",
|
124
134
|
"url": "https://www.lbbd.gov.uk/rubbish-recycling/household-bin-collection/check-your-bin-collection-days",
|
125
135
|
"wiki_name": "Barking and Dagenham",
|
126
|
-
"wiki_note": "Use
|
136
|
+
"wiki_note": "Use house number and postcode. Requires Selenium.",
|
127
137
|
"LAD24CD": "E09000002"
|
128
138
|
},
|
129
139
|
"BarnetCouncil": {
|
@@ -311,13 +321,13 @@
|
|
311
321
|
"LAD24CD": "E09000005"
|
312
322
|
},
|
313
323
|
"BrightonandHoveCityCouncil": {
|
314
|
-
"house_number": "44
|
324
|
+
"house_number": "44",
|
315
325
|
"postcode": "BN1 8NE",
|
316
326
|
"skip_get_url": true,
|
317
327
|
"url": "https://cityclean.brighton-hove.gov.uk/link/collections",
|
318
328
|
"web_driver": "http://selenium:4444",
|
319
329
|
"wiki_name": "Brighton and Hove",
|
320
|
-
"wiki_note": "Use
|
330
|
+
"wiki_note": "Use house number and postcode. Requires Selenium",
|
321
331
|
"LAD24CD": "E06000043"
|
322
332
|
},
|
323
333
|
"BristolCityCouncil": {
|
@@ -330,12 +340,12 @@
|
|
330
340
|
},
|
331
341
|
"BroadlandDistrictCouncil": {
|
332
342
|
"skip_get_url": true,
|
333
|
-
"house_number": "1
|
343
|
+
"house_number": "1",
|
334
344
|
"postcode": "NR10 3FD",
|
335
345
|
"url": "https://area.southnorfolkandbroadland.gov.uk/FindAddress",
|
336
346
|
"web_driver": "http://selenium:4444",
|
337
347
|
"wiki_name": "Broadland",
|
338
|
-
"wiki_note": "Use
|
348
|
+
"wiki_note": "Use house number and postcode. Requires Selenium.",
|
339
349
|
"LAD24CD": "E07000144"
|
340
350
|
},
|
341
351
|
"BromleyBoroughCouncil": {
|
@@ -521,7 +531,7 @@
|
|
521
531
|
"LAD24CD": "E07000034"
|
522
532
|
},
|
523
533
|
"ChichesterDistrictCouncil": {
|
524
|
-
"house_number": "7
|
534
|
+
"house_number": "7",
|
525
535
|
"postcode": "RH14 0JT",
|
526
536
|
"skip_get_url": true,
|
527
537
|
"url": "https://www.chichester.gov.uk/checkyourbinday",
|
@@ -901,6 +911,15 @@
|
|
901
911
|
"wiki_note": "Pass the UPRN. You can find it using [FindMyAddress](https://www.findmyaddress.co.uk/search).",
|
902
912
|
"LAD24CD": "E07000010"
|
903
913
|
},
|
914
|
+
"FermanaghOmaghDistrictCouncil": {
|
915
|
+
"house_number": "20",
|
916
|
+
"postcode": "BT74 6DQ",
|
917
|
+
"skip_get_url": true,
|
918
|
+
"url": "https://www.fermanaghomagh.com/services/environment-and-waste/waste-collection-calendar/",
|
919
|
+
"wiki_name": "Fermanagh and Omagh",
|
920
|
+
"wiki_note": "Pass the house number and postcode in their respective parameters.",
|
921
|
+
"LAD24CD": "N09000006"
|
922
|
+
},
|
904
923
|
"FifeCouncil": {
|
905
924
|
"uprn": "320203521",
|
906
925
|
"url": "https://www.fife.gov.uk",
|
@@ -1199,6 +1218,7 @@
|
|
1199
1218
|
"LAD24CD": "E07000120",
|
1200
1219
|
"uprn": "100010448773",
|
1201
1220
|
"url": "https://iapp.itouchvision.com/iappcollectionday/collection-day/?uuid=FEBA68993831481FD81B2E605364D00A8DC017A4",
|
1221
|
+
"skip_get_url": true,
|
1202
1222
|
"web_driver": "http://selenium:4444",
|
1203
1223
|
"wiki_name": "Hyndburn",
|
1204
1224
|
"wiki_note": "Pass the UPRN. You can find it using [FindMyAddress](https://www.findmyaddress.co.uk/search). This parser requires a Selenium webdriver."
|
@@ -1622,7 +1642,7 @@
|
|
1622
1642
|
"NorthEastDerbyshireDistrictCouncil": {
|
1623
1643
|
"postcode": "S42 5RB",
|
1624
1644
|
"skip_get_url": true,
|
1625
|
-
"uprn": "
|
1645
|
+
"uprn": "010034492222",
|
1626
1646
|
"url": "https://myselfservice.ne-derbyshire.gov.uk/service/Check_your_Bin_Day",
|
1627
1647
|
"web_driver": "http://selenium:4444",
|
1628
1648
|
"wiki_name": "North East Derbyshire",
|
@@ -1935,6 +1955,7 @@
|
|
1935
1955
|
"skip_get_url": true,
|
1936
1956
|
"uprn": "100070182634",
|
1937
1957
|
"url": "https://www.rugby.gov.uk/check-your-next-bin-day",
|
1958
|
+
"web_driver": "http://selenium:4444",
|
1938
1959
|
"wiki_name": "Rugby",
|
1939
1960
|
"wiki_note": "Provide your UPRN and postcode. You can find your UPRN using [FindMyAddress](https://www.findmyaddress.co.uk/search).",
|
1940
1961
|
"LAD24CD": "E07000220"
|
@@ -2012,6 +2033,15 @@
|
|
2012
2033
|
"wiki_note": "Follow the instructions [here](https://bins.shropshire.gov.uk/) until you get the page showing your bin collection dates, then copy the URL and replace the URL in the command.",
|
2013
2034
|
"LAD24CD": "E06000051"
|
2014
2035
|
},
|
2036
|
+
"SloughBoroughCouncil": {
|
2037
|
+
"postcode": "SL2 2EW",
|
2038
|
+
"skip_get_url": true,
|
2039
|
+
"url": "https://www.slough.gov.uk/bin-collections",
|
2040
|
+
"web_driver": "http://selenium:4444",
|
2041
|
+
"wiki_name": "Slough",
|
2042
|
+
"wiki_note": "Pass the UPRN and postcode in their respective parameters. This parser requires a Selenium webdriver.",
|
2043
|
+
"LAD24CD": "E06000039"
|
2044
|
+
},
|
2015
2045
|
"SolihullCouncil": {
|
2016
2046
|
"url": "https://digital.solihull.gov.uk/BinCollectionCalendar/Calendar.aspx?UPRN=100071005444",
|
2017
2047
|
"wiki_command_url_override": "https://digital.solihull.gov.uk/BinCollectionCalendar/Calendar.aspx?UPRN=XXXXXXXX",
|
@@ -2331,6 +2361,14 @@
|
|
2331
2361
|
"wiki_note": "Provide your UPRN. Find it using [FindMyAddress](https://www.findmyaddress.co.uk/search).",
|
2332
2362
|
"LAD24CD": "E06000020"
|
2333
2363
|
},
|
2364
|
+
"TewkesburyBoroughCouncil": {
|
2365
|
+
"skip_get_url": true,
|
2366
|
+
"uprn": "10067626314",
|
2367
|
+
"url": "https://tewkesbury.gov.uk/services/waste-and-recycling/",
|
2368
|
+
"wiki_name": "Tewkesbury",
|
2369
|
+
"wiki_note": "Provide your UPRN. Find it using [FindMyAddress](https://www.findmyaddress.co.uk/search).",
|
2370
|
+
"LAD24CD": "E07000083"
|
2371
|
+
},
|
2334
2372
|
"TendringDistrictCouncil": {
|
2335
2373
|
"postcode": "CO15 4EU",
|
2336
2374
|
"skip_get_url": true,
|
@@ -0,0 +1,149 @@
|
|
1
|
+
import time
|
2
|
+
import re
|
3
|
+
from datetime import datetime
|
4
|
+
|
5
|
+
from bs4 import BeautifulSoup
|
6
|
+
from selenium.webdriver.common.by import By
|
7
|
+
from selenium.webdriver.common.keys import Keys
|
8
|
+
from selenium.webdriver.support import expected_conditions as EC
|
9
|
+
from selenium.webdriver.support.ui import Select, 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
|
+
class CouncilClass(AbstractGetBinDataClass):
|
16
|
+
def parse_data(self, page: str, **kwargs) -> dict:
|
17
|
+
driver = None
|
18
|
+
try:
|
19
|
+
user_postcode = kwargs.get("postcode")
|
20
|
+
if not user_postcode:
|
21
|
+
raise ValueError("No postcode provided.")
|
22
|
+
check_postcode(user_postcode)
|
23
|
+
|
24
|
+
user_uprn = kwargs.get("uprn")
|
25
|
+
check_uprn(user_uprn)
|
26
|
+
|
27
|
+
headless = kwargs.get("headless")
|
28
|
+
web_driver = kwargs.get("web_driver")
|
29
|
+
driver = create_webdriver(web_driver, headless, None, __name__)
|
30
|
+
page = "https://www.angus.gov.uk/bins_litter_and_recycling/bin_collection_days"
|
31
|
+
|
32
|
+
driver.get(page)
|
33
|
+
|
34
|
+
wait = WebDriverWait(driver, 10)
|
35
|
+
accept_cookies_button = wait.until(
|
36
|
+
EC.element_to_be_clickable((By.ID, "ccc-recommended-settings"))
|
37
|
+
)
|
38
|
+
accept_cookies_button.click()
|
39
|
+
|
40
|
+
find_your_collection_button = wait.until(
|
41
|
+
EC.element_to_be_clickable(
|
42
|
+
(By.XPATH, "/html/body/div[2]/div[2]/div/div/section/div[2]/div/article/div/div/p[2]/a")
|
43
|
+
)
|
44
|
+
)
|
45
|
+
find_your_collection_button.click()
|
46
|
+
|
47
|
+
iframe = wait.until(EC.presence_of_element_located((By.ID, "fillform-frame-1")))
|
48
|
+
driver.switch_to.frame(iframe)
|
49
|
+
|
50
|
+
postcode_input = wait.until(EC.presence_of_element_located((By.ID, "searchString")))
|
51
|
+
postcode_input.send_keys(user_postcode + Keys.TAB + Keys.ENTER)
|
52
|
+
|
53
|
+
time.sleep(15)
|
54
|
+
|
55
|
+
select_elem = wait.until(EC.presence_of_element_located((By.ID, "customerAddress")))
|
56
|
+
WebDriverWait(driver, 10).until(
|
57
|
+
lambda d: len(select_elem.find_elements(By.TAG_NAME, "option")) > 1
|
58
|
+
)
|
59
|
+
dropdown = Select(select_elem)
|
60
|
+
dropdown.select_by_value(user_uprn)
|
61
|
+
|
62
|
+
time.sleep(10)
|
63
|
+
|
64
|
+
wait.until(
|
65
|
+
EC.presence_of_element_located(
|
66
|
+
(By.CSS_SELECTOR, "span.fieldInput.content.html.non-input"))
|
67
|
+
)
|
68
|
+
|
69
|
+
soup = BeautifulSoup(driver.page_source, "html.parser")
|
70
|
+
bin_data = {"bins": []}
|
71
|
+
current_date = datetime.now()
|
72
|
+
current_formatted_date = None
|
73
|
+
|
74
|
+
spans = soup.select("span.fieldInput.content.html.non-input")
|
75
|
+
print(f"Found {len(spans)} bin info spans.")
|
76
|
+
|
77
|
+
for i, span in enumerate(spans):
|
78
|
+
try:
|
79
|
+
# Look for any non-empty <u> tag recursively
|
80
|
+
date_tag = next(
|
81
|
+
(u for u in span.find_all("u") if u and u.text.strip()),
|
82
|
+
None
|
83
|
+
)
|
84
|
+
bin_type_tag = span.find("b")
|
85
|
+
|
86
|
+
if date_tag:
|
87
|
+
raw_date = date_tag.text.strip().replace(",", "")
|
88
|
+
full_date_str = f"{raw_date} {current_date.year}"
|
89
|
+
full_date_str = re.sub(r"\s+", " ", full_date_str)
|
90
|
+
|
91
|
+
try:
|
92
|
+
parsed_date = datetime.strptime(full_date_str, "%A %d %B %Y")
|
93
|
+
if parsed_date.date() < current_date.date():
|
94
|
+
parsed_date = parsed_date.replace(year=current_date.year + 1)
|
95
|
+
current_formatted_date = parsed_date.strftime("%d/%m/%Y")
|
96
|
+
print(f"[{i}] Parsed date: {current_formatted_date}")
|
97
|
+
except ValueError as ve:
|
98
|
+
print(f"[{i}] Could not parse date: '{full_date_str}' - {ve}")
|
99
|
+
continue
|
100
|
+
else:
|
101
|
+
print(f"[{i}] No date tag found, using last valid date: {current_formatted_date}")
|
102
|
+
|
103
|
+
if not current_formatted_date:
|
104
|
+
print(f"[{i}] No current date to associate bin type with — skipping.")
|
105
|
+
continue
|
106
|
+
|
107
|
+
if not bin_type_tag or not bin_type_tag.text.strip():
|
108
|
+
print(f"[{i}] No bin type found — skipping.")
|
109
|
+
continue
|
110
|
+
|
111
|
+
bin_type = bin_type_tag.text.strip()
|
112
|
+
|
113
|
+
# Optional seasonal override
|
114
|
+
try:
|
115
|
+
overrides_dict = get_seasonal_overrides()
|
116
|
+
if current_formatted_date in overrides_dict:
|
117
|
+
current_formatted_date = overrides_dict[current_formatted_date]
|
118
|
+
except Exception:
|
119
|
+
pass
|
120
|
+
|
121
|
+
print(f"[{i}] Found bin: {bin_type} on {current_formatted_date}")
|
122
|
+
|
123
|
+
bin_data["bins"].append({
|
124
|
+
"type": bin_type,
|
125
|
+
"collectionDate": current_formatted_date
|
126
|
+
})
|
127
|
+
|
128
|
+
except Exception as inner_e:
|
129
|
+
print(f"[{i}] Skipping span due to error: {inner_e}")
|
130
|
+
continue
|
131
|
+
|
132
|
+
except Exception as inner_e:
|
133
|
+
print(f"Skipping span due to error: {inner_e}")
|
134
|
+
continue
|
135
|
+
|
136
|
+
if not bin_data["bins"]:
|
137
|
+
raise ValueError("No bin data found.")
|
138
|
+
|
139
|
+
print(bin_data)
|
140
|
+
|
141
|
+
return bin_data
|
142
|
+
|
143
|
+
except Exception as e:
|
144
|
+
print(f"An error occurred: {e}")
|
145
|
+
raise
|
146
|
+
|
147
|
+
finally:
|
148
|
+
if driver:
|
149
|
+
driver.quit()
|
@@ -8,8 +8,6 @@ from uk_bin_collection.uk_bin_collection.get_bin_data import AbstractGetBinDataC
|
|
8
8
|
|
9
9
|
|
10
10
|
# import the wonderful Beautiful Soup and the URL grabber
|
11
|
-
|
12
|
-
|
13
11
|
class CouncilClass(AbstractGetBinDataClass):
|
14
12
|
"""
|
15
13
|
Concrete classes have to implement all abstract operations of the
|
@@ -84,10 +84,19 @@ class CouncilClass(AbstractGetBinDataClass):
|
|
84
84
|
EC.element_to_be_clickable((By.ID, "address")),
|
85
85
|
message="Address dropdown not found",
|
86
86
|
)
|
87
|
+
|
87
88
|
dropdown = Select(address_select)
|
88
89
|
|
89
|
-
|
90
|
-
|
90
|
+
found = False
|
91
|
+
for option in dropdown.options:
|
92
|
+
if user_paon in option.text:
|
93
|
+
option.click()
|
94
|
+
found = True
|
95
|
+
print("Address selected successfully")
|
96
|
+
break
|
97
|
+
|
98
|
+
if not found:
|
99
|
+
raise Exception(f"No matching address containing '{user_paon}' found.")
|
91
100
|
|
92
101
|
driver.switch_to.active_element.send_keys(Keys.TAB + Keys.ENTER)
|
93
102
|
print("Pressed ENTER on Next button")
|
@@ -74,42 +74,56 @@ class CouncilClass(AbstractGetBinDataClass):
|
|
74
74
|
)
|
75
75
|
|
76
76
|
if service_details:
|
77
|
-
|
78
|
-
# Extract next collection date
|
77
|
+
# Extract next collection date only
|
79
78
|
next_collection_row = service_details.find(
|
80
79
|
"dt", string="Next collection"
|
81
80
|
)
|
82
|
-
|
83
|
-
next_collection_row.find_next_sibling(
|
84
|
-
|
85
|
-
)
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
year=next_year
|
81
|
+
if next_collection_row:
|
82
|
+
next_collection = next_collection_row.find_next_sibling(
|
83
|
+
"dd"
|
84
|
+
).get_text(strip=True)
|
85
|
+
|
86
|
+
# Remove the adjusted collection time message
|
87
|
+
if (
|
88
|
+
"(this collection has been adjusted from its usual time)"
|
89
|
+
in next_collection
|
90
|
+
):
|
91
|
+
next_collection = next_collection.replace(
|
92
|
+
"(this collection has been adjusted from its usual time)",
|
93
|
+
"",
|
94
|
+
).strip()
|
95
|
+
|
96
|
+
# Parse date from format like "Wednesday, 7th May"
|
97
|
+
next_collection = remove_ordinal_indicator_from_date_string(
|
98
|
+
next_collection
|
101
99
|
)
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
100
|
+
try:
|
101
|
+
next_collection_date = datetime.strptime(
|
102
|
+
next_collection, "%A, %d %B"
|
103
|
+
)
|
104
|
+
|
105
|
+
# Handle year rollover
|
106
|
+
if (
|
107
|
+
datetime.now().month == 12
|
108
|
+
and next_collection_date.month == 1
|
109
|
+
):
|
110
|
+
next_collection_date = next_collection_date.replace(
|
111
|
+
year=next_year
|
112
|
+
)
|
113
|
+
else:
|
114
|
+
next_collection_date = next_collection_date.replace(
|
115
|
+
year=current_year
|
116
|
+
)
|
117
|
+
|
118
|
+
dict_data = {
|
119
|
+
"type": collection_type.strip(),
|
120
|
+
"collectionDate": next_collection_date.strftime(
|
121
|
+
date_format
|
122
|
+
),
|
123
|
+
}
|
124
|
+
data["bins"].append(dict_data)
|
125
|
+
print(dict_data)
|
126
|
+
except ValueError as e:
|
127
|
+
print(f"Error parsing date {next_collection}: {e}")
|
114
128
|
|
115
129
|
return data
|
@@ -63,8 +63,16 @@ class CouncilClass(AbstractGetBinDataClass):
|
|
63
63
|
|
64
64
|
# Create a 'Select' for it, then select the first address in the list
|
65
65
|
# (Index 0 is "Make a selection from the list")
|
66
|
-
|
67
|
-
|
66
|
+
options = parent_element.find_elements(By.TAG_NAME, "option")
|
67
|
+
found = False
|
68
|
+
for option in options:
|
69
|
+
if user_paon in option.text:
|
70
|
+
option.click()
|
71
|
+
found = True
|
72
|
+
break
|
73
|
+
|
74
|
+
if not found:
|
75
|
+
raise Exception(f"Address containing '{user_paon}' not found in dropdown options")
|
68
76
|
|
69
77
|
submit_btn = wait.until(
|
70
78
|
EC.presence_of_element_located(
|
@@ -125,6 +133,7 @@ class CouncilClass(AbstractGetBinDataClass):
|
|
125
133
|
break
|
126
134
|
dict_data = {"type": bin_type, "collectionDate": bin_date}
|
127
135
|
data["bins"].append(dict_data)
|
136
|
+
print(data)
|
128
137
|
except Exception as e:
|
129
138
|
# Here you can log the exception if needed
|
130
139
|
print(f"An error occurred: {e}")
|
@@ -83,15 +83,30 @@ class CouncilClass(AbstractGetBinDataClass):
|
|
83
83
|
)
|
84
84
|
print("Found address dropdown")
|
85
85
|
|
86
|
-
# Create a Select object for the dropdown
|
87
86
|
dropdown_select = Select(address_dropdown)
|
88
87
|
|
89
|
-
|
90
|
-
print(f"Looking for address: {user_paon}")
|
88
|
+
print(f"Looking for address containing: {user_paon}")
|
91
89
|
|
92
|
-
|
93
|
-
|
94
|
-
|
90
|
+
found = False
|
91
|
+
user_paon_clean = user_paon.lower().strip()
|
92
|
+
|
93
|
+
for option in dropdown_select.options:
|
94
|
+
option_text_clean = option.text.lower().strip()
|
95
|
+
|
96
|
+
if (
|
97
|
+
option_text_clean == user_paon_clean # Exact match if full address given
|
98
|
+
or option_text_clean.startswith(f"{user_paon_clean} ") # Startswith match if just a number
|
99
|
+
):
|
100
|
+
option.click()
|
101
|
+
found = True
|
102
|
+
print(f"Selected address: {option.text.strip()}")
|
103
|
+
break
|
104
|
+
|
105
|
+
if not found:
|
106
|
+
all_options = [opt.text for opt in dropdown_select.options]
|
107
|
+
raise Exception(
|
108
|
+
f"Could not find a matching address for '{user_paon}'. Available options: {all_options}"
|
109
|
+
)
|
95
110
|
|
96
111
|
print("Looking for submit button after address selection...")
|
97
112
|
submit_btn = wait.until(
|