initial commit

This commit is contained in:
epiii2 2021-03-31 04:51:44 +00:00
commit 3fdfe7b6d6
17 changed files with 2180 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
__pycache__/

1
README.md Normal file
View File

@ -0,0 +1 @@
# PGNP: Philadelphia Gemini News Proxy

3
pgnp/__init__.py Normal file
View File

@ -0,0 +1,3 @@
# https://tildegit.org/solderpunk/molly-brown
# gemini://gemini.circumlunar.space:1965/docs/specification.gmi

17
pgnp/__main__.py Normal file
View File

@ -0,0 +1,17 @@
import re
import os
from .handlers import HANDLERS, Handler
def main():
path_info = os.getenv("PATH_INFO", "")
path_query = os.getenv("QUERY_STRING", "")
if path_query:
path_info = path_info + "?" + path_query
path_base = re.sub("[/?].*$", "", path_info)
handler = HANDLERS.get(path_base, Handler)
h = handler(path_info)
h.parse()
h.render()
if __name__ == "__main__":
main()

475
pgnp/handlers.py Normal file
View File

@ -0,0 +1,475 @@
import re
import sys
from pathlib import Path
from requests_html import HTMLSession
# I think all three of these are actually wordpress under the hood, and they
# might also be exposing a REST api. Can I ditch all this HTML parsing and
# just GET JSON?!
# https://whyy.org/wp-json/wp/v2/pages
# Hm, maybe not. WHYY at least doesn't expose the bulk of the content that
# way. Still, might help with metadata. For example, if I'm on some random
# URL like https://whyy.org/nice/ I can see that it's actually "page-id-497788"
# and then request https://whyy.org/wp-json/wp/v2/pages/497788
# There are other types too but I can't find any live examples of them yet.
ROOT = "/proxy/"
HEADINGS = ["h%d" % num for num in range(1, 7)]
def first_text(elems):
"""Text of the first element, or an empty string if the list is empty."""
try:
return elems[0].text
except IndexError:
return ""
def slug(txt):
"""Replace all non-alphanumeric characters with dashes."""
return re.sub("[^A-Za-z0-9]", "-", txt)
class Handler:
def __init__(self, path):
self.session = HTMLSession()
self.path_base = re.sub("/.*$", "", path)
self.path = re.sub("^[^/?]+", "", path)
self.root_html = ""
self.root_gmni = ""
self.status_code = "20"
self.ctype = "text/gemini"
self.output = ""
def get(self):
response = self.session.get(self.root_html + self.path)
return response
def parse(self):
self.output = f"No handler defined for {self.path_base}\r\n"
self.output += "=> . Go back to the index\r\n"
def make_proxy_snippet(self):
links = [
(self.root_html + self.path, "HTML Original"),
(self.root_gmni, "Proxy Home Page")]
output = "\r\n".join([f"=> {lnk[0]} {lnk[1]}" for lnk in links])
output += "\r\n\r\n"
return output
def render(self):
sys.stdout.buffer.write(f"{self.status_code} {self.ctype}\r\n".encode())
if self.status_code == "10" or self.ctype.startswith("text/"):
sys.stdout.buffer.write(self.output.encode())
else:
sys.stdout.buffer.write(self.output)
def href(self, anchor, attrib="href"):
try:
link = anchor.attrs.get(attrib, "")
except AttributeError:
link = anchor
if not link or not self.root_html or not self.root_gmni:
return link
if link.startswith("/"):
return self.root_gmni + link
else:
return link.replace(self.root_html, self.root_gmni)
class HandlerDefault(Handler):
def parse(self):
for key in HANDLERS:
if key:
self.output += f"=> {ROOT}{key}\r\n"
class HandlerCitizen(Handler):
def __init__(self, path):
super().__init__(path)
self.root_html = "https://thephiladelphiacitizen.org/"
self.root_gmni = ROOT + "thephiladelphiacitizen.org/"
def parse(self):
r = self.get()
if r.headers["Content-Type"] in ["image/png", "image/jpeg"]:
self.ctype = "image/png"
self.output = r.content
return
output = ""
if r.html.find("body.home"):
output += self.parse_main_title(r.html)
output += self.make_proxy_snippet()
output += self.parse_home_page(r.html)
output += self.parse_menu(r.html)
elif r.html.find("body.category") or r.html.find("body.author"):
output += self.parse_main_title(r.html)
output += self.make_proxy_snippet()
output += self.parse_category_page(r.html)
output += self.parse_menu(r.html)
elif r.html.find("body.single-post"):
output += self.make_proxy_snippet()
output += self.parse_article(r.html)
output += self.parse_menu(r.html)
else:
output += "Unknown page type. View this via HTTPS instead:\r\n"
output += f"=> {self.root_html}{self.path}\r\n"
self.output = output
def parse_main_title(self, html):
main_title = first_text(html.find("a#logo h1"))
sub_title = first_text(html.find("a#logo p"))
return f"# {main_title}\r\n{sub_title}\r\n\r\n"
def parse_home_page(self, html):
output = ""
article_links = [(self.href(a), first_text(a.find("h1"))) for a in html.find("div.featuredStory a.featuredStory-titlebar")]
article_links += [(self.href(a), first_text(a.find("h1"))) for a in html.find("div.storyList a")]
output += "## Latest Articles\r\n\r\n"
for url, title in article_links:
output += f"=> {url} {title}\r\n"
return output
def parse_category_page(self, html):
output = ""
category_title = first_text(html.find("main header h1"))
article_links = []
for a in html.find("main div.row a"):
url = self.href(a)
for heading in HEADINGS:
title = first_text(a.find(heading))
if title:
break
article_links.append((url, title))
if category_title:
output += f"## {category_title}\r\n\r\n"
for url, title in article_links:
output += f"=> {url} {title}\r\n"
output += "\r\n"
return output
def parse_article(self, html):
output = ""
article_title = first_text(html.find("div.article-headline h1"))
author = first_text(html.find("div.postAuthor"))
date = first_text(html.find("div.postDate"))
output += f"# {article_title}\r\n{author}\r\n{date}\r\n\r\n"
for elem in html.find("section.mainText article > *"):
if elem.tag == "p":
if elem.find("span strong") or elem.find("span b"):
output += f"## {elem.text}\r\n\r\n"
elif elem.find("strong"):
if elem.text != "RELATED VIDEO CONTENT":
output += f"{elem.text}\r\n\r\n"
else:
output += f"{elem.text}\r\n\r\n"
elif elem.tag in ["ol", "ul"]:
for item in elem.find("li"):
output += f"* {item.text}\r\n"
output += "\r\n"
elif elem.tag == "blockquote":
# These are repeats of quotes embedded in the article.
pass
elif elem.tag == "figure":
try:
imgsrc = self.href(elem.find("img")[0], "src")
caption = first_text(elem.find("figcaption"))
except IndexError:
pass
else:
if caption:
output += f"=> {imgsrc} Figure: {caption}\r\n\r\n"
else:
output += f"=> {imgsrc} Figure\r\n\r\n"
elif elem.tag == "div":
classes = elem.attrs.get("class", ())
if "inline_link_container" in classes:
# This is a related link. maybe hold until the end and
# then list of links?
# TODO
pass
elif "social_footer" in classes:
# This is a block of social network links
pass
return output
def _fallback_link(self, elem, prefix):
"""Kludge for div.voiceWrap that is missing links."""
a_elems = elem.find("a")
if a_elems:
return self.href(a_elems[0])
else:
return self.href(prefix + slug(elem.text))
def parse_menu(self, html):
menus = {}
for menudiv in html.find("div.menuContent"):
key = first_text(menudiv.find("strong"))
# Evidently most of these links are added after page-load by
# javascript for some reason. I think I can kludge it to work
# without having to restort to javascript!
if menudiv.attrs.get("id", "") == "voiceWrap":
links = [(self._fallback_link(li, "/author/"), li.text) for li in menudiv.find("li")]
else:
links = [(self.href(a), a.text) for a in menudiv.find("a")]
if not key in menus:
menus[key] = []
menus[key] += links
output = "## Site Menu\r\n\r\n"
navlinks = [(self.href(a), a.text) for a in html.find("div.navContainer-wrap a.nothing")]
for url, title in navlinks:
output += f"=> {url} {title}\r\n"
output += "\r\n"
for section, linkset in menus.items():
if section:
output += f"### {section}\r\n\r\n"
for url, title in linkset:
output += f"=> {url} {title}\r\n"
output += "\r\n"
return output
# Though I just found: https://billypenn.com/wp-json/ !
# and now also https://thephiladelphiacitizen.org/wp-json !!
class HandlerBillyPenn(Handler):
def __init__(self, path):
# I don't know why my use of the status code 10 seems to do .../?query
# instead of .../?s=query but this kludgey hack makes it work like I
# want
if "?" in path and "=" not in path:
path = path.replace("?", "?s=")
super().__init__(path)
self.root_html = "https://billypenn.com/"
self.root_gmni = ROOT + "billypenn.com/"
def parse(self):
r = self.get()
if r.headers["Content-Type"] in ["image/png", "image/jpeg"]:
self.ctype = "image/png"
self.output = r.content
return
output = ""
if r.html.find("body.home"):
output += "# Billy Penn\r\n\r\n"
output += self.make_proxy_snippet()
output += self.parse_home_page(r.html)
output += self.parse_menu(r.html)
elif r.html.find("body.archive"):
output += "# Billy Penn\r\n\r\n"
output += self.make_proxy_snippet()
output += self.parse_category_page(r.html)
output += self.parse_menu(r.html)
elif r.html.find("body.search"):
output += "# Billy Penn\r\n\r\n"
parts = r.url.split("?", 1)
if len(parts) > 1:
_, query = parts[1].split("=", 1)
if query:
output += self.make_proxy_snippet()
output += self.parse_search_page(r.html)
output += self.parse_menu(r.html)
else:
output = ""
self.status_code = "10"
self.ctype = "Search Query"
elif r.html.find("body.single"):
output += "# Billy Penn\r\n\r\n"
output += self.make_proxy_snippet()
output += self.parse_article(r.html)
output += self.parse_menu(r.html)
else:
output += "Unknown page type. View this via HTTPS instead:\r\n"
output += f"=> {self.root_html}{self.path}\r\n"
self.output = output
def parse_home_page(self, html):
output = ""
article_links = [(self.href(a), a.text) for a in html.find("main article div.stream-item__body h1 a")]
for url, title in article_links:
output += f"=> {url} {title}\r\n"
output += self.parse_paginate_link(html)
return output
def parse_search_page(self, html):
output = ""
title = first_text(html.find("h1.c-main__title"))
if title:
output += f"## {title}\r\n\r\n"
search_results = first_text(html.find("p.search-tools__total-results"))
output += search_results + "\r\n\r\n"
article_links = [(self.href(a), a.text) for a in html.find("main article h1 a")]
for url, title in article_links:
output += f"=> {url} {title}\r\n"
output += self.parse_paginate_link(html)
return output
def parse_category_page(self, html):
output = ""
category_title = first_text(html.find("main header h1"))
category_desc = first_text(html.find("h2.c-main__description"))
if category_title:
output += f"## {category_title}\r\n"
if category_desc:
output += f"{category_desc}\r\n"
output += "\r\n"
article_links = [(self.href(a), a.text) for a in html.find("main article h1 a")]
for url, title in article_links:
output += f"=> {url} {title}\r\n"
output += self.parse_paginate_link(html)
return output
def parse_paginate_link(self, html):
output = ""
page_links = html.find("a[data-ga-category=pagination]")
if len(page_links) == 1:
url = self.href(page_links[0])
title = page_links[0].text
output += f"\r\n=> {url} {title}\r\n"
return output
def parse_article(self, html):
output = ""
title = first_text(html.find("article header h1"))
author = ""
date = first_text(html.find("article header time"))
for anchor in html.find("article header a[data-ga-label=author]"):
if anchor.text:
author = anchor.text
break
if title:
output += f"# {title}\r\n"
if author:
output += f"{author}\r\n"
if date:
output += f"{date}\r\n"
output += "\r\n"
output += self.parse_header_figure(html)
for elem in html.find("article section.c-main__body > *"):
if elem.tag == "p":
output += f"{elem.text}\r\n\r\n"
elif elem.tag in HEADINGS:
prefix = HEADINGS.index(elem.tag) + 1
prefix = min(4, max(2, prefix))
prefix = prefix * "#"
output += f"{prefix} {elem.text}\r\n\r\n"
return output
def parse_header_figure(self, html):
output = ""
header_figures = html.find("article header figure")
if header_figures:
for figure in header_figures:
try:
imgsrc = self.href(figure.find("img")[0], "src")
caption_h1 = first_text(figure.find("figcaption h1"))
caption_cite = first_text(figure.find("figcaption cite"))
if caption_h1:
caption = f"{caption_h1} ({caption_cite})"
elif caption_cite:
caption = f"Photo by {caption_cite}"
else:
caption = ""
except IndexError:
pass
else:
output += f"=> {imgsrc} {caption}\r\n"
output += "\r\n"
return output
def parse_menu(self, html):
links = [(self.href(a), a.text) for a in html.find("nav.site-nav--primary li a")]
output = "## Site Menu\r\n\r\n"
for url, title in links:
output += f"=> {url} {title}\r\n"
return output
class HandlerWHYYNews(Handler):
def __init__(self, path):
super().__init__(path)
self.root_html = "https://whyy.org/"
self.root_gmni = ROOT + "whyy.org/"
def parse(self):
r = self.get()
if r.headers["Content-Type"] in ["image/png", "image/jpeg"]:
self.ctype = "image/png"
self.output = r.content
return
output = ""
output += self.parse_main_title(r.html)
output += self.parse_secondary_title(r.html)
actual_articles = r.html.find("article.article")
if actual_articles:
output += first_text(actual_articles) + "\r\n"
else:
output += self.parse_article_jumble(r.html)
output += self.parse_menu(r.html)
self.output = output
def parse_main_title(self, html):
output = ""
title = first_text(html.find("header div.site-logo"))
if title:
output = f"# {title}\r\n\r\n"
return output
def parse_secondary_title(self, html):
output = ""
h1 = first_text(html.find("main header h1"))
if h1:
output = f"## {h1}\r\n\r\n"
return output
def parse_article_jumble(self, html):
output = ""
teasers = html.find("article.content-mode--teaser")
for teaser in teasers:
anchor = teaser.find("p.h2-hack a")
if len(anchor) == 1:
url = self.href(anchor[0])
title = anchor[0].text
output += f"=> {url} {title}\r\n"
return output
def parse_article(self, html):
output = ""
article = html.find("article.article")[0]
output += article.text + "\r\n"
return output
def parse_menu(self, html):
output = ""
anchors = html.find("ul#menu-header-menu-main a")
if anchors:
output = "## Site Menu\r\n\r\n"
for anchor in anchors:
url = self.href(anchor)
title = anchor.text
output += f"=> {url} {title}\r\n"
return output
HANDLERS = {
"": HandlerDefault,
"thephiladelphiacitizen.org": HandlerCitizen,
"billypenn.com": HandlerBillyPenn,
"whyy.org": HandlerWHYYNews
}

0
test_pgnp/__init__.py Normal file
View File

View File

@ -0,0 +1,362 @@
<!DOCTYPE html>
<html lang="en-US" class="no-js">
<head>
</head>
<body class="home page-template page-template-page-templates page-template-home page-template-page-templateshome-php page page-id-1547">
<div class="fancyboxes deployed">
<div id="newsletterPopup">
<div class="newsletterSpot">
<div class="popupTitle">
<h3>NEWSLETTER SIGNUP</h3>
</div>
</div>
</div>
</div>
<div id="page" class="hfeed site ">
<header id="masthead" class="site-header" role="banner">
<div class="sectionScale">
<div class="burgerWrap mobile" data-state="close">
<div class="burgerBar first"></div>
<div class="burgerBar second"></div>
<div class="burgerBar third"></div>
</div>
<a href="https://thephiladelphiacitizen.org" id="logo">
<img src="https://thephiladelphiacitizen.org/wp-content/themes/citizen/img/logo.png" class="desktopLogo" alt="The Philadephia Citizen" />
<h1>The Philadelphia Citizen</h1><p>What happened. What it means. And what you can do about it.</p>
</a>
<a class="nlSignup" href="https://thephiladelphiacitizen.org/donate">SUPPORT<br>THE CITIZEN</a>
<div class="socialIcons">
<div class="socialWrap">
<a class="fbBtn" title="Facebook" target="_blank" href="https://www.facebook.com/thephillycitizen"></a>
<a class="twitterBtn" title="Twitter" target="_blank" href="https://twitter.com/@thephilacitizen"></a>
<a class="instaBtn" title="Instagram" target="_blank" href="https://instagram.com/thephiladelphiacitizen"></a>
<a class="linkedinBtn" title="LinkedIn" target="_blank" href="https://www.linkedin.com/company/the-philadelphia-citizen/"></a>
<a class="emailBtn" title="Newsletter" href="https://thephiladelphiacitizen.org/sign-up-for-the-citizen-newsletter/"></a>
<a class="smileBtn" title="Amazon Smile" target="_blank" href="https://smile.amazon.com/ch/46-2777419"></a>
<a class="rssBtn" title="RSS" target="_blank" href="https://feeds.feedburner.com/thephiladelphiacitizen/NqdF"></a>
</div>
<div class="expandBtn"></div>
</div>
<div id="mSearch" class="mobile" data-show="closed">
<div class="searchGlass">
<div class="handle">
<div class="tail"></div>
</div>
</div>
</div>
</div>
</header>
<div id="mobileSearch" class="mobile">
<form method="get" action="https://thephiladelphiacitizen.org/">
<input type="text" id="searchInput" value="" name="s" placeholder="Search">
<input type="submit" id="searchsubmit" value="Search" class="btn" />
</form>
</div>
<div class="pageNav">
<div class="navCenter">
<div class="article-progress">
<div class="article-pg-fill"></div>
</div>
<div id="navContainer">
<div class="bolt">
<img src="https://thephiladelphiacitizen.org/wp-content/themes/citizen/img/footerBolt-small.png" alt="" />
</div>
<div class="navContainer-wrap">
<a href="#" id="menuBtnLink">
<div id="menuBtnWrap" >
<div class="burgerWrap">
<div class="burgerBar first"></div>
<div class="burgerBar second"></div>
<div class="burgerBar third"></div>
</div>
<p>Menu</p>
<div class="menuSpacer"></div>
</div>
</a>
<span>&#9679;</span>
<a href="https://thephiladelphiacitizen.org/events/" class="nothing">
<p>Events</p>
</a>
<span>&#9679;</span>
<a href="https://thephiladelphiacitizen.org/ideas-we-should-steal-festival-2020-videos/" class="nothing">
<p>Ideas We Should Steal Festival</p>
</a>
<span>&#9679;</span>
<a href="https://thephiladelphiacitizen.org/how-to-get-involved-in-your-community/" class="nothing">
<p>Do Something Guides</p>
</a>
<span>&#9679;</span>
<a href="https://thephiladelphiacitizen.org/about/" class="nothing">
<p>About</p>
</a>
<span>&#9679;</span>
<div id="searchLink" href="#">
<p>Search</p>
<form method="get" id="searchform" action="https://thephiladelphiacitizen.org/">
<input type="text" id="searchInput" value="" name="s" placeholder="Search...">
<input type="submit" id="searchsubmit" value="Search" class="btn" />
</form>
<div class="searchWrap">
<div class="searchGlass">
<div class="handle">
<div class="tail"></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div id="dropWrapper">
<div id="dropContent">
<div class="dropSizer">
<div id="topicWrap" class="menuContent">
<strong>Topics</strong>
<ul>
<li><a class="business" title="(20)" href="https://thephiladelphiacitizen.org/category/politics/">Politics</a></li>
<li><a class="business" title="(20)" href="https://thephiladelphiacitizen.org/category/opinion/">Opinion</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/business-and-economy/" target="_blank" rel="noopener noreferrer">Business</a></li>
<li><a class="schools" title="(46)" href="https://thephiladelphiacitizen.org/category/education/">Education</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/urban-development/">Development</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/environment/">Environment</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/health-wellness/">Health</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/philadelphia-citizen-topics/technology/">Tech</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/jobs-philadelphia/">Jobs</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/food-philadelphia/">Food</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/philadelphia-citizen-topics/arts-and-culture/">Arts</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/philadelphia-sports/">Sports</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/lgbtq/">LGBTQ</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/youth-philadelphia/">Youth</a></li>
<li><a class="events" title="(4)" href="https://thephiladelphiacitizen.org/category/philadelphia-events/">Events</a></li>
<li><a href="/about/join-our-team/">Work at The Citizen</a></li>
</ul> </div>
<div id="categoryWrap" class="menuContent">
<strong>Categories</strong>
<ul>
<li><a href="https://thephiladelphiacitizen.org/category/business-and-economy" target="_blank" rel="noopener noreferrer">Business for Good</a></li>
<li><a href="https://thephiladelphiacitizen.org/citizencast-audio-articles/" target="_blank" rel="noopener noreferrer">CitizenCast</a></li>
<li><a href="https://thephiladelphiacitizen.org/tag/philadelphia-citizen-of-the-week/" target="_blank" rel="noopener noreferrer">Citizens of the Week</a></li>
<li><a href="https://thephiladelphiacitizen.org/tag/foodizen-philadelphia/" target="_blank" rel="noopener noreferrer">Foodizen</a></li>
<li><a href="/tag/ideas-we-should-steal-philly" target="_blank" rel="noopener noreferrer">Ideas We Should Steal</a></li>
<li><a href="/category/rubrics/mystery-shopping-philadelphia-city-hall">Mystery Shopper</a></li>
<li><a href="https://thephiladelphiacitizen.org/tag/jason-kelce-eagles-education-season/" target="_blank" rel="noopener noreferrer">Jason Kelces Eagles Education Season</a></li>
<li><a href="https://thephiladelphiacitizen.org/tag/connor-barwin-civic-season/" target="_blank" rel="noopener noreferrer">Connor Barwins Civic Season</a></li>
<li><a href="https://thephiladelphiacitizen.org/tag/malcolm-jenkins-criminal-justice-season-phl/" target="_blank" rel="noopener noreferrer">Malcolm Jenkins Criminal Justice Season</a></li>
</ul> </div>
<div id="voiceWrap" class="menuContent">
<strong>Voices</strong>
<ul>
<li>Connor Barwin</li>
<li>Courtney DuChene</li>
<li>Charles D. Ellison</li>
<li>Jon Geeting</li>
<li>Anne Gemmell</li>
<li>Jill Harkins</li>
<li>Bruce Katz</li>
<li>Jason Kelce</li>
<li>Diana Lind</li>
<li>James Peterson</li>
<li>Larry Platt</li>
<li><a href="https://thephiladelphiacitizen.org/author/jessica-press/">Jessica Blatt Press</a></li>
<li>Katherine Rapin</li>
<li>Roxanne Patel Shepelavy</li>
</ul> </div>
<div id="sponsorWrap" class="menuContent">
<div class="listCol">
<strong>Featured Partners</strong>
<ul>
<li><a href="/board-of-directors/">Board of Directors</a></li>
<li><a href="/corporations-and-foundations">Corporate &amp; Foundation Partners</a></li>
<li><a href="/founding-donors/">Founding Donors</a></li>
</ul> </div>
</div>
</div>
</div>
</div>
</div>
<!-- site-header -->
<div class="nav-bar mobileNav">
<ul>
<li><a href="/" class="selected">Stories</a></li>
<li><a href="https://thephiladelphiacitizen.org/events/" >Events</a></li>
<li><a href="https://thephiladelphiacitizen.org/ideas-we-should-steal-festival-2020-videos/" >Ideas We Should Steal Festival</a></li>
<li><a href="https://thephiladelphiacitizen.org/how-to-get-involved-in-your-community/" >Do Something Guides</a></li>
<li class="parent"><a href="https://thephiladelphiacitizen.org/topic-list">Topics</a>
<div class="submenu">
<ul>
<li><a class="business" title="(20)" href="https://thephiladelphiacitizen.org/category/politics/">Politics</a></li>
<li><a class="business" title="(20)" href="https://thephiladelphiacitizen.org/category/opinion/">Opinion</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/business-and-economy/" target="_blank" rel="noopener noreferrer">Business</a></li>
<li><a class="schools" title="(46)" href="https://thephiladelphiacitizen.org/category/education/">Education</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/urban-development/">Development</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/environment/">Environment</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/health-wellness/">Health</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/philadelphia-citizen-topics/technology/">Tech</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/jobs-philadelphia/">Jobs</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/food-philadelphia/">Food</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/philadelphia-citizen-topics/arts-and-culture/">Arts</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/philadelphia-sports/">Sports</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/lgbtq/">LGBTQ</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/youth-philadelphia/">Youth</a></li>
<li><a class="events" title="(4)" href="https://thephiladelphiacitizen.org/category/philadelphia-events/">Events</a></li>
<li><a href="/about/join-our-team/">Work at The Citizen</a></li>
</ul> </div>
</li>
<li><a href="https://podcasts.apple.com/us/podcast/citizencast/id1348163928#episodeGuid=20023371-2c58-4e1a-83ed-7ef1946f834c" >CitizenCast</a></li>
<li><a href="https://thephiladelphiacitizen.org/about/" >About</a></li>
<li><a href="https://thephiladelphiacitizen.org/donate/" >Support Us</a></li>
<li><a href="https://thephiladelphiacitizen.org/contact/" >Contact</a></li>
<li class="parent"><a>Social</a>
<div class="submenu">
<ul>
<li><a title="Facebook" target="_blank" href="https://www.facebook.com/thephillycitizen">Facebook</a>
<li><a title="Twitter" target="_blank" href="https://twitter.com/@thephilacitizen">Twitter</a>
<li><a title="Instagram" target="_blank" href="https://instagram.com/thephiladelphiacitizen">Instagram</a>
<li><a title="LinkedIn" target="_blank" href="https://www.linkedin.com/company/the-philadelphia-citizen/">LinkedIn</a>
<li><a title="Newsletter" href="https://thephiladelphiacitizen.org/sign-up-for-the-citizen-newsletter/">Newsletter</a>
<li><a title="Amazon Smile" target="_blank" href="https://smile.amazon.com/ch/46-2777419">Amazon Smile</a>
<li><a title="RSS" target="_blank" href="https://feeds.feedburner.com/thephiladelphiacitizen/NqdF">RSS</a>
</ul>
</div>
</li>
</ul>
</div>
<div class="article-progress"></div>
<div id="content" class="site-content">
<div class="overlay"></div>
<div style="display: none;" id="popupCount">0</div> <div class="fancyboxes">
<div id="timedPopup">
<a href="#timedPopup" id="fancyTrigger" class="fancybox"></a>
</div>
</div>
<div id="primary" class="content-area">
<div id="content" class="site-content" role="main">
<div class="articleStrip homeStrip" style="border-top:0;">
<div class="articleWrap">
<ul>
<li>
<a class="thumbnail" href="https://thephiladelphiacitizen.org/things-to-do-in-philadelphia-during-coronavirus/" title="Things to Do in Philadelphia This Weekend" style="background:url(https://thephiladelphiacitizen.org/wp-content/uploads/2021/03/Mural-Arts-Philadelphia-Walking-Tours-2021-150x150.jpg);"></a>
<div class="relatedBlurb">
<a class="relHeadline" href="https://thephiladelphiacitizen.org/things-to-do-in-philadelphia-during-coronavirus/" title="Things to Do in Philadelphia This Weekend">Things to Do in Philadelphia This Weekend</a>
<p class="railAuthor">By <a href="https://thephiladelphiacitizen.org/author/josh-middleton/">Josh Middleton</a></p>
</div>
</li><li>
<a class="thumbnail" href="https://thephiladelphiacitizen.org/will-pop-ups-save-phillys-food-scene/" title="Will Pop-Ups Save Phillys Food Scene?" style="background:url(https://thephiladelphiacitizen.org/wp-content/uploads/2021/02/philly-food-pop-ups-covid-150x150.jpg);"></a>
<div class="relatedBlurb">
<a class="relHeadline" href="https://thephiladelphiacitizen.org/will-pop-ups-save-phillys-food-scene/" title="Will Pop-Ups Save Phillys Food Scene?">Will Pop-Ups Save Phillys Food Scene?</a>
<p class="railAuthor">By <a href="https://thephiladelphiacitizen.org/author/maddy-sweitzer-lamme/">Maddy Sweitzer-Lamme</a></p>
</div>
</li><li>
<a class="thumbnail" href="https://thephiladelphiacitizen.org/disruptive-mayoral-wishlist/" title="A Mayoral Wishlist, Disruptor Edition" style="background:url(https://thephiladelphiacitizen.org/wp-content/uploads/2021/02/Mayoral-wishlist-Philadelphia-1-150x150.jpg);"></a>
<div class="relatedBlurb">
<a class="relHeadline" href="https://thephiladelphiacitizen.org/disruptive-mayoral-wishlist/" title="A Mayoral Wishlist, Disruptor Edition">A Mayoral Wishlist, Disruptor Edition</a>
<p class="railAuthor">By <a href="https://thephiladelphiacitizen.org/author/larry-platt/">Larry Platt</a></p>
</div>
</li><li>
<a class="thumbnail" href="https://thephiladelphiacitizen.org/black-owned-businesses-philadelphia/" title="19 Black-Owned Businesses in Philly That Give Back" style="background:url(https://thephiladelphiacitizen.org/wp-content/uploads/2021/02/FrannyLousPorch_J.Fusco_34_rgb_hd-150x150.jpg);"></a>
<div class="relatedBlurb">
<a class="relHeadline" href="https://thephiladelphiacitizen.org/black-owned-businesses-philadelphia/" title="19 Black-Owned Businesses in Philly That Give Back">19 Black-Owned Businesses in Philly That Give Back</a>
<p class="railAuthor">By <a href="https://thephiladelphiacitizen.org/author/the-philadelphia-citizen-staff/">The Philadelphia Citizen Staff</a></p>
</div>
</li> </ul>
</div>
</div>
<div class="featuredStory">
<a href="https://thephiladelphiacitizen.org/enough-corruption-philly/" class="col" style="background:url(https://thephiladelphiacitizen.org/wp-content/uploads/2021/03/John-Dougherty-Philadelphia-1.jpeg);">
<img class="mobileTileImg" style="display:none;" src="https://thephiladelphiacitizen.org/wp-content/uploads/2021/03/John-Dougherty-Philadelphia-1.jpeg" alt="" />
</a>
<a href="https://thephiladelphiacitizen.org/enough-corruption-philly/" class="featuredStory-titlebar">
<span class="subheader">Guest Commentary:</span><h1> Time to Say <i>Enough</i> to Corruption</h1> <p>
Union boss John Dougherty was indicted again this week, and 12 percent of City Council is facing corruption charges. One outraged elected official is calling for an end to the scourge of Philly politics <span class="author">By Jared Solomon</span>
</p>
</a>
</div>
<div class="storyList">
<div class="row">
<a href="https://thephiladelphiacitizen.org/elizabeth-willing-powel-bio/" class="col standard" style="background:url(https://thephiladelphiacitizen.org/wp-content/uploads/2021/02/Elizabeth-Powel-copy-791x400.jpg); background-position:center center!important">
<img style="display:none;" class="mobileTileImg" src="https://thephiladelphiacitizen.org/wp-content/uploads/2021/02/Elizabeth-Powel-copy-791x400.jpg" alt="" />
<span class="text-overlay">
<h1>Elizabeth Willing Powel | Philadelphia Women&#8217;s History Month All-Star</h1> <p>All-Star #9: Elizabeth Willing Powel</p>
</span>
</a>
<a href="https://thephiladelphiacitizen.org/things-to-do-in-philadelphia-during-coronavirus/" class="col standard" style="background:url(https://thephiladelphiacitizen.org/wp-content/uploads/2021/03/Mural-Arts-Philadelphia-Walking-Tours-2021-791x400.jpg); background-position:center center!important">
<img style="display:none;" class="mobileTileImg" src="https://thephiladelphiacitizen.org/wp-content/uploads/2021/03/Mural-Arts-Philadelphia-Walking-Tours-2021-791x400.jpg" alt="" />
<span class="text-overlay">
<h1>Things to Do in Philadelphia This Weekend</h1> <p>Explore Philly's amazing public art scene on a new Mural Arts Philadelphia spring walking tour, check out a handful of food and craft fairs and more fun things to do in Philly this weekend during Covid-19</p>
<span class="author">By Josh Middleton</span> </span>
</a>
<a href="https://thephiladelphiacitizen.org/truth-consequences-philly/" class="col standard" style="background:url(https://thephiladelphiacitizen.org/wp-content/uploads/2021/03/TC-Group-1-791x400.jpeg); background-position:center center!important">
<img style="display:none;" class="mobileTileImg" src="https://thephiladelphiacitizen.org/wp-content/uploads/2021/03/TC-Group-1-791x400.jpeg" alt="" />
<span class="text-overlay">
<h1>Business for Good: Truth &#038; Consequences</h1> <p>In an industry known for high levels of burnout, one local ad agency has a different blueprint for success: taking care—<em>great</em> care—of its employees </p>
<span class="author">By Christine Speer Lejeune</span> </span>
</a>
<a href="https://thephiladelphiacitizen.org/answer-vaccine-debacle/" class="col standard" style="background:url(https://thephiladelphiacitizen.org/wp-content/uploads/2021/03/covid-vaccine-791x400.jpg); background-position:center center!important">
<img style="display:none;" class="mobileTileImg" src="https://thephiladelphiacitizen.org/wp-content/uploads/2021/03/covid-vaccine-791x400.jpg" alt="" />
<span class="text-overlay">
<h1>The Answer To Our Vaccine Debacle</h1> <p>Locally and nationally, getting shots into arms has been a disaster. A longtime college president says the answer to preventing this in future is clear: education</p>
<span class="author">By Elaine Maimon</span> </span>
</a>
<a href="https://thephiladelphiacitizen.org/can-the-future-still-be-female/" class="col standard" style="background:url(https://thephiladelphiacitizen.org/wp-content/uploads/2021/03/Female-Business-Leaders-Philadelphia-1-791x400.jpg); background-position:center center!important">
<img style="display:none;" class="mobileTileImg" src="https://thephiladelphiacitizen.org/wp-content/uploads/2021/03/Female-Business-Leaders-Philadelphia-1-791x400.jpg" alt="" />
<span class="text-overlay">
<h1>Future-Proofing Work: Can The Future Still Be Female?</h1> <p>Covid has wreaked havoc on womens careers—but it doesnt have to stay that way. Join Future Works Alliance and The Citizen for an event next week on where to go from here</p>
<span class="author">By Anne Gemmell</span> </span>
</a>
<a href="https://thephiladelphiacitizen.org/meditation-training-philly/" class="col standard" style="background:url(https://thephiladelphiacitizen.org/wp-content/uploads/2021/03/PA012134-1-1-791x400.jpg); background-position:center center!important">
<img style="display:none;" class="mobileTileImg" src="https://thephiladelphiacitizen.org/wp-content/uploads/2021/03/PA012134-1-1-791x400.jpg" alt="" />
<span class="text-overlay">
<h1>Mindfulness for Minors</h1> <p>A local nonprofit has shown measurable progress in helping Philly public school students stay on track through training in an unexpected skill: meditation</p>
<span class="author">By Jessica Blatt Press</span> </span>
</a>
<a href="https://thephiladelphiacitizen.org/philadelphia-obituary-project/" class="col standard" style="background:url(https://thephiladelphiacitizen.org/wp-content/uploads/2021/03/Philadelphia-Obituary-Project-791x400.jpg); background-position:center center!important">
<img style="display:none;" class="mobileTileImg" src="https://thephiladelphiacitizen.org/wp-content/uploads/2021/03/Philadelphia-Obituary-Project-791x400.jpg" alt="" />
<span class="text-overlay">
<h1>Who Have They Left Behind?</h1> <p>The Philadelphia Obituary Project chronicles the devastating toll of our citys murder epidemic, one victim at a time</p>
<span class="author">By Jessica Blatt Press</span> </span>
</a>
<a href="https://thephiladelphiacitizen.org/leaving-money-on-the-table/" class="col standard" style="background:url(https://thephiladelphiacitizen.org/wp-content/uploads/2021/03/Fairmount_Neighborhood-791x400.jpeg); background-position:center center!important">
<img style="display:none;" class="mobileTileImg" src="https://thephiladelphiacitizen.org/wp-content/uploads/2021/03/Fairmount_Neighborhood-791x400.jpeg" alt="" />
<span class="text-overlay">
<h1>Leaving Money on the Table</h1> <p>Rising house prices <em>should</em> mean rising tax revenue to help close Phillys budget gap. Too bad, Philly 3.0s engagement director notes, the Citys property office is still too dysfunctional to reassess values</p>
<span class="author">By Jon Geeting</span> </span>
</a>
</div>
<div class="alm-btn-wrap"><button data-pageoffset="0" data-exclude="62666|62511|52496|62657|62656|62646|62632|62614|62623" style="margin-bottom:2rem;" id="load-more" class="alm-load-more-btn more loadMorer moreTopicsHome">Show More</button></div>
</div>
</div>
</div>
</div><!-- .site-content -->
</div><!-- .site -->
<div class="footer-fade"></div>
</body>
</html>

