diff --git a/uk_bin_collection/tests/features/validate_council_outputs.feature b/uk_bin_collection/tests/features/validate_council_outputs.feature index 1fdae15827..912ce532bf 100644 --- a/uk_bin_collection/tests/features/validate_council_outputs.feature +++ b/uk_bin_collection/tests/features/validate_council_outputs.feature @@ -57,6 +57,7 @@ Feature: Test each council output matches expected results | MalvernHillsDC | None | None | | ManchesterCityCouncil | None | None | | MertonCouncil | None | None | + | MidAndEastAntrimBoroughCouncil | http://selenium:4444 | local | | MidSussexDistrictCouncil | None | None | | MiltonKeynesCityCouncil | None | None | | NeathPortTalbotCouncil | http://selenium:4444 | local | diff --git a/uk_bin_collection/tests/input.json b/uk_bin_collection/tests/input.json index ce160bb45e..27fd157e1a 100644 --- a/uk_bin_collection/tests/input.json +++ b/uk_bin_collection/tests/input.json @@ -330,6 +330,14 @@ "wiki_name": "Merton Council", "wiki_note": "Follow the instructions [here](https://myneighbourhood.merton.gov.uk/Wasteservices/WasteServicesSearch.aspx) until you get the \"Your recycling and rubbish collection days\" page then copy the URL and replace the URL in the command (the Address parameter is optional)." }, + "MidAndEastAntrimBoroughCouncil": { + "postcode": "100 Galgorm Road", + "skip_get_url": true, + "url": "https://www.midandeastantrim.gov.uk/resident/waste-recycling/collection-dates/", + "web_driver": "http://selenium:4444", + "wiki_name": "Mid and East Antrim Borough Council", + "wiki_note": "Pass the house name/number plus the name of the street with the postcode parameter, wrapped in double quotes. Check the address in the web site first. This version will only pick the first SHOW button returned by the search or if it is fully unique. The search is not very predictable (e.g. house number 4 returns 14,24,4,44 etc.)." + }, "MidSussexDistrictCouncil": { "house_number": "OAKLANDS", "postcode": "RH16 1SS", @@ -674,4 +682,4 @@ "url": "https://waste-api.york.gov.uk/api/Collections/GetBinCollectionDataForUprn/", "wiki_name": "York Council" } -} \ No newline at end of file +} diff --git a/uk_bin_collection/uk_bin_collection/councils/MidAndEastAntrimBoroughCouncil.py b/uk_bin_collection/uk_bin_collection/councils/MidAndEastAntrimBoroughCouncil.py new file mode 100644 index 0000000000..8c61bbccd2 --- /dev/null +++ b/uk_bin_collection/uk_bin_collection/councils/MidAndEastAntrimBoroughCouncil.py @@ -0,0 +1,117 @@ +from bs4 import BeautifulSoup +import time +from dateutil.relativedelta import relativedelta +from selenium.webdriver.common.by import By +from selenium.webdriver.common.keys import Keys +from selenium.webdriver.support.ui import Select +from selenium.common.exceptions import NoSuchElementException + +from uk_bin_collection.uk_bin_collection.common import * +from uk_bin_collection.uk_bin_collection.get_bin_data import \ + AbstractGetBinDataClass + +class CouncilClass(AbstractGetBinDataClass): + """ + Concrete classes have to implement all abstract operations of the + base class. They can also override some operations with a default + implementation. + """ + + def parse_data(self, page: str, **kwargs) -> dict: + page = "https://www.midandeastantrim.gov.uk/resident/waste-recycling/collection-dates/" + + # Assign user info + user_postcode = kwargs.get("postcode") + # not used: user_paon = kwargs.get("paon") + web_driver = kwargs.get("web_driver") + + # Create Selenium webdriver + options = webdriver.ChromeOptions() + options.add_experimental_option('excludeSwitches', ['enable-logging']) + driver = create_webdriver(web_driver) + + driver.get(page) + + time.sleep(5) + number=0 + driver.switch_to.frame(number) + # Enter postcode in text box and wait + inputElement_pc = driver.find_element( + By.ID, "txtAjaxSearch" + ) + inputElement_pc.send_keys(user_postcode) + + time.sleep(5) + + # Submit address information and wait - selecting the top one only + # if it is an exact match then it will go straight to the results + try: + button = driver.find_element( + By.XPATH, '//*[@id="show-button-0"]' + ) + driver.execute_script("arguments[0].click();", button) + except NoSuchElementException: + pass + + time.sleep(4) + + # Read next collection information + page = driver.find_element( + By.ID, "divCalendarGraphics" + ).get_attribute("outerHTML") + + # Make a BS4 object - remove bold tags and add @ so we can split the lines later + soup = BeautifulSoup(page.strip().replace("", "").replace("", "").replace("
", "@"), features="html.parser") + soup.prettify() + + # Data to return + data = {"bins": []} + + # Valid bin types + binTypes = [ + "Refuse", + "Garden" + ] + + # Value to create dict for bin values + keys, values = [], [] + + # Loop though html for text containing bins + # example of html (bold tags removed above) + #
+ #
Refuse: Tue 14 Nov then every alternate Tue
Recycling: No Recycling waste collection for this address
Garden: Tue 21 Nov then every alternate Tue
spacer + # split by br tag and take first 4 splits + lines = soup.text.split('@',4) + for line in lines[1:4]: + keys.append(line.split(':')[0].strip()) + # strip out the day and month from the text + values.append(line.split(':')[1].strip().split(' ')[:3]) + + # Create dict for bin name and string dates + binDict = dict(zip(keys, values)) + + # Process dict for valid bin types + for bin in list(binDict): + if bin in binTypes: + # Convert date - no year value so take it from todays date + if binDict[bin][0] == "Tomorrow": + date = datetime.today() + relativedelta(days=1) + elif binDict[bin][0] == "Today": + date = datetime.today() + else: + date = datetime.strptime(' '.join(binDict[bin][1:]), "%d %b").replace(year=datetime.today().year) + # if the date is in the past then it means the collection is next year so add a year + if date < datetime.today(): + date = date + relativedelta(years=1) + + # Set bin data + dict_data = { + "type": bin, + "collectionDate": date.strftime(date_format), + } + data["bins"].append(dict_data) + + # Quit Selenium webdriver to release session + driver.quit() + + return data