Skip to content

Commit

Permalink
fix: CheshireWestAndChesterCouncil
Browse files Browse the repository at this point in the history
fix: #993
  • Loading branch information
m26dvd committed Nov 11, 2024
1 parent ece3a8d commit c7b62c4
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 133 deletions.
15 changes: 4 additions & 11 deletions uk_bin_collection/tests/input.json
Original file line number Diff line number Diff line change
Expand Up @@ -342,26 +342,19 @@
"wiki_note": "Both the UPRN and a one-line address are passed in the URL, which needs to be wrapped in double quotes. The one-line address is made up of the house number, street name, and postcode. Use the form [here](https://online.cheshireeast.gov.uk/mycollectionday/) to find them, then take the first line and postcode and replace all spaces with `%20`."
},
"CheshireWestAndChesterCouncil": {
"house_number": "Hill View House",
"postcode": "CH3 9ER",
"uprn": "100012346655",
"skip_get_url": true,
"url": "https://www.cheshirewestandchester.gov.uk/residents/waste-and-recycling/your-bin-collection/collection-day",
"url": "https://my.cheshirewestandchester.gov.uk",
"wiki_name": "Cheshire West and Chester Council",
"wiki_note": "Pass the house name/number and postcode in their respective parameters."
"wiki_note": "Pass the UPRN. You will need to use [FindMyAddress](https://www.findmyaddress.co.uk/search)."
},
"ChesterfieldBoroughCouncil": {
"uprn": "74008234",
"skip_get_url": true,
"url": "https://www.cheshirewestandchester.gov.uk/residents/waste-and-recycling/your-bin-collection/collection-day",
"url": "https://www.chesterfield.gov.uk",
"wiki_name": "Chesterfield Borough Council",
"wiki_note": "Pass the UPRN. You will need to use [FindMyAddress](https://www.findmyaddress.co.uk/search)."
},
"ChesterfieldBoroughCouncil": {
"uprn": "74008234",
"skip_get_url": true,
"url": "https://www.cheshirewestandchester.gov.uk/residents/waste-and-recycling/your-bin-collection/collection-day",
"wiki_name": "Chesterfield Borough Council"
},
"ChichesterDistrictCouncil": {
"house_number": "7, Plaistow Road, Kirdford, Billingshurst, West Sussex",
"postcode": "RH14 0JT",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,123 +1,105 @@
import logging
import time

from bs4 import BeautifulSoup
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import Select
from selenium.webdriver.support.wait import WebDriverWait
import requests

from uk_bin_collection.uk_bin_collection.common import *
from uk_bin_collection.uk_bin_collection.get_bin_data import AbstractGetBinDataClass

# Set up logging
logging.basicConfig(
level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s"
)

# import the wonderful Beautiful Soup and the URL grabber
class CouncilClass(AbstractGetBinDataClass):
def parse_data(self, page: str, **kwargs) -> dict:
driver = None
try:
data = {"bins": []}
collections = []
user_uprn = kwargs.get("uprn")
user_paon = kwargs.get("paon")
user_postcode = kwargs.get("postcode")
web_driver = kwargs.get("web_driver")
headless = kwargs.get("headless")
check_paon(user_paon)
check_postcode(user_postcode)

# Create Selenium webdriver
driver = create_webdriver(web_driver, headless, None, __name__)
if headless:
driver.set_window_size(1920, 1080)

driver.get(
"https://www.cheshirewestandchester.gov.uk/residents/waste-and-recycling/your-bin-collection/collection-day"
)
wait = WebDriverWait(driver, 60)

def click_element(by, value):
element = wait.until(EC.element_to_be_clickable((by, value)))
driver.execute_script("arguments[0].scrollIntoView();", element)
element.click()

logging.info("Accepting cookies")
click_element(By.ID, "ccc-close")

logging.info("Finding collection day")
click_element(By.LINK_TEXT, "Find your collection day")

logging.info("Switching to iframe")
iframe_presence = wait.until(
EC.presence_of_element_located((By.ID, "fillform-frame-1"))
)
driver.switch_to.frame(iframe_presence)

logging.info("Entering postcode")
input_element_postcode = wait.until(
EC.presence_of_element_located(
(By.XPATH, '//input[@id="postcode_search"]')
)
)
input_element_postcode.send_keys(user_postcode)

pcsearch_btn = wait.until(
EC.element_to_be_clickable((By.XPATH, "//input[@id='postcode_search']"))
)
click_element(By.XPATH, "//input[@id='postcode_search']")

logging.info("Selecting address")
dropdown = wait.until(EC.element_to_be_clickable((By.ID, "Choose_Address")))
dropdown_options = wait.until(
EC.presence_of_element_located((By.CLASS_NAME, "lookup-option"))
)
drop_down_values = Select(dropdown)
option_element = wait.until(
EC.presence_of_element_located(
(By.CSS_SELECTOR, f'option.lookup-option[value="{str(user_uprn)}"]')
)
)
driver.execute_script("arguments[0].scrollIntoView();", option_element)
drop_down_values.select_by_value(str(user_uprn))

logging.info("Waiting for bin schedule")
wait.until(
EC.presence_of_element_located(
(By.CLASS_NAME, "bin-schedule-content-bin-card")
)
)

logging.info("Extracting bin collection data")
soup = BeautifulSoup(driver.page_source, features="html.parser")
bin_cards = soup.find_all("div", {"class": "bin-schedule-content-bin-card"})
collections = []

for card in bin_cards:
bin_info = card.find("div", {"class": "bin-schedule-content-info"})
bin_name = bin_info.find_all("p")[0].text.strip() + " bin"
bin_date_str = bin_info.find_all("p")[1].text.split(":")[1].strip()
bin_date = datetime.strptime(bin_date_str, "%A, %B %d, %Y")
collections.append((bin_name, bin_date))

ordered_data = sorted(collections, key=lambda x: x[1])

for item in ordered_data:
dict_data = {
"type": item[0].capitalize(),
"collectionDate": item[1].strftime(date_format),
}
data["bins"].append(dict_data)

logging.info("Data extraction complete")
return data
"""
Concrete classes have to implement all abstract operations of the
base class. They can also override some operations with a default
implementation.
"""

except Exception as e:
logging.error(f"An error occurred: {e}")
raise
def parse_data(self, page: str, **kwargs) -> dict:

finally:
if driver:
driver.quit()
user_uprn = kwargs.get("uprn")
check_uprn(user_uprn)
bindata = {"bins": []}

SESSION_URL = "https://my.cheshirewestandchester.gov.uk/authapi/isauthenticated?uri=https://my.cheshirewestandchester.gov.uk/fillform/?iframe_id=fillform-frame-1&db_id=&hostname=my.cheshirewestandchester.gov.uk&withCredentials=true"

API_URL = "https://my.cheshirewestandchester.gov.uk/apibroker/runLookup"

headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"User-Agent": "Mozilla/5.0",
"X-Requested-With": "XMLHttpRequest",
"Referer": "https://mycouncil.milton-keynes.gov.uk/fillform/?iframe_id=fillform-frame-1&db_id=",
}
s = requests.session()
r = s.get(SESSION_URL)
r.raise_for_status()
session_data = r.json()
sid = session_data["auth-session"]
params = {
"id": "609b918c7dd6d",
"repeat_against": "",
"noRetry": "false",
"getOnlyTokens": "undefined",
"log_id": "",
"app_name": "AchieveForms",
# unix_timestamp
"_": str(int(time.time() * 1000)),
"sid": sid,
}

r = s.post(API_URL, headers=headers, params=params)
r.raise_for_status()

data = r.json()
rows_data = data["integration"]["transformed"]["rows_data"]["0"]
AuthenticateResponse = rows_data["AuthenticateResponse"]

params = {
"id": "6101d23110243",
"repeat_against": "",
"noRetry": "false",
"getOnlyTokens": "undefined",
"log_id": "",
"app_name": "AchieveForms",
# unix_timestamp
"_": str(int(time.time() * 1000)),
"sid": sid,
}

data = {
"formValues": {
"Section 1": {
"UPRN": {
"value": user_uprn,
},
"AuthenticateResponse": {
"value": AuthenticateResponse,
},
}
},
}

r = s.post(API_URL, json=data, headers=headers, params=params)
r.raise_for_status()

data = r.json()
rows_data = data["integration"]["transformed"]["rows_data"]
if not isinstance(rows_data, dict):
raise ValueError("Invalid data returned from API")

# Extract each service's relevant details for the bin schedule
for item in rows_data.values():
dict_data = {
"type": item["serviceType"],
"collectionDate": datetime.strptime(
item["collectionDateTime"], "%Y-%m-%dT%H:%M:%S"
).strftime(date_format),
}
bindata["bins"].append(dict_data)

bindata["bins"].sort(
key=lambda x: datetime.strptime(x.get("collectionDate"), "%d/%m/%Y")
)