View File

@ -0,0 +1,78 @@
# The Philadelphia Citizen
What happened. What it means. And what you can do about it.
=> https://thephiladelphiacitizen.org/ HTML Original
=> /proxy/thephiladelphiacitizen.org/ Proxy Home Page
## Latest Articles
=> /proxy/thephiladelphiacitizen.org/enough-corruption-philly/ Time to Say Enough to Corruption
=> /proxy/thephiladelphiacitizen.org/elizabeth-willing-powel-bio/ Elizabeth Willing Powel | Philadelphia Womens History Month All-Star
=> /proxy/thephiladelphiacitizen.org/things-to-do-in-philadelphia-during-coronavirus/ Things to Do in Philadelphia This Weekend
=> /proxy/thephiladelphiacitizen.org/truth-consequences-philly/ Business for Good: Truth & Consequences
=> /proxy/thephiladelphiacitizen.org/answer-vaccine-debacle/ The Answer To Our Vaccine Debacle
=> /proxy/thephiladelphiacitizen.org/can-the-future-still-be-female/ Future-Proofing Work: Can The Future Still Be Female?
=> /proxy/thephiladelphiacitizen.org/meditation-training-philly/ Mindfulness for Minors
=> /proxy/thephiladelphiacitizen.org/philadelphia-obituary-project/ Who Have They Left Behind?
=> /proxy/thephiladelphiacitizen.org/leaving-money-on-the-table/ Leaving Money on the Table
## Site Menu
=> /proxy/thephiladelphiacitizen.org/events/ Events
=> /proxy/thephiladelphiacitizen.org/ideas-we-should-steal-festival-2020-videos/ Ideas We Should Steal Festival
=> /proxy/thephiladelphiacitizen.org/how-to-get-involved-in-your-community/ Do Something Guides
=> /proxy/thephiladelphiacitizen.org/about/ About
### Topics
=> /proxy/thephiladelphiacitizen.org/category/politics/ Politics
=> /proxy/thephiladelphiacitizen.org/category/opinion/ Opinion
=> /proxy/thephiladelphiacitizen.org/category/business-and-economy/ Business
=> /proxy/thephiladelphiacitizen.org/category/education/ Education
=> /proxy/thephiladelphiacitizen.org/category/urban-development/ Development
=> /proxy/thephiladelphiacitizen.org/category/environment/ Environment
=> /proxy/thephiladelphiacitizen.org/category/health-wellness/ Health
=> /proxy/thephiladelphiacitizen.org/category/philadelphia-citizen-topics/technology/ Tech
=> /proxy/thephiladelphiacitizen.org/category/jobs-philadelphia/ Jobs
=> /proxy/thephiladelphiacitizen.org/category/food-philadelphia/ Food
=> /proxy/thephiladelphiacitizen.org/category/philadelphia-citizen-topics/arts-and-culture/ Arts
=> /proxy/thephiladelphiacitizen.org/category/philadelphia-sports/ Sports
=> /proxy/thephiladelphiacitizen.org/category/lgbtq/ LGBTQ
=> /proxy/thephiladelphiacitizen.org/category/youth-philadelphia/ Youth
=> /proxy/thephiladelphiacitizen.org/category/philadelphia-events/ Events
=> /proxy/thephiladelphiacitizen.org//about/join-our-team/ Work at The Citizen
### Categories
=> /proxy/thephiladelphiacitizen.org/category/business-and-economy Business for Good
=> /proxy/thephiladelphiacitizen.org/citizencast-audio-articles/ CitizenCast
=> /proxy/thephiladelphiacitizen.org/tag/philadelphia-citizen-of-the-week/ Citizens of the Week
=> /proxy/thephiladelphiacitizen.org/tag/foodizen-philadelphia/ Foodizen
=> /proxy/thephiladelphiacitizen.org//tag/ideas-we-should-steal-philly Ideas We Should Steal
=> /proxy/thephiladelphiacitizen.org//category/rubrics/mystery-shopping-philadelphia-city-hall Mystery Shopper
=> /proxy/thephiladelphiacitizen.org/tag/jason-kelce-eagles-education-season/ Jason Kelces Eagles Education Season
=> /proxy/thephiladelphiacitizen.org/tag/connor-barwin-civic-season/ Connor Barwins Civic Season
=> /proxy/thephiladelphiacitizen.org/tag/malcolm-jenkins-criminal-justice-season-phl/ Malcolm Jenkins Criminal Justice Season
### Voices
=> /proxy/thephiladelphiacitizen.org//author/Connor-Barwin Connor Barwin
=> /proxy/thephiladelphiacitizen.org//author/Courtney-DuChene Courtney DuChene
=> /proxy/thephiladelphiacitizen.org//author/Charles-D--Ellison Charles D. Ellison
=> /proxy/thephiladelphiacitizen.org//author/Jon-Geeting Jon Geeting
=> /proxy/thephiladelphiacitizen.org//author/Anne-Gemmell Anne Gemmell
=> /proxy/thephiladelphiacitizen.org//author/Jill-Harkins Jill Harkins
=> /proxy/thephiladelphiacitizen.org//author/Bruce-Katz Bruce Katz
=> /proxy/thephiladelphiacitizen.org//author/Jason-Kelce Jason Kelce
=> /proxy/thephiladelphiacitizen.org//author/Diana-Lind Diana Lind
=> /proxy/thephiladelphiacitizen.org//author/James-Peterson James Peterson
=> /proxy/thephiladelphiacitizen.org//author/Larry-Platt Larry Platt
=> /proxy/thephiladelphiacitizen.org/author/jessica-press/ Jessica Blatt Press
=> /proxy/thephiladelphiacitizen.org//author/Katherine-Rapin Katherine Rapin
=> /proxy/thephiladelphiacitizen.org//author/Roxanne-Patel-Shepelavy Roxanne Patel Shepelavy
### Featured Partners
=> /proxy/thephiladelphiacitizen.org//board-of-directors/ Board of Directors
=> /proxy/thephiladelphiacitizen.org//corporations-and-foundations Corporate & Foundation Partners
=> /proxy/thephiladelphiacitizen.org//founding-donors/ Founding Donors

View File

@ -0,0 +1,647 @@
<!DOCTYPE html>
<html lang="en-US" class="no-js">
<head>
<title>Article Title</title>
</head>
<body class="post-template-default single single-post postid-62666 single-format-standard">
<div class="fancyboxes deployed">
<div id="newsletterPopup">
<div class="newsletterSpot">
<div class="popupTitle">
<h3>NEWSLETTER SIGNUP</h3>
</div>
</div>
</div>
</div>
<div id="page" class="hfeed site ">
<header id="masthead" class="site-header" role="banner">
<div class="sectionScale">
<div class="burgerWrap mobile" data-state="close">
<div class="burgerBar first"></div>
<div class="burgerBar second"></div>
<div class="burgerBar third"></div>
</div>
<a href="https://thephiladelphiacitizen.org" id="logo">
<img src="https://thephiladelphiacitizen.org/wp-content/themes/citizen/img/logo.png" class="desktopLogo" alt="The Philadephia Citizen" />
<h1>The Philadelphia Citizen</h1><p>What happened. What it means. And what you can do about it.</p>
</a>
<a class="nlSignup" href="https://thephiladelphiacitizen.org/donate">SUPPORT<br>THE CITIZEN</a>
<div class="socialIcons">
<div class="socialWrap">
<a class="fbBtn" title="Facebook" target="_blank" href="https://www.facebook.com/thephillycitizen"></a>
<a class="twitterBtn" title="Twitter" target="_blank" href="https://twitter.com/@thephilacitizen"></a>
<a class="instaBtn" title="Instagram" target="_blank" href="https://instagram.com/thephiladelphiacitizen"></a>
<a class="linkedinBtn" title="LinkedIn" target="_blank" href="https://www.linkedin.com/company/the-philadelphia-citizen/"></a>
<a class="emailBtn" title="Newsletter" href="https://thephiladelphiacitizen.org/sign-up-for-the-citizen-newsletter/"></a>
<a class="smileBtn" title="Amazon Smile" target="_blank" href="https://smile.amazon.com/ch/46-2777419"></a>
<a class="rssBtn" title="RSS" target="_blank" href="https://feeds.feedburner.com/thephiladelphiacitizen/NqdF"></a>
</div>
<div class="expandBtn"></div>
</div>
<div id="mSearch" class="mobile" data-show="closed">
<div class="searchGlass">
<div class="handle">
<div class="tail"></div>
</div>
</div>
</div>
</div>
</header>
<div id="mobileSearch" class="mobile">
<form method="get" action="https://thephiladelphiacitizen.org/">
<input type="text" id="searchInput" value="" name="s" placeholder="Search">
<input type="submit" id="searchsubmit" value="Search" class="btn" />
</form>
</div>
<div class="pageNav">
<div class="navCenter">
<div class="article-progress">
<div class="article-pg-fill"></div>
</div>
<div id="navContainer">
<div class="bolt">
<img src="https://thephiladelphiacitizen.org/wp-content/themes/citizen/img/footerBolt-small.png" alt="" />
</div>
<div class="navContainer-wrap">
<a href="#" id="menuBtnLink">
<div id="menuBtnWrap" >
<div class="burgerWrap">
<div class="burgerBar first"></div>
<div class="burgerBar second"></div>
<div class="burgerBar third"></div>
</div>
<p>Menu</p>
<div class="menuSpacer"></div>
</div>
</a>
<span>&#9679;</span>
<a href="https://thephiladelphiacitizen.org/events/" class="nothing">
<p>Events</p>
</a>
<span>&#9679;</span>
<a href="https://thephiladelphiacitizen.org/ideas-we-should-steal-festival-2020-videos/" class="nothing">
<p>Ideas We Should Steal Festival</p>
</a>
<span>&#9679;</span>
<a href="https://thephiladelphiacitizen.org/how-to-get-involved-in-your-community/" class="nothing">
<p>Do Something Guides</p>
</a>
<span>&#9679;</span>
<a href="https://thephiladelphiacitizen.org/about/" class="nothing">
<p>About</p>
</a>
<span>&#9679;</span>
<div id="searchLink" href="#">
<p>Search</p>
<form method="get" id="searchform" action="https://thephiladelphiacitizen.org/">
<input type="text" id="searchInput" value="" name="s" placeholder="Search...">
<input type="submit" id="searchsubmit" value="Search" class="btn" />
</form>
<div class="searchWrap">
<div class="searchGlass">
<div class="handle">
<div class="tail"></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div id="dropWrapper">
<div id="dropContent">
<div class="dropSizer">
<div id="topicWrap" class="menuContent">
<strong>Topics</strong>
<ul>
<li><a class="business" title="(20)" href="https://thephiladelphiacitizen.org/category/politics/">Politics</a></li>
<li><a class="business" title="(20)" href="https://thephiladelphiacitizen.org/category/opinion/">Opinion</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/business-and-economy/" target="_blank" rel="noopener noreferrer">Business</a></li>
<li><a class="schools" title="(46)" href="https://thephiladelphiacitizen.org/category/education/">Education</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/urban-development/">Development</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/environment/">Environment</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/health-wellness/">Health</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/philadelphia-citizen-topics/technology/">Tech</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/jobs-philadelphia/">Jobs</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/food-philadelphia/">Food</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/philadelphia-citizen-topics/arts-and-culture/">Arts</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/philadelphia-sports/">Sports</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/lgbtq/">LGBTQ</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/youth-philadelphia/">Youth</a></li>
<li><a class="events" title="(4)" href="https://thephiladelphiacitizen.org/category/philadelphia-events/">Events</a></li>
<li><a href="/about/join-our-team/">Work at The Citizen</a></li>
</ul> </div>
<div id="categoryWrap" class="menuContent">
<strong>Categories</strong>
<ul>
<li><a href="https://thephiladelphiacitizen.org/category/business-and-economy" target="_blank" rel="noopener noreferrer">Business for Good</a></li>
<li><a href="https://thephiladelphiacitizen.org/citizencast-audio-articles/" target="_blank" rel="noopener noreferrer">CitizenCast</a></li>
<li><a href="https://thephiladelphiacitizen.org/tag/philadelphia-citizen-of-the-week/" target="_blank" rel="noopener noreferrer">Citizens of the Week</a></li>
<li><a href="https://thephiladelphiacitizen.org/tag/foodizen-philadelphia/" target="_blank" rel="noopener noreferrer">Foodizen</a></li>
<li><a href="/tag/ideas-we-should-steal-philly" target="_blank" rel="noopener noreferrer">Ideas We Should Steal</a></li>
<li><a href="/category/rubrics/mystery-shopping-philadelphia-city-hall">Mystery Shopper</a></li>
<li><a href="https://thephiladelphiacitizen.org/tag/jason-kelce-eagles-education-season/" target="_blank" rel="noopener noreferrer">Jason Kelces Eagles Education Season</a></li>
<li><a href="https://thephiladelphiacitizen.org/tag/connor-barwin-civic-season/" target="_blank" rel="noopener noreferrer">Connor Barwins Civic Season</a></li>
<li><a href="https://thephiladelphiacitizen.org/tag/malcolm-jenkins-criminal-justice-season-phl/" target="_blank" rel="noopener noreferrer">Malcolm Jenkins Criminal Justice Season</a></li>
</ul> </div>
<div id="voiceWrap" class="menuContent">
<strong>Voices</strong>
<ul>
<li>Connor Barwin</li>
<li>Courtney DuChene</li>
<li>Charles D. Ellison</li>
<li>Jon Geeting</li>
<li>Anne Gemmell</li>
<li>Jill Harkins</li>
<li>Bruce Katz</li>
<li>Jason Kelce</li>
<li>Diana Lind</li>
<li>James Peterson</li>
<li>Larry Platt</li>
<li><a href="https://thephiladelphiacitizen.org/author/jessica-press/">Jessica Blatt Press</a></li>
<li>Katherine Rapin</li>
<li>Roxanne Patel Shepelavy</li>
</ul> </div>
<div id="sponsorWrap" class="menuContent">
<div class="listCol">
<strong>Featured Partners</strong>
<ul>
<li><a href="/board-of-directors/">Board of Directors</a></li>
<li><a href="/corporations-and-foundations">Corporate &amp; Foundation Partners</a></li>
<li><a href="/founding-donors/">Founding Donors</a></li>
</ul> </div>
</div>
</div>
</div>
</div>
</div>
<!-- site-header -->
<div class="nav-bar mobileNav">
<ul>
<li><a href="/" >Stories</a></li>
<li><a href="https://thephiladelphiacitizen.org/events/" >Events</a></li>
<li><a href="https://thephiladelphiacitizen.org/ideas-we-should-steal-festival-2020-videos/" >Ideas We Should Steal Festival</a></li>
<li><a href="https://thephiladelphiacitizen.org/how-to-get-involved-in-your-community/" >Do Something Guides</a></li>
<li class="parent"><a href="https://thephiladelphiacitizen.org/topic-list">Topics</a>
<div class="submenu">
<ul>
<li><a class="business" title="(20)" href="https://thephiladelphiacitizen.org/category/politics/">Politics</a></li>
<li><a class="business" title="(20)" href="https://thephiladelphiacitizen.org/category/opinion/">Opinion</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/business-and-economy/" target="_blank" rel="noopener noreferrer">Business</a></li>
<li><a class="schools" title="(46)" href="https://thephiladelphiacitizen.org/category/education/">Education</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/urban-development/">Development</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/environment/">Environment</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/health-wellness/">Health</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/philadelphia-citizen-topics/technology/">Tech</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/jobs-philadelphia/">Jobs</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/food-philadelphia/">Food</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/philadelphia-citizen-topics/arts-and-culture/">Arts</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/philadelphia-sports/">Sports</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/lgbtq/">LGBTQ</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/youth-philadelphia/">Youth</a></li>
<li><a class="events" title="(4)" href="https://thephiladelphiacitizen.org/category/philadelphia-events/">Events</a></li>
<li><a href="/about/join-our-team/">Work at The Citizen</a></li>
</ul> </div>
</li>
<li><a href="https://podcasts.apple.com/us/podcast/citizencast/id1348163928#episodeGuid=20023371-2c58-4e1a-83ed-7ef1946f834c" >CitizenCast</a></li>
<li><a href="https://thephiladelphiacitizen.org/about/" >About</a></li>
<li><a href="https://thephiladelphiacitizen.org/donate/" >Support Us</a></li>
<li><a href="https://thephiladelphiacitizen.org/contact/" >Contact</a></li>
<li class="parent"><a>Social</a>
<div class="submenu">
<ul>
<li><a title="Facebook" target="_blank" href="https://www.facebook.com/thephillycitizen">Facebook</a>
<li><a title="Twitter" target="_blank" href="https://twitter.com/@thephilacitizen">Twitter</a>
<li><a title="Instagram" target="_blank" href="https://instagram.com/thephiladelphiacitizen">Instagram</a>
<li><a title="LinkedIn" target="_blank" href="https://www.linkedin.com/company/the-philadelphia-citizen/">LinkedIn</a>
<li><a title="Newsletter" href="https://thephiladelphiacitizen.org/sign-up-for-the-citizen-newsletter/">Newsletter</a>
<li><a title="Amazon Smile" target="_blank" href="https://smile.amazon.com/ch/46-2777419">Amazon Smile</a>
<li><a title="RSS" target="_blank" href="https://feeds.feedburner.com/thephiladelphiacitizen/NqdF">RSS</a>
</ul>
</div>
</li>
</ul>
</div>
<div class="article-progress"></div>
<div id="content" class="site-content">
<div class="overlay"></div>
<!-- #assets -->
<div id="assets">
<div id="doSomething" data-content-type="richText">
<header>
<h2>Do Something</h2>
</header>
<div class="doSomethingText">
<div class="blurb">
<h3>VOTE!</h3>
</div>
<p><p>Yes, we have another election coming up! The PA Primary is <strong>May 18, 2021</strong>. Join local organizations like <strong><a href="https://powerinterfaith.org/voter-engagement/" target="_blank" rel="noopener noreferrer">POWER</a></strong> and <a href="https://twitter.com/PHLYouthVOTE" target="_blank" rel="noopener noreferrer"><strong>Philly Youth VOTE</strong></a> to help get folks registered by the deadline: May 3.</p>
<p>Go <strong><a href="https://thephiladelphiacitizen.org/help-voting-philadelphia-2020/" target="_blank" rel="noopener">here</a></strong> for more ideas about how to get out the vote. And stayed tuned for our voter guide to make sure you&#8217;re well-informed.</p>
</p>
<div class="divider">
<img src="https://thephiladelphiacitizen.org/wp-content/themes/citizen/img/star.png" alt="">
<img src="https://thephiladelphiacitizen.org/wp-content/themes/citizen/img/star.png" alt="">
<img src="https://thephiladelphiacitizen.org/wp-content/themes/citizen/img/star.png" alt="">
<img src="https://thephiladelphiacitizen.org/wp-content/themes/citizen/img/star.png" alt="">
</div>
<h6><a href="/cdn-cgi/l/email-protection#691a060a000805080a1d000607291d010c19010005080d0c05190100080a001d00130c0747061b0e"><strong>Connect&nbsp;WITH OUR SOCIAL ACTION TEAM</strong></a></h6>
<br />
<hr /><br />
</div>
</div>
<div id="readMore" data-content-type="richText">
<header>
<h2>Read More</h2>
</header>
<div class="dataText">
<h3>On Philly corruption</h3>
<div class="divider">
<img src="https://thephiladelphiacitizen.org/wp-content/themes/citizen/img/star.png" alt="">
<img src="https://thephiladelphiacitizen.org/wp-content/themes/citizen/img/star.png" alt="">
<img src="https://thephiladelphiacitizen.org/wp-content/themes/citizen/img/star.png" alt="">
<img src="https://thephiladelphiacitizen.org/wp-content/themes/citizen/img/star.png" alt="">
</div>
<div class="inline_link_container norel">
<a href="/?p=55929">
<ul class="post-list with-image"><li class="listed-post"><img width="150" height="76" src="https://thephiladelphiacitizen.org/wp-content/uploads/2020/05/ballot-question-philadelphia-city-hall.jpg" class="pcs-featured-image wp-post-image" alt="An image of City Hall in Philadelphia, through a yellow glass tunnel leading to suburban station." loading="lazy" srcset="https://thephiladelphiacitizen.org/wp-content/uploads/2020/05/ballot-question-philadelphia-city-hall.jpg 1186w, https://thephiladelphiacitizen.org/wp-content/uploads/2020/05/ballot-question-philadelphia-city-hall-300x152.jpg 300w, https://thephiladelphiacitizen.org/wp-content/uploads/2020/05/ballot-question-philadelphia-city-hall-768x389.jpg 768w, https://thephiladelphiacitizen.org/wp-content/uploads/2020/05/ballot-question-philadelphia-city-hall-1024x518.jpg 1024w, https://thephiladelphiacitizen.org/wp-content/uploads/2020/05/ballot-question-philadelphia-city-hall-791x400.jpg 791w" sizes="(max-width: 150px) 100vw, 150px" /></li></ul>
<div class="inline_link_text_container">
<div class="inline_link_title">The Fix: Is Now The Time to Go <i>Softer</i> On Public Corruption?</div>
<div class="inline_link_blurb">A ballot question amends the charters ban on political activity. Is there evidence that, left to their own devices, our political players will make good government choices?</div>
</div>
</a>
</div>
<p><span style="font-weight: 400;"><div class="inline_link_container norel">
<a href="/?p=41152">
<ul class="post-list with-image"><li class="listed-post"><img width="150" height="76" src="https://thephiladelphiacitizen.org/wp-content/uploads/2019/03/Screen-Shot-2019-03-25-at-3.42.12-PM.png" class="pcs-featured-image wp-post-image" alt="" loading="lazy" srcset="https://thephiladelphiacitizen.org/wp-content/uploads/2019/03/Screen-Shot-2019-03-25-at-3.42.12-PM.png 1186w, https://thephiladelphiacitizen.org/wp-content/uploads/2019/03/Screen-Shot-2019-03-25-at-3.42.12-PM-300x152.png 300w, https://thephiladelphiacitizen.org/wp-content/uploads/2019/03/Screen-Shot-2019-03-25-at-3.42.12-PM-768x389.png 768w, https://thephiladelphiacitizen.org/wp-content/uploads/2019/03/Screen-Shot-2019-03-25-at-3.42.12-PM-1024x518.png 1024w, https://thephiladelphiacitizen.org/wp-content/uploads/2019/03/Screen-Shot-2019-03-25-at-3.42.12-PM-791x400.png 791w" sizes="(max-width: 150px) 100vw, 150px" /></li></ul>
<div class="inline_link_text_container">
<div class="inline_link_title">The Last Outraged Philadelphian</div>
<div class="inline_link_blurb">Today State Rep. Jared Solomon is announcing a bill to give voters recall power. Why is he seemingly the only person worked up about Phillys culture of corruption?</div>
</div>
</a>
</div></span></p>
<p><span style="font-weight: 400;"><div class="inline_link_container norel">
<a href="/?p=40694">
<ul class="post-list with-image"><li class="listed-post"><img width="150" height="76" src="https://thephiladelphiacitizen.org/wp-content/uploads/2019/03/Citizen_Wall_2.jpg" class="pcs-featured-image wp-post-image" alt="" loading="lazy" srcset="https://thephiladelphiacitizen.org/wp-content/uploads/2019/03/Citizen_Wall_2.jpg 1186w, https://thephiladelphiacitizen.org/wp-content/uploads/2019/03/Citizen_Wall_2-300x152.jpg 300w, https://thephiladelphiacitizen.org/wp-content/uploads/2019/03/Citizen_Wall_2-768x389.jpg 768w, https://thephiladelphiacitizen.org/wp-content/uploads/2019/03/Citizen_Wall_2-1024x518.jpg 1024w, https://thephiladelphiacitizen.org/wp-content/uploads/2019/03/Citizen_Wall_2-791x400.jpg 791w" sizes="(max-width: 150px) 100vw, 150px" /></li></ul>
<div class="inline_link_text_container">
<div class="inline_link_title">What Change Feels Like</div>
<div class="inline_link_blurb">Three months out from mayoral and council elections, is Phillys political establishment heading for a reckoning?</div>
</div>
</a>
</div></span></p>
<p><span style="font-weight: 400;"><div class="inline_link_container norel">
<a href="/?p=34596">
<ul class="post-list with-image"><li class="listed-post"><img width="150" height="77" src="https://thephiladelphiacitizen.org/wp-content/uploads/2018/07/CityHallFix.jpg" class="pcs-featured-image wp-post-image" alt="" loading="lazy" srcset="https://thephiladelphiacitizen.org/wp-content/uploads/2018/07/CityHallFix.jpg 1180w, https://thephiladelphiacitizen.org/wp-content/uploads/2018/07/CityHallFix-300x154.jpg 300w, https://thephiladelphiacitizen.org/wp-content/uploads/2018/07/CityHallFix-768x395.jpg 768w, https://thephiladelphiacitizen.org/wp-content/uploads/2018/07/CityHallFix-1024x527.jpg 1024w, https://thephiladelphiacitizen.org/wp-content/uploads/2018/07/CityHallFix-791x400.jpg 791w" sizes="(max-width: 150px) 100vw, 150px" /></li></ul>
<div class="inline_link_text_container">
<div class="inline_link_title">The Fix</div>
<div class="inline_link_blurb">Introducing a new series, in which we delve into the citys transactional culture of influence—and look at strategies for promoting public integrity</div>
</div>
</a>
</div></span></p>
<p><span style="font-weight: 400;"><div class="inline_link_container norel">
<a href="/?p=33418">
<ul class="post-list with-image"><li class="listed-post"><img width="150" height="76" src="https://thephiladelphiacitizen.org/wp-content/uploads/2018/05/moneydownthedrain.jpg" class="pcs-featured-image wp-post-image" alt="" loading="lazy" srcset="https://thephiladelphiacitizen.org/wp-content/uploads/2018/05/moneydownthedrain.jpg 1185w, https://thephiladelphiacitizen.org/wp-content/uploads/2018/05/moneydownthedrain-300x152.jpg 300w, https://thephiladelphiacitizen.org/wp-content/uploads/2018/05/moneydownthedrain-768x389.jpg 768w, https://thephiladelphiacitizen.org/wp-content/uploads/2018/05/moneydownthedrain-1024x518.jpg 1024w, https://thephiladelphiacitizen.org/wp-content/uploads/2018/05/moneydownthedrain-791x400.jpg 791w" sizes="(max-width: 150px) 100vw, 150px" /></li></ul>
<div class="inline_link_text_container">
<div class="inline_link_title">What Did They Know? When Did They Know It?</div>
<div class="inline_link_blurb">The citys missing millions is turning into a full-blown scandal. The finance director and treasurer need to do the right thing</div>
</div>
</a>
</div></span></p>
<p><span style="font-weight: 400;"><div class="inline_link_container norel">
<a href="/?p=33120">
<ul class="post-list with-image"><li class="listed-post"><img width="150" height="77" src="https://thephiladelphiacitizen.org/wp-content/uploads/2018/05/lostmoney.jpg" class="pcs-featured-image wp-post-image" alt="" loading="lazy" srcset="https://thephiladelphiacitizen.org/wp-content/uploads/2018/05/lostmoney.jpg 1170w, https://thephiladelphiacitizen.org/wp-content/uploads/2018/05/lostmoney-300x154.jpg 300w, https://thephiladelphiacitizen.org/wp-content/uploads/2018/05/lostmoney-768x395.jpg 768w, https://thephiladelphiacitizen.org/wp-content/uploads/2018/05/lostmoney-1024x526.jpg 1024w, https://thephiladelphiacitizen.org/wp-content/uploads/2018/05/lostmoney-791x400.jpg 791w" sizes="(max-width: 150px) 100vw, 150px" /></li></ul>
<div class="inline_link_text_container">
<div class="inline_link_title">The Case of the Missing Millions</div>
<div class="inline_link_blurb">The City misplaced $27 million of your money, didnt reconcile its bank accounts for 7 years, and now wants to raise taxes again. Where does the buck stop?</div>
</div>
</a>
</div></span></p>
<p><span style="font-weight: 400;"><div class="inline_link_container norel">
<a href="/?p=39054">
<ul class="post-list with-image"><li class="listed-post"><img width="150" height="76" src="https://thephiladelphiacitizen.org/wp-content/uploads/2018/12/MG_9426-864x576.jpg" class="pcs-featured-image wp-post-image" alt="" loading="lazy" srcset="https://thephiladelphiacitizen.org/wp-content/uploads/2018/12/MG_9426-864x576.jpg 1184w, https://thephiladelphiacitizen.org/wp-content/uploads/2018/12/MG_9426-864x576-300x152.jpg 300w, https://thephiladelphiacitizen.org/wp-content/uploads/2018/12/MG_9426-864x576-768x390.jpg 768w, https://thephiladelphiacitizen.org/wp-content/uploads/2018/12/MG_9426-864x576-1024x520.jpg 1024w, https://thephiladelphiacitizen.org/wp-content/uploads/2018/12/MG_9426-864x576-791x400.jpg 791w" sizes="(max-width: 150px) 100vw, 150px" /></li></ul>
<div class="inline_link_text_container">
<div class="inline_link_title">The Fix: The Real Problem with Corrupt Land Sales? City Council</div>
<div class="inline_link_blurb">As Philly 3.0's engagement director notes, reform is hampered by Council's refusal to grapple with its own worst impulses</div>
</div>
</a>
</div></span></p>
<p><span style="font-weight: 400;"><div class="inline_link_container norel">
<a href="/?p=35317">
<ul class="post-list with-image"><li class="listed-post"><img width="150" height="76" src="https://thephiladelphiacitizen.org/wp-content/uploads/2018/07/vadercityhall.jpg" class="pcs-featured-image wp-post-image" alt="" loading="lazy" srcset="https://thephiladelphiacitizen.org/wp-content/uploads/2018/07/vadercityhall.jpg 1186w, https://thephiladelphiacitizen.org/wp-content/uploads/2018/07/vadercityhall-300x151.jpg 300w, https://thephiladelphiacitizen.org/wp-content/uploads/2018/07/vadercityhall-768x387.jpg 768w, https://thephiladelphiacitizen.org/wp-content/uploads/2018/07/vadercityhall-1024x516.jpg 1024w, https://thephiladelphiacitizen.org/wp-content/uploads/2018/07/vadercityhall-791x400.jpg 791w" sizes="(max-width: 150px) 100vw, 150px" /></li></ul>
<div class="inline_link_text_container">
<div class="inline_link_title">The Fix: When The Empire Strikes Back</div>
<div class="inline_link_blurb">An attack on Controller Rebecca Rhynhart by the Mayors allies is straight from a familiar Philly playbook</div>
</div>
</a>
</div></span></p>
</div>
</div>
<div id="customHalo" data-content-type="richText">
<header>
<h2>For more ideas for change</h2>
</header>
<div class="doSomethingText" style="width:calc(100% - 6em);">
<div class="blurb">
<h3>Sign up for our newsletter</h3>
</div>
<div class="divider">
<img src="https://thephiladelphiacitizen.org/wp-content/themes/citizen/img/star.png" alt="">
<img src="https://thephiladelphiacitizen.org/wp-content/themes/citizen/img/star.png" alt="">
<img src="https://thephiladelphiacitizen.org/wp-content/themes/citizen/img/star.png" alt="">
<img src="https://thephiladelphiacitizen.org/wp-content/themes/citizen/img/star.png" alt="">
</div>
<p>For a weekly dose of ideas, solutions and practical action steps, sign up for our newsletter:</p>
<div id="mc_embed_signup">
<form id="mc-embedded-subscribe-form" class="validate" action="https://thephiladelphiacitizen.us4.list-manage.com/subscribe/post?u=3089138f987fae38d9964b335&amp;id=165ebaa6be" method="post" name="mc-embedded-subscribe-form" novalidate="" target="_blank">
<div id="mc_embed_signup_scroll">
<div class="indicates-required" style="text-align: center;"><span style="font-size: 10pt;"><span class="asterisk">*</span> indicates required</span></div>
<div class="mc-field-group" style="text-align: center;"><label for="mce-EMAIL">Email Address <span class="asterisk">*</span></label><br />
<input id="mce-EMAIL" class="required email" name="EMAIL" type="email" value="" /></div>
<div class="mc-field-group" style="text-align: center;"><label for="mce-FNAME">First Name </label><br />
<input id="mce-FNAME" class="" name="FNAME" type="text" value="" /></div>
<div class="mc-field-group" style="text-align: center;"><label for="mce-LNAME">Last Name </label><br />
<input id="mce-LNAME" class="" name="LNAME" type="text" value="" /></div>
<div class="mc-field-group size1of2">
<p style="text-align: center;"><label for="mce-BIRTHDAY-month">Birthday </label></p>
<div class="datefield" style="text-align: center;"><span class="subfield monthfield"><input id="mce-BIRTHDAY-month" class="birthday " maxlength="2" name="BIRTHDAY[month]" pattern="[0-9]*" size="2" type="text" value="" placeholder="MM" /></span> /<br />
<span class="subfield dayfield"><input id="mce-BIRTHDAY-day" class="birthday " maxlength="2" name="BIRTHDAY[day]" pattern="[0-9]*" size="2" type="text" value="" placeholder="DD" /></span><br />
<span class="small-meta nowrap">( mm / dd )</span></div>
</div>
<div id="mce-responses" class="clear">
<div id="mce-error-response" class="response" style="display: none;"></div>
<div id="mce-success-response" class="response" style="display: none;"></div>
</div>
<p><!-- real people should not fill this in and expect good things - do not remove this or risk form bot signups--></p>
<div style="position: absolute; left: -5000px;" aria-hidden="true"><input tabindex="-1" name="b_3089138f987fae38d9964b335_165ebaa6be" type="text" value="" /></div>
<div class="clear"><input id="mc-embedded-subscribe" class="button" name="subscribe" type="submit" value="Subscribe" /></div>
</div>
</form>
</div>
<p></p>
<p>And follow us on <strong><a href="https://www.facebook.com/thephillycitizen" target="_blank" rel="noopener">Facebook</a></strong>, <strong><a href="https://twitter.com/thephilacitizen" target="_blank" rel="noopener">Twitter</a></strong> &amp; <strong><a href="https://www.instagram.com/thephiladelphiacitizen/" target="_blank" rel="noopener">Instagram</a></strong>.</p>
</div>
</div>
</div>
<!-- End #assets -->
<div id="primary" class="content-area normal-width dropCap">
<div class="jumbotron supporting-template">
<div class="image" style="background:url(https://thephiladelphiacitizen.org/wp-content/uploads/2021/03/John-Dougherty-Philadelphia-1.jpeg) #ec008c;">
<img src="https://thephiladelphiacitizen.org/wp-content/uploads/2021/03/John-Dougherty-Philadelphia-1.jpeg" class="mobileHero" alt="" />
<div class="callout">
<div class="textWrap">
<h1>
<span>Guest Commentary:</span> Time to Say <i>Enough</i> to Corruption </h1>
<div class=""><h2>Union boss John Dougherty was indicted again this week, and 12 percent of City Council is facing corruption charges. One outraged elected official is calling for an end to the scourge of Philly politics</h2></div>
</div>
</div>
</div>
<div class="actions supportingMaterials-actions">
<div class="actions-inner">
<ul>
<li >
<a data-cat="doSomething" href="#doSomething" class="fancybox">
<h4>Do Something</h4>
<p>VOTE!</p>
</a>
</li>
<li >
<a data-cat="readMore" href="#readMore" class="fancybox">
<h4>Read More</h4>
<p>On Philly corruption</p>
</a>
</li>
<li >
<a data-cat="customHalo" href="#customHalo" class="fancybox">
<h4>For more ideas for change</h4>
<p>Sign up for our newsletter</p>
</a>
</li>
</ul>
</div>
</div>
</div><!-- /jumbotron -->
<div class="article-headline-wrap">
<div class="article-headline">
<h1>
<span>Guest Commentary:</span> Time to Say <i>Enough</i> to Corruption </h1>
<div class=""><h2>Union boss John Dougherty was indicted again this week, and 12 percent of City Council is facing corruption charges. One outraged elected official is calling for an end to the scourge of Philly politics</h2></div>
</div>
</div>
<div id="contentArea">
<style>
.page-template-noTweets .postDate{
display: none!important;
}
.postAuthor:empty{
display: none;
}
.postAuthor:empty + .postDate{
margin-left: 0!important;
}
</style>
<section class="postInfo">
<div class="postAuthor"><p>BY <a href="https://thephiladelphiacitizen.org/author/author-mcauthor/">Author McAuthor</a></p></div>
<div class="postDate">
<p>
Mar. 11, 2021 </p>
</div>
<div class="postMeta">
<style>
.postMeta a.fa-icon{
display: inline-block;
vertical-align: top;
margin: 0 2px;
float: none;
transition: opacity 0.2s ease-out;
}
.postMeta a.fa-icon:hover{
opacity: 0.75;
}
.postMeta a.fa-icon img{
height: 25px;
width: auto;
display: block;
position: relative;
}
.postMeta a.fa-icon.mobile{
display: none;
}
@media (max-width: 900px){
.postMeta a.fa-icon.mobile{
display: inline-block!important;
float: left;
margin-top: -2px;
}
}
</style>
<a class="fa-icon" href="#comments" title="Comment on this story"><div class="comment-icon"><img style="margin-bottom: -1px;" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAMAAAAM7l6QAAAASFBMVEUAAADsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIxh/kwFAAAAF3RSTlMAAQsPEBQXGyEoKzhiZG1xlLTt9ff5/eyUk5gAAABOSURBVChT7dM3EoBADENRkZdglmjd/6Y0VMxYFeX+9rUSoFvPO+raKzhFDZSyLVz4Pz4U1xgWM9tI0rN9mt+xJ5I+hV9IUtFLBcZOadgDbMc+qnrTf+gAAAAASUVORK5CYII=" /></div></a>
<a class="fa-icon" title="Email this story" href="/cdn-cgi/l/email-protection#6d521e180f07080e19502a18081e194d2e0200000803190c1f14574d390400084d19024d3e0c144d280302180a054d19024d2e021f1f181d190402034b0f020914503f080c094d1905084d0b1801014d1e19021f144d05081f08574d0519191d1e5742421905081d0504010c0908011d05040c0e04190417080343021f0a42080302180a05400e021f1f181d19040203401d050401011442"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAMAAAAM7l6QAAAAmVBMVEUAAADsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzJ17BbAAAAMnRSTlMAAgMEBQgJEBESExUWFxkaIScoLS48PUpMZmdpcXN0dZeYnZ6wtbe+w8XMztzi5Obv90ZvGPwAAAC5SURBVCjPzdNHDsJAEAXRmmHIOQeTczT43/9wbLCMjc0OiVr2W7XUDb/NNFqpNQxA2VdGfhm4KLMzWOlwS7PbQbI4yTOzT50aT3I4yYPqKY7HKoS8dcAoiDAYAW77Yj36QGET6roADB4KWdoVgZ4vSX4XKO2lN5bGBuxCmlswk9cwYl3bQL0GdK76ZGmZB8ivokmMFQxh+LZBgqVTfP8kJ/przn1j+/WYLkDlnqX3CoBpph9y0/z4g55feW2ngOrYiQAAAABJRU5ErkJggg==" /></a>
<a class="fa-icon print" href="#" onclick="print();" title="Print this story"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAAZCAMAAADzN3VRAAAAh1BMVEUAAADsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIw/LF1OAAAALHRSTlMAAQIEDA0SFRsgJi0zODs+P0BXWXmJlJ6jsLS8vszR2drc4OLk8fP19/n7/Sh1fFcAAACISURBVCiRpdDJDoJQDEDR4jwrziM8QPAh9/+/z4WBvEhhgXfV5CyaVqS1raUsOwxdyYukzPKaOIKpxj3k0ybhPdZkB3DWxFv4fpprIiKS0F3ml7gm8XUpMgNqAmzkiNJoUDzkpkm/Z5G7JlFIg8A/Enluz6+cQL3HdP5o9rM8rWQdGLdgJa19AGbELzaGAAw0AAAAAElFTkSuQmCC" alt="Print" /></a>
<div class="postSocial" id="postSocial1">
<a class="fa-icon mobile" style="margin-top: 0;" href="#comments" title="Comment on this story"><div class="comment-icon"><img style="margin-bottom: -1px;" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAMAAAAM7l6QAAAASFBMVEUAAADsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIxh/kwFAAAAF3RSTlMAAQsPEBQXGyEoKzhiZG1xlLTt9ff5/eyUk5gAAABOSURBVChT7dM3EoBADENRkZdglmjd/6Y0VMxYFeX+9rUSoFvPO+raKzhFDZSyLVz4Pz4U1xgWM9tI0rN9mt+xJ5I+hV9IUtFLBcZOadgDbMc+qnrTf+gAAAAASUVORK5CYII=" /></div></a>
<a class="fa-icon mobile" title="Email this story" href="/cdn-cgi/l/email-protection#310e4244535b5452450c764454424511725e5c5c545f455043480b1165585c5411455e11625048110d580f745f5e4456590d1e580f11455e11725e4343444145585e5f17535e55480c63545055114559541157445d5d1142455e434811595443540b1159454541420b1e1e4559544159585d5055545d41595850525845584b545f1f5e43561e545f5e4456591c525e4343444145585e5f1c4159585d5d481e"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAMAAAAM7l6QAAAAmVBMVEUAAADsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzsAIzJ17BbAAAAMnRSTlMAAgMEBQgJEBESExUWFxkaIScoLS48PUpMZmdpcXN0dZeYnZ6wtbe+w8XMztzi5Obv90ZvGPwAAAC5SURBVCjPzdNHDsJAEAXRmmHIOQeTczT43/9wbLCMjc0OiVr2W7XUDb/NNFqpNQxA2VdGfhm4KLMzWOlwS7PbQbI4yTOzT50aT3I4yYPqKY7HKoS8dcAoiDAYAW77Yj36QGET6roADB4KWdoVgZ4vSX4XKO2lN5bGBuxCmlswk9cwYl3bQL0GdK76ZGmZB8ivokmMFQxh+LZBgqVTfP8kJ/przn1j+/WYLkDlnqX3CoBpph9y0/z4g55feW2ngOrYiQAAAABJRU5ErkJggg==" /></a>
<div class="socialBtn twitterBtn">
<a href="https://twitter.com/share" class="twitter-share-button" data-via="thephilacitizen"></a>
</div>
<div class="socialBtn facebook">
<div class="fb-share-button" data-href="http://thephiladelphiacitizen.org/enough-corruption-philly/" data-layout="button" data-action="share"></div>
</div>
</div>
</div>
</section>
<section class="mainText">
<article>
<p>Paragraph with a <a href="/tag/some-tag">Tag Link</a> and that's it.</p>
<p>Another paragraph.</p>
<p>This paragraph has a <a href="https://thephiladelphiacitizen.org/article/">link to an article</a>.</p>
<p><img class="alignright" src="../customIcons/doSomething.png" alt="Do Something" />More text.</p>
<blockquote><p>These blockquotes are just repeats of what's already in the text, so we should ignore them.</p></blockquote>
<hr />
<p><span style="font-size: 10pt;"><i>A little blurb about the author.</i></span></p>
<div class="social_footer included">
<p>&nbsp;</p>
<hr>
<p class="social_footer_intro"><strong>Like what youre reading? Stay updated on all our coverage. Heres how:</strong></p>
<div id="follow-sprites">
<div class="sprites-row">
<div class="follow-sprite-item">
<a style="background-position: -64px 0!important;" href="/sign-up-for-the-citizen-newsletter/" target="_blank"></a><br> Newsletter
</div>
<div class="follow-sprite-item">
<a style="background-position: -32px 0!important;" href="https://twitter.com/@thephilacitizen" target="_blank"></a><br>Twitter
</div>
<div class="follow-sprite-item">
<a href="https://www.facebook.com/thephillycitizen" target="_blank"></a><br>Facebook
</div>
<div class="follow-sprite-item">
<a style="background-position: -191px 0!important;" href="https://instagram.com/thephiladelphiacitizen" target="_blank"></a><br>Instagram
</div>
<div class="follow-sprite-item linkedinBtn-postfooter">
<a href="https://www.linkedin.com/company/the-philadelphia-citizen" target="_blank"></a><br>LinkedIn
</div>
<div class="follow-sprite-item">
<a style="background-position: -96px 0!important;" href="https://feeds.feedburner.com/thephiladelphiacitizen/NqdF" target="_blank"></a><br>RSS
</div>
</div>
</div>
<div class="popupNL" style="clear: both; width: 100%; text-align: center;">
<div class="newsletterSpot" style="display: table; border: 0; width: 95%; max-width: 580px; margin: 1em auto; float: none; text-align: center;">
<div class="newsletterSpot2">
<a href="https://thephiladelphiacitizen.org/sign-up-for-the-citizen-newsletter/" style="background:rgb(230, 9, 144);padding:10px 20px;text-align:center;text-decoration:none;font-size:12pt;color:rgb(255, 255, 255);display:inline-block;">SIGN UP!</a>
<div class="formLegal">
<span>By signing up to our newsletter, you agree to our <a href="#terms" class="fancybox" target="_blank">terms</a>.</span>
</div>
</div>
</div>
</div>
</div>
</article>
</section>
<section id="comments">
<div class="postSocial" id="postSocial2">
<div class="socialBtn facebook">
<div class="fb-like" data-href="http://thephiladelphiacitizen.org/enough-corruption-philly/" data-layout="button_count" data-action="recommend" data-show-faces="false" data-share="false"></div>
</div>
<div class="socialBtn twitterBtn">
<a href="https://twitter.com/share" class="twitter-share-button" data-via="thephilacitizen"></a>
</div>
<div class="socialBtn googlePlus">
<div class="g-plusone" data-size="tall" data-annotation="none"></div>
</div>
</div>
<div class="commentDisclaimer">
<p>The Philadelphia Citizen will only publish thoughtful, civil comments. If your post is offensive, not only will we not publish it, we'll laugh at you while hitting delete.</p>
</div>
<div id="disqus_thread"></div>
</section>
<div class="divider">
<img src="https://thephiladelphiacitizen.org/wp-content/themes/citizen/img/star.png" alt="">
<img src="https://thephiladelphiacitizen.org/wp-content/themes/citizen/img/star.png" alt="">
<img src="https://thephiladelphiacitizen.org/wp-content/themes/citizen/img/star.png" alt="">
<img src="https://thephiladelphiacitizen.org/wp-content/themes/citizen/img/star.png" alt="">
</div>
</div>
<div id="siderail">
<section class="beEditor">
<div class="edLabel">
<p class="label">Be a Citizen Editor</p>
<a href="/cdn-cgi/l/email-protection#e184858895a19589849189888d8085848d91898880828895889b848fcf8e9386">Suggest a Story</a>
</div>
</section>
</div>
<div class="articleStrip">
<div class="relatedLabel">
<h4>Related Stories</h4>
</div>
<div class="articleWrap">
<ul>
<li>
<a class="thumbnail" href="https://thephiladelphiacitizen.org/ideas-please/" title="Ideas, Please!" style="background:url(https://thephiladelphiacitizen.org/wp-content/uploads/2021/03/Jim-Kenney-Philadelphia-1.jpeg);"></a>
<div class="relatedBlurb">
<a class="relHeadline" href="https://thephiladelphiacitizen.org/ideas-please/" title="Ideas, Please!">
Ideas, Please! </a>
<p class="railAuthor">By <a href="https://thephiladelphiacitizen.org/author/larry-platt/">Larry Platt</a></p>
</div>
</li>
<li>
<a class="thumbnail" href="https://thephiladelphiacitizen.org/answer-vaccine-debacle/" title="The Answer To Our Vaccine Debacle" style="background:url(https://thephiladelphiacitizen.org/wp-content/uploads/2021/03/covid-vaccine.jpg);"></a>
<div class="relatedBlurb">
<a class="relHeadline" href="https://thephiladelphiacitizen.org/answer-vaccine-debacle/" title="The Answer To Our Vaccine Debacle">
The Answer To Our Vaccine Debacle </a>
<p class="railAuthor">By <a href="https://thephiladelphiacitizen.org/author/elaine-maimon/">Elaine Maimon</a></p>
</div>
</li>
<li>
<a class="thumbnail" href="https://thephiladelphiacitizen.org/leaving-money-on-the-table/" title="Leaving Money on the Table" style="background:url(https://thephiladelphiacitizen.org/wp-content/uploads/2021/03/Fairmount_Neighborhood.jpeg);"></a>
<div class="relatedBlurb">
<a class="relHeadline" href="https://thephiladelphiacitizen.org/leaving-money-on-the-table/" title="Leaving Money on the Table">
Leaving Money on the Table </a>
<p class="railAuthor">By <a href="https://thephiladelphiacitizen.org/author/jon-geeting/">Jon Geeting</a></p>
</div>
</li>
<li>
<a class="thumbnail" href="https://thephiladelphiacitizen.org/we-only-have-one-mayor/" title="“We Only Have One Mayor”" style="background:url(https://thephiladelphiacitizen.org/wp-content/uploads/2021/03/Ed-Rendell-and-Dwight-Evans.jpg);"></a>
<div class="relatedBlurb">
<a class="relHeadline" href="https://thephiladelphiacitizen.org/we-only-have-one-mayor/" title="“We Only Have One Mayor”">
“We Only Have One Mayor” </a>
<p class="railAuthor">By <a href="https://thephiladelphiacitizen.org/author/larry-platt/">Larry Platt</a></p>
</div>
</li>
</ul>
</div>
</div>
</div><!-- .content-area -->
</div><!-- .site-content -->
</div><!-- .site -->
</body>
</html>

