Last active
August 11, 2020 04:57
-
-
Save AO8/085f396e3918796edce7be407dd4a3ad to your computer and use it in GitHub Desktop.
Daily Coronavirus data update (global and WA state) with Python 3, requests, and beautifulsoup.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Check out https://ncov2019.live/data by Avi Schiffmann | |
# as featured in the Seattle Times at: | |
# https://www.seattletimes.com/seattle-news/education/qa-avi-schiffmann-the-washington-state-teen-behind-a-coronavirus-website-with-millions-of-views/ | |
from email.mime.text import MIMEText | |
import smtplib | |
import ssl | |
import sys | |
import stdiomask | |
from bs4 import BeautifulSoup | |
import requests | |
URL = "https://ncov2019.live/data" | |
def main(): | |
"""Make call to site, extract and transform date, then email through Gmail.""" | |
resp = get_response(URL) | |
soup = create_soup(resp) | |
data = get_data_from_soup(soup) | |
cases = int(get_cases_from_data(data).replace(",", "")) | |
deaths = int(get_deaths_from_data(data).replace(",", "")) | |
recovered = int(get_recovered_from_data(data).replace(",", "")) | |
wa_data = get_wa_data_from_soup(soup) | |
wa_cases = int(get_cases_from_wa_data(wa_data).replace(",", "")) | |
wa_deaths = int(get_deaths_from_wa_data(wa_data).replace(",", "")) | |
body = f"""Your daily Coronavirus update. | |
GLOBAL | |
Confirmed cases: | |
{cases:,} | |
Total deaths: | |
{deaths:,} | |
Mortality rate: | |
{deaths/cases:.1%} | |
Total recovered: | |
{recovered:,} | |
WASHINGTON STATE | |
Confirmed cases: | |
{wa_cases:,} | |
Total deaths: | |
{wa_deaths} | |
Source: ncov2019.live/data (as featured in the Seattle Times)""" | |
sender = "your_gmail_address" | |
password = stdiomask.getpass(mask="*") | |
receiver = "#your_to_address" | |
send_gmail(sender, password, receiver, "Coronavirus update", body) | |
def send_gmail(sender, password, receiver, subject, body): | |
"""Function for sending a nicely-formatted email through Gmail.""" | |
msg = MIMEText(body) | |
msg["Subject"] = subject | |
msg["From"] = sender | |
msg["To"] = receiver | |
# create a secure SSL context | |
context = ssl.create_default_context() | |
# 'with' context manager closes connection at end of indented code block | |
with smtplib.SMTP_SSL("smtp.gmail.com", 465, context=context) as s: | |
s.login(sender, password) | |
s.sendmail(sender, receiver, msg.as_string()) | |
print("Email sent!") | |
def get_response(url): | |
"""Make a request to supplied url.""" | |
try: | |
resp = requests.get(url) | |
print(resp.status_code) | |
except requests.exceptions.RequestException as e: | |
print("There was a problem getting a response from the url provided:\n\n{e}") | |
sys.exit() | |
return resp | |
def create_soup(resp): | |
"""Convert response from get_response() to a soup object.""" | |
html = resp.text | |
soup = BeautifulSoup(html, "html.parser") | |
return soup | |
def get_data_from_soup(soup): | |
"""Get data from soup object and return a list of p's. | |
The p tags in col-12 collects key Coronavirus stats and is | |
specific to https://ncov2019.live/data. | |
""" | |
data_div = soup.find_all(class_="container--wrap")[0] | |
data = data_div.find_all("p") | |
return data | |
def get_cases_from_data(data): | |
"""Get total confirmed cases from data, a list. | |
Item at index 2 corresponds to total confirmed cases. | |
""" | |
confirmed_cases = data[3].get_text().strip() | |
return confirmed_cases | |
def get_deaths_from_data(data): | |
"""Get total deaths from data, a list. | |
Item at index 4 corresponds to total deaths. | |
""" | |
total_deaths = data[5].get_text().strip() | |
return total_deaths | |
def get_recovered_from_data(data): | |
"""Get total recovered cases from data, a list. | |
Item at index 8 corresponds to total deaths. | |
""" | |
total_deaths = data[9].get_text().strip() | |
return total_deaths | |
def get_wa_data_from_soup(soup): | |
state_table = soup.find_all("table")[2] | |
data = state_table.find_all("td") | |
return data | |
def get_cases_from_wa_data(data): | |
for idx, element in enumerate(data): | |
if element.text.strip() == "Washington": | |
wa_idx = idx | |
wa_cases = data[wa_idx+1].text.strip() | |
return wa_cases | |
def get_deaths_from_wa_data(data): | |
for idx, element in enumerate(data): | |
if element.text.strip() == "Washington": | |
wa_idx = idx | |
wa_deaths = data[wa_idx+2].text.strip() | |
return wa_deaths | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment