From 5bbe74d340eba1e022392f43777ce496513f07b3 Mon Sep 17 00:00:00 2001
From: Daniel Simmons-Ritchie
<37225902+SimmonsRitchie@users.noreply.github.com>
Date: Tue, 16 Jul 2024 15:38:23 -0500
Subject: [PATCH 1/2] Revert "Merge pull request #1091 from
City-Bureau/dep_chi_ssa_5"
This reverts commit 683bcb1c0fedcabd6992e94c354b8ff558497e74, reversing
changes made to 1491b139973990d071da1b3309aeb4e4a75558ea.
---
city_scrapers/spiders/chi_ssa_5.py | 145 +++++
city_scrapers/spiders/chi_ssa_51.py | 83 +++
city_scrapers/spiders/chi_ssa_54.py | 9 +
tests/files/chi_ssa_5.html | 379 +++++++++++++
tests/files/chi_ssa_51.html | 208 +++++++
tests/files/chi_ssa_54.html | 699 +++++++++++++++++++++++
tests/files/chi_ssa_54_detail.html | 841 ++++++++++++++++++++++++++++
tests/files/chi_ssa_5_minutes.html | 375 +++++++++++++
tests/test_chi_ssa_5.py | 88 +++
tests/test_chi_ssa_51.py | 81 +++
tests/test_chi_ssa_54.py | 78 +++
11 files changed, 2986 insertions(+)
create mode 100644 city_scrapers/spiders/chi_ssa_5.py
create mode 100644 city_scrapers/spiders/chi_ssa_51.py
create mode 100644 city_scrapers/spiders/chi_ssa_54.py
create mode 100644 tests/files/chi_ssa_5.html
create mode 100644 tests/files/chi_ssa_51.html
create mode 100644 tests/files/chi_ssa_54.html
create mode 100644 tests/files/chi_ssa_54_detail.html
create mode 100644 tests/files/chi_ssa_5_minutes.html
create mode 100644 tests/test_chi_ssa_5.py
create mode 100644 tests/test_chi_ssa_51.py
create mode 100644 tests/test_chi_ssa_54.py
diff --git a/city_scrapers/spiders/chi_ssa_5.py b/city_scrapers/spiders/chi_ssa_5.py
new file mode 100644
index 000000000..237f1ca6f
--- /dev/null
+++ b/city_scrapers/spiders/chi_ssa_5.py
@@ -0,0 +1,145 @@
+import re
+from datetime import datetime, time
+
+import scrapy
+from city_scrapers_core.constants import COMMISSION
+from city_scrapers_core.items import Meeting
+from city_scrapers_core.spiders import CityScrapersSpider
+
+
+class ChiSsa5Spider(CityScrapersSpider):
+ name = "chi_ssa_5"
+ agency = "Chicago Special Service Area #5 Commercial Ave"
+ timezone = "America/Chicago"
+ start_urls = ["http://scpf-inc.org/ssa5/meeting-calendar/"]
+ location = {
+ "address": "3030 E 92nd St Chicago, IL 60617",
+ "name": "MB Financial Bank",
+ }
+
+ def parse(self, response):
+ """
+ `parse` should always `yield` Meeting items.
+
+ Change the `_parse_title`, `_parse_start`, etc methods to fit your scraping
+ needs.
+ """
+ if "3030" not in response.text:
+ raise ValueError("Meeting address has changed")
+
+ self.meetings = self._parse_current_year(response)
+ yield scrapy.Request(
+ "http://scpf-inc.org/ssa5/meeting-minutes/",
+ callback=self._parse_minutes,
+ dont_filter=True,
+ )
+
+ def _parse_current_year(self, response):
+ description = " ".join(response.css(".page-post-content *::text").extract())
+ self._validate_location(description)
+
+ items = []
+ for item in response.css(".page-post-content > *"):
+ items.extend(
+ [scrapy.Selector(text=s) for s in item.extract().split(" ")]
+ )
+
+ meetings = []
+ for item in items:
+ item_text = " ".join(item.css("* ::text").extract())
+ start = self._parse_start(item_text)
+ if not start:
+ continue
+ meeting = Meeting(
+ title=self._parse_title(item_text),
+ description="",
+ classification=COMMISSION,
+ start=start,
+ end=None,
+ time_notes="",
+ all_day=False,
+ location=self.location,
+ links=self._parse_links(item),
+ source=response.url,
+ )
+ meeting["status"] = self._get_status(meeting)
+ meeting["id"] = self._get_id(meeting)
+ meetings.append(meeting)
+ return meetings
+
+ def _parse_minutes(self, response):
+ """
+ Parse the minutes page, matching with existing events if found
+ """
+ for item in response.css(".page-post-content a"):
+ text = item.xpath("text()").extract_first()
+ if not text:
+ continue
+ start = self._parse_start(text, minutes=True)
+ if not start:
+ continue
+ links = [{"href": item.attrib["href"], "title": "Minutes"}]
+ date_match = [
+ idx
+ for idx, i in enumerate(self.meetings)
+ if i["start"].date() == start.date()
+ ]
+ if len(date_match):
+ self.meetings[date_match[0]]["links"].extend(links)
+ else:
+ meeting = Meeting(
+ title=self._parse_title(text),
+ description="",
+ classification=COMMISSION,
+ start=start,
+ end=None,
+ time_notes="",
+ all_day=False,
+ location=self.location,
+ links=links,
+ source=response.url,
+ )
+ meeting["status"] = self._get_status(meeting)
+ meeting["id"] = self._get_id(meeting)
+ self.meetings.append(meeting)
+ for meeting in self.meetings:
+ yield meeting
+
+ def _parse_title(self, text):
+ """Parse or generate meeting title."""
+ if "special" in text.lower():
+ return "Special Commission"
+ return "Regular Commission"
+
+ def _parse_start(self, text, minutes=False):
+ """Parse start datetime."""
+ parsed_date = None
+ if minutes:
+ date_match = re.search(r"\d{2}/\d{2}/\d{4}", text)
+ if date_match:
+ parsed_date = datetime.strptime(date_match.group(), "%m/%d/%Y")
+ else:
+ date_match = re.search(r"\w{3,9} \d{1,2}, \d{4}", text)
+ if date_match:
+ parsed_date = datetime.strptime(date_match.group(), "%B %d, %Y")
+ if parsed_date:
+ return datetime.combine(parsed_date.date(), time(14))
+
+ def _parse_links(self, item):
+ """
+ Parse or generate documents.
+ """
+ links = []
+ for link in item.css("a"):
+ links.append(
+ {
+ "title": " ".join(link.css("*::text").extract()),
+ "href": link.attrib["href"],
+ }
+ )
+ return links
+
+ def _validate_location(self, description):
+ """Check that location hasn't changed or raise an exception"""
+ if "3030 E" not in description:
+ raise ValueError("Meeting location has changed")
diff --git a/city_scrapers/spiders/chi_ssa_51.py b/city_scrapers/spiders/chi_ssa_51.py
new file mode 100644
index 000000000..d8e9dd23b
--- /dev/null
+++ b/city_scrapers/spiders/chi_ssa_51.py
@@ -0,0 +1,83 @@
+import re
+from datetime import datetime
+
+from city_scrapers_core.constants import COMMISSION
+from city_scrapers_core.items import Meeting
+from city_scrapers_core.spiders import CityScrapersSpider
+
+
+class ChiSsa51Spider(CityScrapersSpider):
+ name = "chi_ssa_51"
+ agency = "Chicago Special Service Area #51 Chatham"
+ timezone = "America/Chicago"
+ start_urls = ["http://www.cbatechworks.org/"]
+ location = {
+ "address": "806 East 78th Street, Chicago IL 60619",
+ "name": "QBG Foundation",
+ }
+
+ def parse(self, response):
+ """
+ `parse` should always `yield` Meeting items.
+
+ Change the `_parse_title`, `_parse_start`, etc methods to fit your scraping
+ needs.
+ """
+ self._validate_location(response)
+ last_parsed_date = ""
+ for item in response.css("div#element106 font"):
+ """
+ The date and times are contained within sibling divs that are identicals,
+ so we have to continue the loop and only create the meeting until both date
+ and times have been parsed.
+ """
+ if not last_parsed_date:
+ last_parsed_date = self._parse_date(item)
+ continue
+ else:
+ start_and_end = self._parse_time(item)
+ if not start_and_end:
+ continue
+ start = last_parsed_date + " " + start_and_end[0].strip()
+ start = datetime.strptime(start, "%B %d, %Y %I:%M%p")
+ end = last_parsed_date + " " + start_and_end[1].strip()
+ end = datetime.strptime(end, "%B %d, %Y %I:%M%p")
+ last_parsed_date = ""
+
+ meeting = Meeting(
+ title="Commission",
+ description="",
+ classification=COMMISSION,
+ start=start,
+ end=end,
+ all_day=False,
+ time_notes="",
+ location=self.location,
+ links=[],
+ source=response.url,
+ )
+
+ meeting["status"] = self._get_status(meeting)
+ meeting["id"] = self._get_id(meeting)
+
+ yield meeting
+
+ def _parse_date(self, item):
+ text = item.css("*::text").extract_first()
+ if text is None:
+ return ""
+ date = re.search(r"\w{3,9} \d{1,2}, \d{4}", text)
+ if date:
+ return date.group()
+ return ""
+
+ def _parse_time(self, item):
+ """Parse start datetime as a naive datetime object."""
+ text = item.css("*::text").extract_first()
+ times = re.search(r"\d{1,2}:\d{2}[ap]m - \d{1,2}:\d{2}[ap]m", text)
+ if times:
+ return times.group().split("-")
+
+ def _validate_location(self, response):
+ if "806 East" not in " ".join(response.css("div#element106 *::text").extract()):
+ raise ValueError("Meeting location has changed")
diff --git a/city_scrapers/spiders/chi_ssa_54.py b/city_scrapers/spiders/chi_ssa_54.py
new file mode 100644
index 000000000..98616f8c2
--- /dev/null
+++ b/city_scrapers/spiders/chi_ssa_54.py
@@ -0,0 +1,9 @@
+from city_scrapers_core.spiders import CityScrapersSpider
+
+from city_scrapers.mixins import ChiRogersParkSsaMixin
+
+
+class ChiSsa54Spider(ChiRogersParkSsaMixin, CityScrapersSpider):
+ name = "chi_ssa_54"
+ agency = "Chicago Special Service Area #54 Sheridan Road"
+ start_urls = ["https://rpba.org/ssa-54/"]
diff --git a/tests/files/chi_ssa_5.html b/tests/files/chi_ssa_5.html
new file mode 100644
index 000000000..dc9e96faf
--- /dev/null
+++ b/tests/files/chi_ssa_5.html
@@ -0,0 +1,379 @@
+
+
+
+
+
+
+
+
+
+
+ MEETING CALENDAR | South Chicago Parents & Friends
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
MEETING CALENDAR
+
+
+
+
2018 PUBLIC MEETING DATES
+
January 25, 2018 – Agenda
+February 22, 2018 – Agenda
+March 22, 2018 – Agenda
+April 26, 2018 – Agenda
+May 7, 2018 – Special Meeting – Agenda
+May 24, 2018 – Agenda
+June 28, 2018 – Agenda
+July 12, 2018 – Agenda
+August 23, 2018 – Agenda
+September 27, 2018 – Agenda
+October 2, 2018 – Special Meeting – Agenda
+October 25, 2018
+November 29, 2018
+December 20, 2018
+
Meeting held at 2:00 pm at MB Financial Bank, 3030 E. 92nd Street, Chicago IL
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Change this in Theme Options
+
+
Change this in Theme Options
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/files/chi_ssa_51.html b/tests/files/chi_ssa_51.html
new file mode 100644
index 000000000..d4b7fe52f
--- /dev/null
+++ b/tests/files/chi_ssa_51.html
@@ -0,0 +1,208 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ CBA Home
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Special Service Area #51
Chatham Cottage GroveÂ
SSA #51 Commissioner Meeting Minutes:Â
March 13, 2019 Meeting Minutes Click Here, June 12, 2019 Meeting Minutes Click Here
SSA #51 Surveys:
SSA #51 Documents:
SSA #51 City Contract: Click Here, 2018 #51 Budget Summary Click Here, 2018 #51 Audit Summary Click Here, SSA #51 Legal Description Click Here , SSA#51 Map Boundary Click Here SSA #51 Open RFP's:
CURRENT REQUESTS FOR PROPOSALS
RFPs will be posted as opportunities become available. SSA #51 posts annual RFPs for holiday decorations, landscaping and snow removal, among other potential RFPs.
Graphic Design RFP Click Here.  If you have questions about any active RFPs or upcoming service requests, please contact SSA #51 Program Manager Karletta R Kelly at Karlettakelly@cbaworks.org or 773-994-5006 ext. 1006. Â
We're Committed to Encouraging Economic Growth & Beautifying Chatham!
Visit us at the SSA #51 Office:
â800 East 78th Street
ââChicago, IL 60619
Chatham Business Association, Small Business Development Inc. |  © copyright 2016
800 East 78th Street, Chicago, Illinois 60619Â
(Office) 773-994-5006 | (Fax)Â 773-855-8905
What is a Special Service Area (SSA)?
The Special Service Area (SSA) program is a mechanism for contiguous industrial, commercial and residential areas to fund expanded services and programs through a localized property tax levy. These enhanced services and programs are in addition to services and programs currently provided through the city. SSA funded projects could include but are not limited to: security services, area marketing and advertising assistance, promotional activities such as parades and festivals, or any variety of small scale capital improvements which could be supported through a modest property tax levy.
About SSA #51 â Chatham Cottage Grove
The Chicago City Council passed the Establishment Ordinance for the SSA #51 â Chatham Cottage Grove on December 8, 2010.
The general boundaries of SSA #51 begins at 95th and Stony Island going west to include only north side of 95th Street to Dobson; then both sides of 95th street to Cottage Grove; then north along both sides of Cottage Grove to include both sides of 87th street between Champlain and Ingleside; as well as the shopping mall on the west side of Cottage Grove between 87th Street and 84th Street; then north along Cottage to 79th Street to include both sides of 79th Street between Champlain and Greenwood; then north along Cottage Grove to 75th Street to include both sides of 75th street between Indian and Drexel.
SSA #51 is administered by CHATHAM BUSINESS ASSOCIATION SBDI, and currently provides funds for Maintenance and Beautification, Debris and Snow Removal; Façade Enhancement; Economic Development; Marketing and Safety and will afford the opportunity for various promotional events in Chatham and its surrounding communities.Â
SSA #51 Commissioners
Veta L. Caldwell-Charles
Lamont Smith
Patricia McCoy
Clarence Glover
SSA #51 Commissioner Applicants
SSA #51 Commissioner Mtgs Â
All meetings will be held at the QBG Foundation:  806 East 78th Street, Chicago IL 60619. Click Here  for Map
ednesday, March 13, 2019
12:00pm - 1:00pm
Wednesday, June 12, 2019
6:00pm - 7:00pm
Wednesday, October 16, 2019
12:00pm - 1:00pm
Wednesday, December 11, 2019
6:00pm - 7:00pm
For more information about Special Service Area #51, please contact Karletta Kelly at 773-994-5006 Ext. 1006 or karlettakelly@cbaworks.org
âAdd SSA #51 Commisioner's Open Meeting Dates to your calendar today! Click Here
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/files/chi_ssa_54.html b/tests/files/chi_ssa_54.html
new file mode 100644
index 000000000..4a159d7d0
--- /dev/null
+++ b/tests/files/chi_ssa_54.html
@@ -0,0 +1,699 @@
+
+
+
+
+
+
+
+
+
+ SSA #54 - Rogers Park Business Alliance
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Sheridan Road Special Service Area #54
+
+
Sheridan Road Special Service Area (SSA) #54 includes Sheridan Road from Devon Avenue to Farwell Avenue. The SSA has provided programs and services in the commercial district since 2012.
+
RogersEdge Retail Guide SSA #54 Map Sheridan BIP & Landscaping Flyer
+
Programs
+
+Advertising and Promotion: We develop promotions, campaigns and business retention and attraction materials.
+Business Improvement Program (BIP): We promote and revitalize the commercial buildings within the SSA by providing financial and technical assistance to owners and tenants who wish to improve their storefronts. Through this program, owners and tenants are eligible for a 50% rebate up to $5,000 on improvements made to their façade. Download application here .
+Marketing: We market the business districts within the SSA #54 by organizing and providing funding to events and public art programs such as Summer on the Plaza and Polar Palooza .
+Landscape Rebate Program: We promote beautification of the SSA by providing up to 50% of the associated costs with a maximum rebate not to exceed $500 for any landscaping planted outside the business within the Sheridan Road SSA #54 boundaries. Applications will be considered in the order in which they are received until all funding is disbursed for the fiscal year. Download application here .
+Outreach: We visit businesses within the SSA to provide technical assistance and ensure that business owners are aware of all the programs, services and resources available to them.
+Public Way Aesthetics: We install holiday lighting, maintain street pole banners and purchase streetscape elements, as needed.
+Public Way Maintenance: We regularly conduct field checks of the public way.
+Small Business Improvement Fund (SBIF): We promote and revitalize the commercial buildings within the Tax Increment Financing District by providing financial advice and technical assistance to the owners and tenants who wish to improve their storefronts. Through this program, owners and tenants are eligible for a 50% rebate up to $150,000 on improvements made to their building/business.
+Tenant Retention/Attraction: We hold business attraction workshops and give presentations to recruit new businesses to the commercial corridors and support current businesses. We also provide technical assistance to businesses and property owners including on-site visits.
+
+
Documents
+
2015 SSA #54 Audit 2016-2017 SSA #54 Audit Business Improvement Program Application 2018 Landscaping Rebate Application 2019 Commissioner Application
+
Commissioners
+
Heather Hill (Chair) – Resident Chris Bell (Secretary) – Business owner; Flatts & Sharpe Music Co. Tony Fox (Treasurer) – Property & business owner; The 400 Theater Jennifer Clark – AVP of Campus and Community Planning; Loyola University Sara Blackstone Lukens – Business owner; ChiTown Magpie
+
+
+
+
+
+
+
+
+
+
+
2019 Meetings
+
+SPECIAL MEETING: Thursday, July 11 at Starbucks, 6738 N. Sheridan Rd. at 8:30 a.m .
+No August meeting. Instead the next meeting will be held Thursday, September 12 at Starbucks, 6738 N. Sheridan Rd. at 8:30 a.m .
+Next meeting is Thursday, November 14 at 8:30 a.m . at 6740 N. Sheridan Rd. 2nd floor.
+Join us for the SSA annual meeting on December 12th at 9 a.m. at the Teal Room, 1406 W. Morse Ave. Information here .
+
+
* Meeting locations, dates and times are subject to change, please check back one week prior to the meeting to verify the information.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Stay Connected Subscribe to our newsletter
+
+
+
+
+
+
+
+
+
+
+
+
Donate to RPBA Contributions of any size can make a huge difference
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Rogers Park Business Alliance 1448 W. Morse Ave. Chicago, IL 60626 Phone: 773.508.5885 Fax: 773.508.9488 Email: info@rpba.org
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/files/chi_ssa_54_detail.html b/tests/files/chi_ssa_54_detail.html
new file mode 100644
index 000000000..9e6756cd9
--- /dev/null
+++ b/tests/files/chi_ssa_54_detail.html
@@ -0,0 +1,841 @@
+
+
+
+
+
+
+Sheridan Road SSA #54 Commissioners Meeting - Nov 14, 2019
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Sheridan Road SSA #54 Commissioners Meeting
+
+
+
+
+ Share:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Name:
+ Sheridan Road SSA #54 Commissioners Meeting
+
+
+
+ Date:
+ November 14, 2019
+
+
+ Time:
+ 8:30 AM - 9:30 AM CST
+
+
+
+
+
Event Description:
+
+
Sheridan Road SSA #54
+
+Sheridan Road Special Service Area #54 Commissioners meet monthly to discuss initiatives, review programs and budgets for Sheridan Road SSA #54. These meetings are open to the public.
+
+Only the Mayor appointed and vetted Commissioners may make motions and vote.
+
+Meetings are held on every second Thursday of the month except at 6744 N. Sheridan Rd. 2nd Floor at 8:30 a.m.
+
+* Meeting locations, dates and times are subject to change, please check back one week prior to the meeting to verify information.
+
+More information contact Rogers Park Business Alliance, 773-508-5885 or visit,
r pba.org/ssa-54 .
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Stay Connected Subscribe to our newsletter
+
+
+
+
+
+
+
+
+
+
+
+
Donate to RPBA Contributions of any size can make a huge difference
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Rogers Park Business Alliance 1448 W. Morse Ave. Chicago, IL 60626 Phone: 773.508.5885 Fax: 773.508.9488 Email: info@rpba.org
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/files/chi_ssa_5_minutes.html b/tests/files/chi_ssa_5_minutes.html
new file mode 100644
index 000000000..5177a7cfd
--- /dev/null
+++ b/tests/files/chi_ssa_5_minutes.html
@@ -0,0 +1,375 @@
+
+
+
+
+
+
+
+
+
+
+ Meeting Minutes | South Chicago Parents & Friends
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Meeting Minutes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Change this in Theme Options
+
+
Change this in Theme Options
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/test_chi_ssa_5.py b/tests/test_chi_ssa_5.py
new file mode 100644
index 000000000..a60157ba1
--- /dev/null
+++ b/tests/test_chi_ssa_5.py
@@ -0,0 +1,88 @@
+from datetime import datetime
+from os.path import dirname, join
+
+import pytest
+from city_scrapers_core.constants import COMMISSION, PASSED, TENTATIVE
+from city_scrapers_core.utils import file_response
+from freezegun import freeze_time
+
+from city_scrapers.spiders.chi_ssa_5 import ChiSsa5Spider
+
+spider = ChiSsa5Spider()
+
+freezer = freeze_time("2018-10-12")
+freezer.start()
+minutes_req = file_response(
+ join(dirname(__file__), "files", "chi_ssa_5_minutes.html"),
+ url="http://scpf-inc.org/ssa5/meeting-minutes/",
+)
+spider.meetings = spider._parse_current_year(
+ file_response(
+ join(dirname(__file__), "files", "chi_ssa_5.html"),
+ url="http://scpf-inc.org/ssa5/meeting-calendar/",
+ )
+)
+parsed_items = [item for item in spider._parse_minutes(minutes_req)]
+freezer.stop()
+
+
+def test_title():
+ assert parsed_items[0]["title"] == "Regular Commission"
+ assert parsed_items[4]["title"] == "Special Commission"
+
+
+def test_start():
+ assert parsed_items[0]["start"] == datetime(2018, 1, 25, 14)
+
+
+def test_end():
+ assert parsed_items[0]["end"] is None
+
+
+def test_id():
+ assert parsed_items[0]["id"] == "chi_ssa_5/201801251400/x/regular_commission"
+
+
+def test_status():
+ assert parsed_items[0]["status"] == PASSED
+ assert parsed_items[13]["status"] == TENTATIVE
+ assert parsed_items[-1]["status"] == PASSED
+
+
+def test_links():
+ assert parsed_items[0]["links"] == [
+ {
+ "href": "http://scpf-inc.org/wp-content/uploads/2018/04/January-Agenda.pdf",
+ "title": "Agenda",
+ },
+ {
+ "href": "http://scpf-inc.org/wp-content/uploads/2018/04/SSA-Meeting-Minutes-January-25-2018.pdf", # noqa
+ "title": "Minutes",
+ },
+ ]
+ assert parsed_items[11]["links"] == []
+
+
+def test_source():
+ assert parsed_items[0]["source"] == "http://scpf-inc.org/ssa5/meeting-calendar/"
+ assert parsed_items[-1]["source"] == "http://scpf-inc.org/ssa5/meeting-minutes/"
+
+
+@pytest.mark.parametrize("item", parsed_items)
+def test_description(item):
+ assert item["description"] == ""
+
+
+@pytest.mark.parametrize("item", parsed_items)
+def test_all_day(item):
+ assert item["all_day"] is False
+
+
+@pytest.mark.parametrize("item", parsed_items)
+def test_location(item):
+ assert item["location"] == spider.location
+
+
+@pytest.mark.parametrize("item", parsed_items)
+def test_classification(item):
+ assert item["classification"] == COMMISSION
diff --git a/tests/test_chi_ssa_51.py b/tests/test_chi_ssa_51.py
new file mode 100644
index 000000000..bee7442c3
--- /dev/null
+++ b/tests/test_chi_ssa_51.py
@@ -0,0 +1,81 @@
+from datetime import datetime
+from os.path import dirname, join
+
+import pytest
+from city_scrapers_core.constants import COMMISSION, PASSED
+from city_scrapers_core.utils import file_response
+from freezegun import freeze_time
+
+from city_scrapers.spiders.chi_ssa_51 import ChiSsa51Spider
+
+test_response = file_response(
+ join(dirname(__file__), "files", "chi_ssa_51.html"),
+ url="http://www.cbatechworks.org/",
+)
+spider = ChiSsa51Spider()
+
+freezer = freeze_time("2019-07-19")
+freezer.start()
+
+parsed_items = [item for item in spider.parse(test_response)]
+
+freezer.stop()
+
+
+def test_start():
+ assert parsed_items[0]["start"] == datetime(2019, 3, 13, 12, 0)
+
+
+def test_end():
+ assert parsed_items[0]["end"] == datetime(2019, 3, 13, 13, 0)
+
+
+def test_id():
+ assert parsed_items[0]["id"] == "chi_ssa_51/201903131200/x/commission"
+
+
+def test_status():
+ assert parsed_items[0]["status"] == PASSED
+
+
+@pytest.mark.parametrize("item", parsed_items)
+def test_all_day(item):
+ assert item["all_day"] is False
+
+
+@pytest.mark.parametrize("item", parsed_items)
+def test_title(item):
+ assert item["title"] == "Commission"
+
+
+@pytest.mark.parametrize("item", parsed_items)
+def test_description(item):
+ assert item["description"] == ""
+
+
+@pytest.mark.parametrize("item", parsed_items)
+def test_time_notes(item):
+ assert item["time_notes"] == ""
+
+
+@pytest.mark.parametrize("item", parsed_items)
+def test_location(item):
+ assert item["location"] == {
+ "address": "806 East 78th Street, Chicago IL 60619",
+ "name": "QBG Foundation",
+ }
+
+
+@pytest.mark.parametrize("item", parsed_items)
+def test_source(item):
+ assert item["source"] == "http://www.cbatechworks.org/"
+
+
+@pytest.mark.parametrize("item", parsed_items)
+def test_links(item):
+ assert item["links"] == []
+
+
+@pytest.mark.parametrize("item", parsed_items)
+def test_classification(item):
+ assert item["classification"] == COMMISSION
diff --git a/tests/test_chi_ssa_54.py b/tests/test_chi_ssa_54.py
new file mode 100644
index 000000000..fe21d65d2
--- /dev/null
+++ b/tests/test_chi_ssa_54.py
@@ -0,0 +1,78 @@
+from datetime import datetime
+from os.path import dirname, join
+
+import pytest # noqa
+from city_scrapers_core.constants import COMMISSION, PASSED
+from city_scrapers_core.utils import file_response
+from freezegun import freeze_time
+
+from city_scrapers.spiders.chi_ssa_54 import ChiSsa54Spider
+
+test_response = file_response(
+ join(dirname(__file__), "files", "chi_ssa_54.html"),
+ url="https://rpba.org/ssa-54/",
+)
+test_detail_response = file_response(
+ join(dirname(__file__), "files", "chi_ssa_54_detail.html"),
+ url="https://business.rpba.org/events/details/sheridan-road-ssa-54-commissioners-meeting-7970", # noqa
+)
+spider = ChiSsa54Spider()
+
+freezer = freeze_time("2019-12-10")
+freezer.start()
+
+spider.link_date_map = spider._parse_links(test_response)
+parsed_item = [item for item in spider._parse_detail(test_detail_response)][0]
+
+freezer.stop()
+
+
+def test_title():
+ assert parsed_item["title"] == "Commission"
+
+
+def test_description():
+ assert parsed_item["description"] == ""
+
+
+def test_start():
+ assert parsed_item["start"] == datetime(2019, 11, 14, 8, 30)
+
+
+def test_end():
+ assert parsed_item["end"] == datetime(2019, 11, 14, 9, 30)
+
+
+def test_time_notes():
+ assert parsed_item["time_notes"] == ""
+
+
+def test_id():
+ assert parsed_item["id"] == "chi_ssa_54/201911140830/x/commission"
+
+
+def test_status():
+ assert parsed_item["status"] == PASSED
+
+
+def test_location():
+ assert parsed_item["location"] == {
+ "address": "6740 N. Sheridan Rd. chicago, IL 60626",
+ "name": "",
+ }
+
+
+def test_source():
+ assert parsed_item["source"] == test_detail_response.url
+
+
+def test_links():
+ assert parsed_item["links"] == []
+
+
+def test_classification():
+ assert parsed_item["classification"] == COMMISSION
+
+
+def test_all_day():
+ assert parsed_item["all_day"] is False
From 2e7fbe5aa3c62b2a4d5f476b5c9af8883fe518c8 Mon Sep 17 00:00:00 2001
From: Daniel Simmons-Ritchie
<37225902+SimmonsRitchie@users.noreply.github.com>
Date: Tue, 16 Jul 2024 15:40:59 -0500
Subject: [PATCH 2/2] deprecate: chi_ssa_5
---
city_scrapers/spiders/chi_ssa_5.py | 145 -----------
tests/files/chi_ssa_5.html | 379 -----------------------------
tests/files/chi_ssa_5_minutes.html | 375 ----------------------------
tests/test_chi_ssa_5.py | 88 -------
4 files changed, 987 deletions(-)
delete mode 100644 city_scrapers/spiders/chi_ssa_5.py
delete mode 100644 tests/files/chi_ssa_5.html
delete mode 100644 tests/files/chi_ssa_5_minutes.html
delete mode 100644 tests/test_chi_ssa_5.py
diff --git a/city_scrapers/spiders/chi_ssa_5.py b/city_scrapers/spiders/chi_ssa_5.py
deleted file mode 100644
index 237f1ca6f..000000000
--- a/city_scrapers/spiders/chi_ssa_5.py
+++ /dev/null
@@ -1,145 +0,0 @@
-import re
-from datetime import datetime, time
-
-import scrapy
-from city_scrapers_core.constants import COMMISSION
-from city_scrapers_core.items import Meeting
-from city_scrapers_core.spiders import CityScrapersSpider
-
-
-class ChiSsa5Spider(CityScrapersSpider):
- name = "chi_ssa_5"
- agency = "Chicago Special Service Area #5 Commercial Ave"
- timezone = "America/Chicago"
- start_urls = ["http://scpf-inc.org/ssa5/meeting-calendar/"]
- location = {
- "address": "3030 E 92nd St Chicago, IL 60617",
- "name": "MB Financial Bank",
- }
-
- def parse(self, response):
- """
- `parse` should always `yield` Meeting items.
-
- Change the `_parse_title`, `_parse_start`, etc methods to fit your scraping
- needs.
- """
- if "3030" not in response.text:
- raise ValueError("Meeting address has changed")
-
- self.meetings = self._parse_current_year(response)
- yield scrapy.Request(
- "http://scpf-inc.org/ssa5/meeting-minutes/",
- callback=self._parse_minutes,
- dont_filter=True,
- )
-
- def _parse_current_year(self, response):
- description = " ".join(response.css(".page-post-content *::text").extract())
- self._validate_location(description)
-
- items = []
- for item in response.css(".page-post-content > *"):
- items.extend(
- [scrapy.Selector(text=s) for s in item.extract().split(" ")]
- )
-
- meetings = []
- for item in items:
- item_text = " ".join(item.css("* ::text").extract())
- start = self._parse_start(item_text)
- if not start:
- continue
- meeting = Meeting(
- title=self._parse_title(item_text),
- description="",
- classification=COMMISSION,
- start=start,
- end=None,
- time_notes="",
- all_day=False,
- location=self.location,
- links=self._parse_links(item),
- source=response.url,
- )
- meeting["status"] = self._get_status(meeting)
- meeting["id"] = self._get_id(meeting)
- meetings.append(meeting)
- return meetings
-
- def _parse_minutes(self, response):
- """
- Parse the minutes page, matching with existing events if found
- """
- for item in response.css(".page-post-content a"):
- text = item.xpath("text()").extract_first()
- if not text:
- continue
- start = self._parse_start(text, minutes=True)
- if not start:
- continue
- links = [{"href": item.attrib["href"], "title": "Minutes"}]
- date_match = [
- idx
- for idx, i in enumerate(self.meetings)
- if i["start"].date() == start.date()
- ]
- if len(date_match):
- self.meetings[date_match[0]]["links"].extend(links)
- else:
- meeting = Meeting(
- title=self._parse_title(text),
- description="",
- classification=COMMISSION,
- start=start,
- end=None,
- time_notes="",
- all_day=False,
- location=self.location,
- links=links,
- source=response.url,
- )
- meeting["status"] = self._get_status(meeting)
- meeting["id"] = self._get_id(meeting)
- self.meetings.append(meeting)
- for meeting in self.meetings:
- yield meeting
-
- def _parse_title(self, text):
- """Parse or generate meeting title."""
- if "special" in text.lower():
- return "Special Commission"
- return "Regular Commission"
-
- def _parse_start(self, text, minutes=False):
- """Parse start datetime."""
- parsed_date = None
- if minutes:
- date_match = re.search(r"\d{2}/\d{2}/\d{4}", text)
- if date_match:
- parsed_date = datetime.strptime(date_match.group(), "%m/%d/%Y")
- else:
- date_match = re.search(r"\w{3,9} \d{1,2}, \d{4}", text)
- if date_match:
- parsed_date = datetime.strptime(date_match.group(), "%B %d, %Y")
- if parsed_date:
- return datetime.combine(parsed_date.date(), time(14))
-
- def _parse_links(self, item):
- """
- Parse or generate documents.
- """
- links = []
- for link in item.css("a"):
- links.append(
- {
- "title": " ".join(link.css("*::text").extract()),
- "href": link.attrib["href"],
- }
- )
- return links
-
- def _validate_location(self, description):
- """Check that location hasn't changed or raise an exception"""
- if "3030 E" not in description:
- raise ValueError("Meeting location has changed")
diff --git a/tests/files/chi_ssa_5.html b/tests/files/chi_ssa_5.html
deleted file mode 100644
index dc9e96faf..000000000
--- a/tests/files/chi_ssa_5.html
+++ /dev/null
@@ -1,379 +0,0 @@
-
-
-
-
-
-
-
-
-
-
- MEETING CALENDAR | South Chicago Parents & Friends
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
MEETING CALENDAR
-
-
-
-
2018 PUBLIC MEETING DATES
-
January 25, 2018 – Agenda
-February 22, 2018 – Agenda
-March 22, 2018 – Agenda
-April 26, 2018 – Agenda
-May 7, 2018 – Special Meeting – Agenda
-May 24, 2018 – Agenda
-June 28, 2018 – Agenda
-July 12, 2018 – Agenda
-August 23, 2018 – Agenda
-September 27, 2018 – Agenda
-October 2, 2018 – Special Meeting – Agenda
-October 25, 2018
-November 29, 2018
-December 20, 2018
-
Meeting held at 2:00 pm at MB Financial Bank, 3030 E. 92nd Street, Chicago IL
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Change this in Theme Options
-
-
Change this in Theme Options
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/tests/files/chi_ssa_5_minutes.html b/tests/files/chi_ssa_5_minutes.html
deleted file mode 100644
index 5177a7cfd..000000000
--- a/tests/files/chi_ssa_5_minutes.html
+++ /dev/null
@@ -1,375 +0,0 @@
-
-
-
-
-
-
-
-
-
-
- Meeting Minutes | South Chicago Parents & Friends
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Meeting Minutes
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Change this in Theme Options
-
-
Change this in Theme Options
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/tests/test_chi_ssa_5.py b/tests/test_chi_ssa_5.py
deleted file mode 100644
index a60157ba1..000000000
--- a/tests/test_chi_ssa_5.py
+++ /dev/null
@@ -1,88 +0,0 @@
-from datetime import datetime
-from os.path import dirname, join
-
-import pytest
-from city_scrapers_core.constants import COMMISSION, PASSED, TENTATIVE
-from city_scrapers_core.utils import file_response
-from freezegun import freeze_time
-
-from city_scrapers.spiders.chi_ssa_5 import ChiSsa5Spider
-
-spider = ChiSsa5Spider()
-
-freezer = freeze_time("2018-10-12")
-freezer.start()
-minutes_req = file_response(
- join(dirname(__file__), "files", "chi_ssa_5_minutes.html"),
- url="http://scpf-inc.org/ssa5/meeting-minutes/",
-)
-spider.meetings = spider._parse_current_year(
- file_response(
- join(dirname(__file__), "files", "chi_ssa_5.html"),
- url="http://scpf-inc.org/ssa5/meeting-calendar/",
- )
-)
-parsed_items = [item for item in spider._parse_minutes(minutes_req)]
-freezer.stop()
-
-
-def test_title():
- assert parsed_items[0]["title"] == "Regular Commission"
- assert parsed_items[4]["title"] == "Special Commission"
-
-
-def test_start():
- assert parsed_items[0]["start"] == datetime(2018, 1, 25, 14)
-
-
-def test_end():
- assert parsed_items[0]["end"] is None
-
-
-def test_id():
- assert parsed_items[0]["id"] == "chi_ssa_5/201801251400/x/regular_commission"
-
-
-def test_status():
- assert parsed_items[0]["status"] == PASSED
- assert parsed_items[13]["status"] == TENTATIVE
- assert parsed_items[-1]["status"] == PASSED
-
-
-def test_links():
- assert parsed_items[0]["links"] == [
- {
- "href": "http://scpf-inc.org/wp-content/uploads/2018/04/January-Agenda.pdf",
- "title": "Agenda",
- },
- {
- "href": "http://scpf-inc.org/wp-content/uploads/2018/04/SSA-Meeting-Minutes-January-25-2018.pdf", # noqa
- "title": "Minutes",
- },
- ]
- assert parsed_items[11]["links"] == []
-
-
-def test_source():
- assert parsed_items[0]["source"] == "http://scpf-inc.org/ssa5/meeting-calendar/"
- assert parsed_items[-1]["source"] == "http://scpf-inc.org/ssa5/meeting-minutes/"
-
-
-@pytest.mark.parametrize("item", parsed_items)
-def test_description(item):
- assert item["description"] == ""
-
-
-@pytest.mark.parametrize("item", parsed_items)
-def test_all_day(item):
- assert item["all_day"] is False
-
-
-@pytest.mark.parametrize("item", parsed_items)
-def test_location(item):
- assert item["location"] == spider.location
-
-
-@pytest.mark.parametrize("item", parsed_items)
-def test_classification(item):
- assert item["classification"] == COMMISSION