View File

@ -0,0 +1,78 @@
=> https://thephiladelphiacitizen.org//article HTML Original
=> /proxy/thephiladelphiacitizen.org/ Proxy Home Page
# Guest Commentary: Time to Say Enough to Corruption
BY Author McAuthor
Mar. 11, 2021
Paragraph with a Tag Link and that's it.
Another paragraph.
This paragraph has a link to an article.
More text.
A little blurb about the author.
## Site Menu
=> /proxy/thephiladelphiacitizen.org/events/ Events
=> /proxy/thephiladelphiacitizen.org/ideas-we-should-steal-festival-2020-videos/ Ideas We Should Steal Festival
=> /proxy/thephiladelphiacitizen.org/how-to-get-involved-in-your-community/ Do Something Guides
=> /proxy/thephiladelphiacitizen.org/about/ About
### Topics
=> /proxy/thephiladelphiacitizen.org/category/politics/ Politics
=> /proxy/thephiladelphiacitizen.org/category/opinion/ Opinion
=> /proxy/thephiladelphiacitizen.org/category/business-and-economy/ Business
=> /proxy/thephiladelphiacitizen.org/category/education/ Education
=> /proxy/thephiladelphiacitizen.org/category/urban-development/ Development
=> /proxy/thephiladelphiacitizen.org/category/environment/ Environment
=> /proxy/thephiladelphiacitizen.org/category/health-wellness/ Health
=> /proxy/thephiladelphiacitizen.org/category/philadelphia-citizen-topics/technology/ Tech
=> /proxy/thephiladelphiacitizen.org/category/jobs-philadelphia/ Jobs
=> /proxy/thephiladelphiacitizen.org/category/food-philadelphia/ Food
=> /proxy/thephiladelphiacitizen.org/category/philadelphia-citizen-topics/arts-and-culture/ Arts
=> /proxy/thephiladelphiacitizen.org/category/philadelphia-sports/ Sports
=> /proxy/thephiladelphiacitizen.org/category/lgbtq/ LGBTQ
=> /proxy/thephiladelphiacitizen.org/category/youth-philadelphia/ Youth
=> /proxy/thephiladelphiacitizen.org/category/philadelphia-events/ Events
=> /proxy/thephiladelphiacitizen.org//about/join-our-team/ Work at The Citizen
### Categories
=> /proxy/thephiladelphiacitizen.org/category/business-and-economy Business for Good
=> /proxy/thephiladelphiacitizen.org/citizencast-audio-articles/ CitizenCast
=> /proxy/thephiladelphiacitizen.org/tag/philadelphia-citizen-of-the-week/ Citizens of the Week
=> /proxy/thephiladelphiacitizen.org/tag/foodizen-philadelphia/ Foodizen
=> /proxy/thephiladelphiacitizen.org//tag/ideas-we-should-steal-philly Ideas We Should Steal
=> /proxy/thephiladelphiacitizen.org//category/rubrics/mystery-shopping-philadelphia-city-hall Mystery Shopper
=> /proxy/thephiladelphiacitizen.org/tag/jason-kelce-eagles-education-season/ Jason Kelces Eagles Education Season
=> /proxy/thephiladelphiacitizen.org/tag/connor-barwin-civic-season/ Connor Barwins Civic Season
=> /proxy/thephiladelphiacitizen.org/tag/malcolm-jenkins-criminal-justice-season-phl/ Malcolm Jenkins Criminal Justice Season
### Voices
=> /proxy/thephiladelphiacitizen.org//author/Connor-Barwin Connor Barwin
=> /proxy/thephiladelphiacitizen.org//author/Courtney-DuChene Courtney DuChene
=> /proxy/thephiladelphiacitizen.org//author/Charles-D--Ellison Charles D. Ellison
=> /proxy/thephiladelphiacitizen.org//author/Jon-Geeting Jon Geeting
=> /proxy/thephiladelphiacitizen.org//author/Anne-Gemmell Anne Gemmell
=> /proxy/thephiladelphiacitizen.org//author/Jill-Harkins Jill Harkins
=> /proxy/thephiladelphiacitizen.org//author/Bruce-Katz Bruce Katz
=> /proxy/thephiladelphiacitizen.org//author/Jason-Kelce Jason Kelce
=> /proxy/thephiladelphiacitizen.org//author/Diana-Lind Diana Lind
=> /proxy/thephiladelphiacitizen.org//author/James-Peterson James Peterson
=> /proxy/thephiladelphiacitizen.org//author/Larry-Platt Larry Platt
=> /proxy/thephiladelphiacitizen.org/author/jessica-press/ Jessica Blatt Press
=> /proxy/thephiladelphiacitizen.org//author/Katherine-Rapin Katherine Rapin
=> /proxy/thephiladelphiacitizen.org//author/Roxanne-Patel-Shepelavy Roxanne Patel Shepelavy
### Featured Partners
=> /proxy/thephiladelphiacitizen.org//board-of-directors/ Board of Directors
=> /proxy/thephiladelphiacitizen.org//corporations-and-foundations Corporate & Foundation Partners
=> /proxy/thephiladelphiacitizen.org//founding-donors/ Founding Donors