return bindata
19 changes: 10 additions & 9 deletions wiki/Councils.md
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,7 @@ Additional parameters:
- `-s` - skip get URL
- `-n` - house number

Note: Use the House Number field to pass the DAY of the week for your colletions. Monday/Tuesday/Wednesday/Thursday/Friday
Note: Use the House Number field to pass the DAY of the week for your collections. Monday/Tuesday/Wednesday/Thursday/Friday

---

Expand Down Expand Up @@ -776,25 +776,26 @@ Note: Both the UPRN and a one-line address are passed in the URL, which needs to

### Cheshire West and Chester Council
```commandline
python collect_data.py CheshireWestAndChesterCouncil https://www.cheshirewestandchester.gov.uk/residents/waste-and-recycling/your-bin-collection/collection-day -s -p "XXXX XXX" -n XX
python collect_data.py CheshireWestAndChesterCouncil https://my.cheshirewestandchester.gov.uk -s -u XXXXXXXX
```
Additional parameters:
- `-s` - skip get URL
- `-p` - postcode
- `-n` - house number
- `-u` - UPRN

Note: Pass the house name/number and postcode in their respective parameters.
Note: Pass the UPRN. You will need to use [FindMyAddress](https://www.findmyaddress.co.uk/search).

---

### Chesterfield Borough Council
```commandline
python collect_data.py ChesterfieldBoroughCouncil https://www.cheshirewestandchester.gov.uk/residents/waste-and-recycling/your-bin-collection/collection-day -s -u XXXXXXXX
python collect_data.py ChesterfieldBoroughCouncil https://www.chesterfield.gov.uk -s -u XXXXXXXX
```
Additional parameters:
- `-s` - skip get URL
- `-u` - UPRN

Note: Pass the UPRN. You will need to use [FindMyAddress](https://www.findmyaddress.co.uk/search).

---

### Chichester District Council
Expand Down Expand Up @@ -1763,7 +1764,7 @@ Additional parameters:
- `-s` - skip get URL
- `-n` - house number

Note: Use the House Number field to pass the DAY of the week for your colletions. Monday/Tuesday/Wednesday/Thursday/Friday
Note: Use the House Number field to pass the DAY of the week for your collections. Monday/Tuesday/Wednesday/Thursday/Friday

---

Expand All @@ -1783,12 +1784,12 @@ Note: Pass the name of the street with the house number parameter, wrapped in do

### Milton Keynes City Council
```commandline
python collect_data.py MiltonKeynesCityCouncil https://www.milton-keynes.gov.uk/waste-and-recycling/collection-days -u XXXXXXXX
python collect_data.py MiltonKeynesCityCouncil https://mycouncil.milton-keynes.gov.uk/en/service/Waste_Collection_Round_Checker -u XXXXXXXX
```
Additional parameters:
- `-u` - UPRN

Note: Pass the name of the estate with the UPRN parameter, wrapped in double quotes.
Note: You will need to use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find the UPRN.

---

Expand Down

0 comments on commit c7b62c4

Please sign in to comment.