View File

@ -0,0 +1,318 @@
<!DOCTYPE html>
<html lang="en-US" class="no-js">
<head>
<title>Politics Archives - The Philadelphia Citizen</title>
</head>
<body class="archive category category-politics category-521">
<div class="fancyboxes deployed">
<div id="newsletterPopup">
<div class="newsletterSpot">
<div class="popupTitle">
<h3>NEWSLETTER SIGNUP</h3>
</div>
</div>
</div>
</div>
<div id="page" class="hfeed site ">
<header id="masthead" class="site-header" role="banner">
<div class="sectionScale">
<div class="burgerWrap mobile" data-state="close">
<div class="burgerBar first"></div>
<div class="burgerBar second"></div>
<div class="burgerBar third"></div>
</div>
<a href="https://thephiladelphiacitizen.org" id="logo">
<img src="https://thephiladelphiacitizen.org/wp-content/themes/citizen/img/logo.png" class="desktopLogo" alt="The Philadephia Citizen" />
<h1>The Philadelphia Citizen</h1><p>What happened. What it means. And what you can do about it.</p>
</a>
<a class="nlSignup" href="https://thephiladelphiacitizen.org/donate">SUPPORT<br>THE CITIZEN</a>
<div class="socialIcons">
<div class="socialWrap">
<a class="fbBtn" title="Facebook" target="_blank" href="https://www.facebook.com/thephillycitizen"></a>
<a class="twitterBtn" title="Twitter" target="_blank" href="https://twitter.com/@thephilacitizen"></a>
<a class="instaBtn" title="Instagram" target="_blank" href="https://instagram.com/thephiladelphiacitizen"></a>
<a class="linkedinBtn" title="LinkedIn" target="_blank" href="https://www.linkedin.com/company/the-philadelphia-citizen/"></a>
<a class="emailBtn" title="Newsletter" href="https://thephiladelphiacitizen.org/sign-up-for-the-citizen-newsletter/"></a>
<a class="smileBtn" title="Amazon Smile" target="_blank" href="https://smile.amazon.com/ch/46-2777419"></a>
<a class="rssBtn" title="RSS" target="_blank" href="https://feeds.feedburner.com/thephiladelphiacitizen/NqdF"></a>
</div>
<div class="expandBtn"></div>
</div>
<div id="mSearch" class="mobile" data-show="closed">
<div class="searchGlass">
<div class="handle">
<div class="tail"></div>
</div>
</div>
</div>
</div>
</header>
<div id="mobileSearch" class="mobile">
<form method="get" action="https://thephiladelphiacitizen.org/">
<input type="text" id="searchInput" value="" name="s" placeholder="Search">
<input type="submit" id="searchsubmit" value="Search" class="btn" />
</form>
</div>
<div class="pageNav">
<div class="navCenter">
<div class="article-progress">
<div class="article-pg-fill"></div>
</div>
<div id="navContainer">
<div class="bolt">
<img src="https://thephiladelphiacitizen.org/wp-content/themes/citizen/img/footerBolt-small.png" alt="" />
</div>
<div class="navContainer-wrap">
<a href="#" id="menuBtnLink">
<div id="menuBtnWrap" >
<div class="burgerWrap">
<div class="burgerBar first"></div>
<div class="burgerBar second"></div>
<div class="burgerBar third"></div>
</div>
<p>Menu</p>
<div class="menuSpacer"></div>
</div>
</a>
<span>&#9679;</span>
<a href="https://thephiladelphiacitizen.org/events/" class="nothing">
<p>Events</p>
</a>
<span>&#9679;</span>
<a href="https://thephiladelphiacitizen.org/ideas-we-should-steal-festival-2020-videos/" class="nothing">
<p>Ideas We Should Steal Festival</p>
</a>
<span>&#9679;</span>
<a href="https://thephiladelphiacitizen.org/how-to-get-involved-in-your-community/" class="nothing">
<p>Do Something Guides</p>
</a>
<span>&#9679;</span>
<a href="https://thephiladelphiacitizen.org/about/" class="nothing">
<p>About</p>
</a>
<span>&#9679;</span>
<div id="searchLink" href="#">
<p>Search</p>
<form method="get" id="searchform" action="https://thephiladelphiacitizen.org/">
<input type="text" id="searchInput" value="" name="s" placeholder="Search...">
<input type="submit" id="searchsubmit" value="Search" class="btn" />
</form>
<div class="searchWrap">
<div class="searchGlass">
<div class="handle">
<div class="tail"></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div id="dropWrapper">
<div id="dropContent">
<div class="dropSizer">
<div id="topicWrap" class="menuContent">
<strong>Topics</strong>
<ul>
<li><a class="business" title="(20)" href="https://thephiladelphiacitizen.org/category/politics/">Politics</a></li>
<li><a class="business" title="(20)" href="https://thephiladelphiacitizen.org/category/opinion/">Opinion</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/business-and-economy/" target="_blank" rel="noopener noreferrer">Business</a></li>
<li><a class="schools" title="(46)" href="https://thephiladelphiacitizen.org/category/education/">Education</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/urban-development/">Development</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/environment/">Environment</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/health-wellness/">Health</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/philadelphia-citizen-topics/technology/">Tech</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/jobs-philadelphia/">Jobs</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/food-philadelphia/">Food</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/philadelphia-citizen-topics/arts-and-culture/">Arts</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/philadelphia-sports/">Sports</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/lgbtq/">LGBTQ</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/youth-philadelphia/">Youth</a></li>
<li><a class="events" title="(4)" href="https://thephiladelphiacitizen.org/category/philadelphia-events/">Events</a></li>
<li><a href="/about/join-our-team/">Work at The Citizen</a></li>
</ul> </div>
<div id="categoryWrap" class="menuContent">
<strong>Categories</strong>
<ul>
<li><a href="https://thephiladelphiacitizen.org/category/business-and-economy" target="_blank" rel="noopener noreferrer">Business for Good</a></li>
<li><a href="https://thephiladelphiacitizen.org/citizencast-audio-articles/" target="_blank" rel="noopener noreferrer">CitizenCast</a></li>
<li><a href="https://thephiladelphiacitizen.org/tag/philadelphia-citizen-of-the-week/" target="_blank" rel="noopener noreferrer">Citizens of the Week</a></li>
<li><a href="https://thephiladelphiacitizen.org/tag/foodizen-philadelphia/" target="_blank" rel="noopener noreferrer">Foodizen</a></li>
<li><a href="/tag/ideas-we-should-steal-philly" target="_blank" rel="noopener noreferrer">Ideas We Should Steal</a></li>
<li><a href="/category/rubrics/mystery-shopping-philadelphia-city-hall">Mystery Shopper</a></li>
<li><a href="https://thephiladelphiacitizen.org/tag/jason-kelce-eagles-education-season/" target="_blank" rel="noopener noreferrer">Jason Kelces Eagles Education Season</a></li>
<li><a href="https://thephiladelphiacitizen.org/tag/connor-barwin-civic-season/" target="_blank" rel="noopener noreferrer">Connor Barwins Civic Season</a></li>
<li><a href="https://thephiladelphiacitizen.org/tag/malcolm-jenkins-criminal-justice-season-phl/" target="_blank" rel="noopener noreferrer">Malcolm Jenkins Criminal Justice Season</a></li>
</ul> </div>
<div id="voiceWrap" class="menuContent">
<strong>Voices</strong>
<ul>
<li>Connor Barwin</li>
<li>Courtney DuChene</li>
<li>Charles D. Ellison</li>
<li>Jon Geeting</li>
<li>Anne Gemmell</li>
<li>Jill Harkins</li>
<li>Bruce Katz</li>
<li>Jason Kelce</li>
<li>Diana Lind</li>
<li>James Peterson</li>
<li>Larry Platt</li>
<li><a href="https://thephiladelphiacitizen.org/author/jessica-press/">Jessica Blatt Press</a></li>
<li>Katherine Rapin</li>
<li>Roxanne Patel Shepelavy</li>
</ul> </div>
<div id="sponsorWrap" class="menuContent">
<div class="listCol">
<strong>Featured Partners</strong>
<ul>
<li><a href="/board-of-directors/">Board of Directors</a></li>
<li><a href="/corporations-and-foundations">Corporate &amp; Foundation Partners</a></li>
<li><a href="/founding-donors/">Founding Donors</a></li>
</ul> </div>
</div>
</div>
</div>
</div>
</div>
<!-- site-header -->
<div class="nav-bar mobileNav">
<ul>
<li><a href="/" >Stories</a></li>
<li><a href="https://thephiladelphiacitizen.org/events/" >Events</a></li>
<li><a href="https://thephiladelphiacitizen.org/ideas-we-should-steal-festival-2020-videos/" >Ideas We Should Steal Festival</a></li>
<li><a href="https://thephiladelphiacitizen.org/how-to-get-involved-in-your-community/" >Do Something Guides</a></li>
<li class="parent"><a href="https://thephiladelphiacitizen.org/topic-list">Topics</a>
<div class="submenu">
<ul>
<li><a class="business" title="(20)" href="https://thephiladelphiacitizen.org/category/politics/">Politics</a></li>
<li><a class="business" title="(20)" href="https://thephiladelphiacitizen.org/category/opinion/">Opinion</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/business-and-economy/" target="_blank" rel="noopener noreferrer">Business</a></li>
<li><a class="schools" title="(46)" href="https://thephiladelphiacitizen.org/category/education/">Education</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/urban-development/">Development</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/environment/">Environment</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/health-wellness/">Health</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/philadelphia-citizen-topics/technology/">Tech</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/jobs-philadelphia/">Jobs</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/food-philadelphia/">Food</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/philadelphia-citizen-topics/arts-and-culture/">Arts</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/philadelphia-sports/">Sports</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/lgbtq/">LGBTQ</a></li>
<li><a href="https://thephiladelphiacitizen.org/category/youth-philadelphia/">Youth</a></li>
<li><a class="events" title="(4)" href="https://thephiladelphiacitizen.org/category/philadelphia-events/">Events</a></li>
<li><a href="/about/join-our-team/">Work at The Citizen</a></li>
</ul> </div>
</li>
<li><a href="https://podcasts.apple.com/us/podcast/citizencast/id1348163928#episodeGuid=20023371-2c58-4e1a-83ed-7ef1946f834c" >CitizenCast</a></li>
<li><a href="https://thephiladelphiacitizen.org/about/" >About</a></li>
<li><a href="https://thephiladelphiacitizen.org/donate/" >Support Us</a></li>
<li><a href="https://thephiladelphiacitizen.org/contact/" >Contact</a></li>
<li class="parent"><a>Social</a>
<div class="submenu">
<ul>
<li><a title="Facebook" target="_blank" href="https://www.facebook.com/thephillycitizen">Facebook</a>
<li><a title="Twitter" target="_blank" href="https://twitter.com/@thephilacitizen">Twitter</a>
<li><a title="Instagram" target="_blank" href="https://instagram.com/thephiladelphiacitizen">Instagram</a>
<li><a title="LinkedIn" target="_blank" href="https://www.linkedin.com/company/the-philadelphia-citizen/">LinkedIn</a>
<li><a title="Newsletter" href="https://thephiladelphiacitizen.org/sign-up-for-the-citizen-newsletter/">Newsletter</a>
<li><a title="Amazon Smile" target="_blank" href="https://smile.amazon.com/ch/46-2777419">Amazon Smile</a>
<li><a title="RSS" target="_blank" href="https://feeds.feedburner.com/thephiladelphiacitizen/NqdF">RSS</a>
</ul>
</div>
</li>
</ul>
</div>
<div class="article-progress"></div>
<div id="content" class="site-content">
<div class="overlay"></div>
<section id="primary" class="content-area">
<main id="main" class="site-main" role="main">
<header class="page-header">
<h1 class="page-title">
<span>Politics</span> </h1>
</header><!-- .page-header -->
<div class="row">
<a href="https://thephiladelphiacitizen.org/ideas-please/" class="col standard" style="background:url(https://thephiladelphiacitizen.org/wp-content/uploads/2021/03/Jim-Kenney-Philadelphia-1-791x400.jpeg); background-position:center center!important">
<img style="display:none;" class="mobileTileImg" src="https://thephiladelphiacitizen.org/wp-content/uploads/2021/03/Jim-Kenney-Philadelphia-1-791x400.jpeg" alt="" />
<span class="text-overlay">
<h1>Ideas, Please!</h1> <p>Two recent public policy press conferences raise the question: Do Philly leaders have any new ideas for old, intransigent problems? Maybe one gaping problem is an opportunity for new thinking</p>
<span class="author">By Larry Platt</span> </span>
</a>
<a href="https://thephiladelphiacitizen.org/enough-corruption-philly/" class="col standard" style="background:url(https://thephiladelphiacitizen.org/wp-content/uploads/2021/03/John-Dougherty-Philadelphia-1-791x400.jpeg); background-position:center center!important">
<img style="display:none;" class="mobileTileImg" src="https://thephiladelphiacitizen.org/wp-content/uploads/2021/03/John-Dougherty-Philadelphia-1-791x400.jpeg" alt="" />
<span class="text-overlay">
<h1>Guest Commentary: Time to Say <i>Enough</i> to Corruption</h1> <p>Union boss John Dougherty was indicted again this week, and 12 percent of City Council is facing corruption charges. One outraged elected official is calling for an end to the scourge of Philly politics</p>
<span class="author">By Jared Solomon</span> </span>
</a>
<a href="https://thephiladelphiacitizen.org/leaving-money-on-the-table/" class="col standard" style="background:url(https://thephiladelphiacitizen.org/wp-content/uploads/2021/03/Fairmount_Neighborhood-791x400.jpeg); background-position:center center!important">
<img style="display:none;" class="mobileTileImg" src="https://thephiladelphiacitizen.org/wp-content/uploads/2021/03/Fairmount_Neighborhood-791x400.jpeg" alt="" />
<span class="text-overlay">
<h1>Leaving Money on the Table</h1> <p>Rising house prices <em>should</em> mean rising tax revenue to help close Phillys budget gap. Too bad, Philly 3.0s engagement director notes, the Citys property office is still too dysfunctional to reassess values</p>
<span class="author">By Jon Geeting</span> </span>
</a>
<a href="https://thephiladelphiacitizen.org/we-only-have-one-mayor/" class="col standard" style="background:url(https://thephiladelphiacitizen.org/wp-content/uploads/2021/03/Ed-Rendell-and-Dwight-Evans-791x400.jpg); background-position:center center!important">
<img style="display:none;" class="mobileTileImg" src="https://thephiladelphiacitizen.org/wp-content/uploads/2021/03/Ed-Rendell-and-Dwight-Evans-791x400.jpg" alt="" />
<span class="text-overlay">
<h1>“We Only Have One Mayor”</h1> <p>Former Governor Ed Rendell and Congressman Dwight Evans voice their concerns for the state of Philadelphia</p>
<span class="author">By Larry Platt</span> </span>
</a>
<a href="https://thephiladelphiacitizen.org/philadelphia-covid-19-aid/" class="col standard" style="background:url(https://thephiladelphiacitizen.org/wp-content/uploads/2021/03/6785092294_ad9bb18561_k-1-791x400.jpg); background-position:center center!important">
<img style="display:none;" class="mobileTileImg" src="https://thephiladelphiacitizen.org/wp-content/uploads/2021/03/6785092294_ad9bb18561_k-1-791x400.jpg" alt="" />
<span class="text-overlay">
<h1>Congress, Dont Cut Local Covid-19 Aid</h1> <p>The Covid Relief Bill includes much-needed funding for city services—if, Philly 3.0s engagement director cautions, Congress doesnt take it away</p>
<span class="author">By Jon Geeting</span> </span>
</a>
<a href="https://thephiladelphiacitizen.org/hannah-callowhill-penn-bio/" class="col standard" style="background:url(https://thephiladelphiacitizen.org/wp-content/uploads/2021/02/Hannah-Callowhill-Penn-copy-791x400.jpg); background-position:center center!important">
<img style="display:none;" class="mobileTileImg" src="https://thephiladelphiacitizen.org/wp-content/uploads/2021/02/Hannah-Callowhill-Penn-copy-791x400.jpg" alt="" />
<span class="text-overlay">
<h1>Hannah Callowhill Penn | Philadelphia Women&#8217;s History Month All-Star</h1> <p>All-Star #4: Hannah Callowhill Penn</p>
</span>
</a>
<a href="https://thephiladelphiacitizen.org/disruptive-mayoral-wishlist/" class="col standard" style="background:url(https://thephiladelphiacitizen.org/wp-content/uploads/2021/02/Mayoral-wishlist-Philadelphia-1-791x400.jpg); background-position:center center!important">
<img style="display:none;" class="mobileTileImg" src="https://thephiladelphiacitizen.org/wp-content/uploads/2021/02/Mayoral-wishlist-Philadelphia-1-791x400.jpg" alt="" />
<span class="text-overlay">
<h1>A Mayoral Wishlist, Disruptor Edition</h1> <p>If we really want a robust debate in 2023, how about some bold, unconventional candidates? Here, a list of unusual suspects.</p>
<span class="author">By Larry Platt</span> </span>
</a>
<a href="https://thephiladelphiacitizen.org/will-philly-be-ready-for-the-vaccine-surge/" class="col standard" style="background:url(https://thephiladelphiacitizen.org/wp-content/uploads/2021/02/Covid-vaccine-in-Philadelphia-791x400.jpg); background-position:center center!important">
<img style="display:none;" class="mobileTileImg" src="https://thephiladelphiacitizen.org/wp-content/uploads/2021/02/Covid-vaccine-in-Philadelphia-791x400.jpg" alt="" />
<span class="text-overlay">
<h1>Will Philly Be Ready For the Vaccine Surge?</h1> <p>President Biden has promised that vaccine supply is ahead of schedule. Philly 3.0s engagement editor wonders: Can Mayor Kenney and other leaders agree on a plan to get the shots in arms?</p>
<span class="author">By Jon Geeting</span> </span>
</a>
</div>
<div class="alm-btn-wrap"><button style="margin-bottom:2rem;" id="load-more" class="alm-load-more-btn more loadMorer moreTopics">Show More</button></div> </main><!-- .site-main -->
</section><!-- .content-area -->
</div><!-- .site-content -->
</div><!-- .site -->
</body>
</html>

View File

@ -0,0 +1,78 @@
# The Philadelphia Citizen
What happened. What it means. And what you can do about it.
=> https://thephiladelphiacitizen.org//category/some-topic HTML Original
=> /proxy/thephiladelphiacitizen.org/ Proxy Home Page
## Politics
=> /proxy/thephiladelphiacitizen.org/ideas-please/ Ideas, Please!
=> /proxy/thephiladelphiacitizen.org/enough-corruption-philly/ Guest Commentary: Time to Say Enough to Corruption
=> /proxy/thephiladelphiacitizen.org/leaving-money-on-the-table/ Leaving Money on the Table
=> /proxy/thephiladelphiacitizen.org/we-only-have-one-mayor/ “We Only Have One Mayor”
=> /proxy/thephiladelphiacitizen.org/philadelphia-covid-19-aid/ Congress, Dont Cut Local Covid-19 Aid
=> /proxy/thephiladelphiacitizen.org/hannah-callowhill-penn-bio/ Hannah Callowhill Penn | Philadelphia Womens History Month All-Star
=> /proxy/thephiladelphiacitizen.org/disruptive-mayoral-wishlist/ A Mayoral Wishlist, Disruptor Edition
=> /proxy/thephiladelphiacitizen.org/will-philly-be-ready-for-the-vaccine-surge/ Will Philly Be Ready For the Vaccine Surge?
## Site Menu
=> /proxy/thephiladelphiacitizen.org/events/ Events
=> /proxy/thephiladelphiacitizen.org/ideas-we-should-steal-festival-2020-videos/ Ideas We Should Steal Festival
=> /proxy/thephiladelphiacitizen.org/how-to-get-involved-in-your-community/ Do Something Guides
=> /proxy/thephiladelphiacitizen.org/about/ About
### Topics
=> /proxy/thephiladelphiacitizen.org/category/politics/ Politics
=> /proxy/thephiladelphiacitizen.org/category/opinion/ Opinion
=> /proxy/thephiladelphiacitizen.org/category/business-and-economy/ Business
=> /proxy/thephiladelphiacitizen.org/category/education/ Education
=> /proxy/thephiladelphiacitizen.org/category/urban-development/ Development
=> /proxy/thephiladelphiacitizen.org/category/environment/ Environment
=> /proxy/thephiladelphiacitizen.org/category/health-wellness/ Health
=> /proxy/thephiladelphiacitizen.org/category/philadelphia-citizen-topics/technology/ Tech
=> /proxy/thephiladelphiacitizen.org/category/jobs-philadelphia/ Jobs
=> /proxy/thephiladelphiacitizen.org/category/food-philadelphia/ Food
=> /proxy/thephiladelphiacitizen.org/category/philadelphia-citizen-topics/arts-and-culture/ Arts
=> /proxy/thephiladelphiacitizen.org/category/philadelphia-sports/ Sports
=> /proxy/thephiladelphiacitizen.org/category/lgbtq/ LGBTQ
=> /proxy/thephiladelphiacitizen.org/category/youth-philadelphia/ Youth
=> /proxy/thephiladelphiacitizen.org/category/philadelphia-events/ Events
=> /proxy/thephiladelphiacitizen.org//about/join-our-team/ Work at The Citizen
### Categories
=> /proxy/thephiladelphiacitizen.org/category/business-and-economy Business for Good
=> /proxy/thephiladelphiacitizen.org/citizencast-audio-articles/ CitizenCast
=> /proxy/thephiladelphiacitizen.org/tag/philadelphia-citizen-of-the-week/ Citizens of the Week
=> /proxy/thephiladelphiacitizen.org/tag/foodizen-philadelphia/ Foodizen
=> /proxy/thephiladelphiacitizen.org//tag/ideas-we-should-steal-philly Ideas We Should Steal
=> /proxy/thephiladelphiacitizen.org//category/rubrics/mystery-shopping-philadelphia-city-hall Mystery Shopper
=> /proxy/thephiladelphiacitizen.org/tag/jason-kelce-eagles-education-season/ Jason Kelces Eagles Education Season
=> /proxy/thephiladelphiacitizen.org/tag/connor-barwin-civic-season/ Connor Barwins Civic Season
=> /proxy/thephiladelphiacitizen.org/tag/malcolm-jenkins-criminal-justice-season-phl/ Malcolm Jenkins Criminal Justice Season
### Voices
=> /proxy/thephiladelphiacitizen.org//author/Connor-Barwin Connor Barwin
=> /proxy/thephiladelphiacitizen.org//author/Courtney-DuChene Courtney DuChene
=> /proxy/thephiladelphiacitizen.org//author/Charles-D--Ellison Charles D. Ellison
=> /proxy/thephiladelphiacitizen.org//author/Jon-Geeting Jon Geeting
=> /proxy/thephiladelphiacitizen.org//author/Anne-Gemmell Anne Gemmell
=> /proxy/thephiladelphiacitizen.org//author/Jill-Harkins Jill Harkins
=> /proxy/thephiladelphiacitizen.org//author/Bruce-Katz Bruce Katz
=> /proxy/thephiladelphiacitizen.org//author/Jason-Kelce Jason Kelce
=> /proxy/thephiladelphiacitizen.org//author/Diana-Lind Diana Lind
=> /proxy/thephiladelphiacitizen.org//author/James-Peterson James Peterson
=> /proxy/thephiladelphiacitizen.org//author/Larry-Platt Larry Platt
=> /proxy/thephiladelphiacitizen.org/author/jessica-press/ Jessica Blatt Press
=> /proxy/thephiladelphiacitizen.org//author/Katherine-Rapin Katherine Rapin
=> /proxy/thephiladelphiacitizen.org//author/Roxanne-Patel-Shepelavy Roxanne Patel Shepelavy
### Featured Partners
=> /proxy/thephiladelphiacitizen.org//board-of-directors/ Board of Directors
=> /proxy/thephiladelphiacitizen.org//corporations-and-foundations Corporate & Foundation Partners
=> /proxy/thephiladelphiacitizen.org//founding-donors/ Founding Donors

View File

@ -0,0 +1,5 @@
<html><head><title>Some Page</title></head>
<body class="something-else">
Some stuff
</body>
</html>

View File

@ -0,0 +1,2 @@
Unknown page type. View this via HTTPS instead:
=> https://thephiladelphiacitizen.org//some-random-page

View File

@ -0,0 +1,3 @@
=> /proxy/thephiladelphiacitizen.org
=> /proxy/billypenn.com
=> /proxy/whyy.org

View File

@ -0,0 +1,54 @@
from pgnp import handlers
from .util import TestBase
class TestHandlerDefault(TestBase):
def test_parse(self):
handler = handlers.HandlerDefault("")
with open(self.path / "output.gmi", newline="") as f_in:
expected = f_in.read()
self.assertEqual("", handler.output)
handler.parse()
self.assertEqual(expected, handler.output)
class TestHandlerCitizen(TestBase):
def setUp(self):
super().setUp()
self.url = "thephiladelphiacitizen.org"
def test_get(self):
handler = handlers.HandlerCitizen(self.url)
with open(self.path / "input.html", "rb") as f_in:
expected = f_in.read()
response = handler.get()
self.assertEqual(expected, response.content)
def test_parse(self):
handler = handlers.HandlerCitizen(self.url)
with open(self.path / "output.gmi", newline="") as f_in:
expected = f_in.read()
self.assertEqual("", handler.output)
handler.parse()
self.assertEqual(expected, handler.output)
class TestHandlerCitizenCategory(TestHandlerCitizen):
def setUp(self):
super().setUp()
self.url = "thephiladelphiacitizen.org/category/some-topic"
class TestHandlerCitizenArticle(TestHandlerCitizen):
def setUp(self):
super().setUp()
self.url = "thephiladelphiacitizen.org/article"
class TestHandlerCitizenUnknown(TestHandlerCitizen):
def setUp(self):
super().setUp()
self.url = "thephiladelphiacitizen.org/some-random-page"

58
test_pgnp/util.py Normal file
View File

@ -0,0 +1,58 @@
import re
import sys
import unittest
import pgnp
from pathlib import Path
from unittest.mock import (Mock, create_autospec, DEFAULT)
from requests_html import HTML
class HTMLSessionMock(pgnp.handlers.HTMLSession):
"""HTMLSession with a fake get() method.
Subclass this and set PATH to a local HTML file path.
"""
PATH = Path("/")
def get(self, url, **kwargs):
"""Fake a GET request from local disk, with mock response object."""
url_suffix = re.sub("http[s]://[^/]+/*", "", url)
response = Mock()
response.headers = {"Content-Type": "text/html"}
path = self.__class__.PATH
if path.exists():
with open(path, "rb") as f_in:
response.content = f_in.read()
else:
response.content = "404"
response.html = HTML(html=response.content)
return response
class TestBase(unittest.TestCase):
@property
def path(self):
"""Path for supporting files for each class."""
path = self.__class__.__module__.split(".") + [self.__class__.__name__]
path.insert(1, "data")
path = Path("/".join(path))
return path
def setUp(self):
self.maxDiff = None
self.setup_mock()
def tearDown(self):
self.tear_down_mock()
def setup_mock(self):
class mocker(HTMLSessionMock):
PATH = self.path / "input.html"
hnd = sys.modules["pgnp"].handlers
hnd.HTMLSessionOrig = hnd.HTMLSession
hnd.HTMLSession = mocker
def tear_down_mock(self):
hnd = sys.modules["pgnp"].handlers
hnd.HTMLSession = hnd.HTMLSessionOrig