рд╕рд╣реА рдХреЛрд╡рд┐рдж -19 рдЧреНрд░рд╛рдлрд┐рдХреНрд╕

рдкреБрд╕реНрддрдХрд╛рд▓рдпреЛрдВ рдФрд░ рд╡реЗрдм рдлреНрд░реЗрдорд╡рд░реНрдХ рдХреЗ рд╕рд╛рде рд╡реНрдпрд╛рдкрдХ рдЬреБрдиреВрди рдХреЗ рд╕рдордп рдореЗрдВ, рд╣рдо рдиреНрдпреВрдирддрдо рд╕рд╛рдзрдиреЛрдВ рдХреЗ рд╕рд╛рде рд╕рдорд╕реНрдпрд╛рдУрдВ рдХреЛ рд╣рд▓ рдХрд░рдиреЗ рдХреА рдЦреБрд╢реА рдХреЛ рднреВрд▓рдиреЗ рд▓рдЧреЗред рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ, рд╣рдо рд╡реИрдирд┐рд▓рд╛ рдкрд╛рдпрдерди рдФрд░ рдЬрд╛рд╡рд╛рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдПрдХ рдкреНрд░рд╛рд╕рдВрдЧрд┐рдХ рд╡рд┐рд╖рдп рдкрд░ рдПрдХ рд╡реЗрдм рд╕реЗрд╡рд╛ рдкреНрд░рджрд╛рди рдХрд░реЗрдВрдЧреЗ, рдФрд░ рдЗрд╕реЗ GitLab Pages рдореЗрдВ рднреА рдЗрдВрд╕реНрдЯреЙрд▓ рдХрд░реЗрдВрдЧреЗ ред рдЕрдирд╛рд╡рд╢реНрдпрдХ рдирд┐рд░реНрднрд░рддрд╛ рдХреЗ рдмрд┐рдирд╛ рддреЗрдЬ, рдиреНрдпреВрдирддрд░, рдФрд░ рдпрдерд╛рд╕рдВрднрд╡ рд╕реБрдВрджрд░ред


рдкреНрд░реЗрд░рдгрд╛ vidosy рдХреИрд╕реЗ рддреЛ рд╣рдо рдкрд┐рдЯрд╛рдИ COVID рдмрддрд╛рдУ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП - 19 рд╕реЗ minutephysics , рдореИрдВ рдореБрдХреНрдд (teleworking рдФрд░ рдЧреГрд╣ рдордВрддреНрд░рд╛рд▓рдп рд╕реЗ) рд╕рдордп рд╕реЗрд╡рд╛ рд╕реЗ рдбреЗрдЯрд╛ рдкрд░ рдЖрдзрд╛рд░рд┐рдд рд╣реИ рдореЗрдВ рддрдп рдХреА рд░реВрд╕ рдореЗрдВ рдФрд░ рджреБрдирд┐рдпрд╛ рдореЗрдВ рдореИрдкреНрд╕ рдХреЛрд░реЛрдирд╛ рдкреНрд░рд╕рд╛рд░ рдХреА Yandex рд░реЗрдЦрд╛рдВрдХрди, рдЙрди рд▓реЛрдЧреЛрдВ рдХреЗ рд╕рдорд╛рди рдмрдирд╛рддрд╛ рд╣реИ рдХреЛрд╡рд┐рдж рдЯреНрд░реЗрдВрдб рдкреЗрдЬ рдкрд░ ред рдпрд╣рд╛рдБ рдпрд╣ рдЖрдпрд╛ рд╣реИ:



рджрд┐рд▓рдЪрд╕реНрдк? рдЪрд▓реЛ рдЪрд▓рддреЗ рд╣реИрдВ!


рдбреЗрдЯрд╛ рдХрд╣рд╛рдБ рд╕реЗ рд▓рд╛рдПрдБ?


рдЙрд╕ рд╕рдордп рдХреЗ рдЖрд╕рдкрд╛рд╕ рдЬрдм рдореБрдЭреЗ рд░реВрд╕ рдХреЗ рдХреНрд╖реЗрддреНрд░реЛрдВ рдХреЗ рд▓рд┐рдП minutephysics рд╕реЗ рдЧреНрд░рд╛рдлрд╝ рдХреЛ рдкреБрди: рдкреНрд░рд╕реНрддреБрдд рдХрд░рдиреЗ рдХрд╛ рд╡рд┐рдЪрд╛рд░ рдерд╛, рдпрд╛рдВрдбреЗрдХреНрд╕ рдиреЗ рдкреНрд░рддреНрдпреЗрдХ рдХреНрд╖реЗрддреНрд░ рдХреЗ рд▓рд┐рдП рдорд╛рдирдЪрд┐рддреНрд░ рдореЗрдВ рд╣рд┐рд╕реНрдЯреЛрдЧреНрд░рд╛рдореНрд╕ рдХреЛ рдЬреЛрдбрд╝рд╛ред



, . - , , , , requests . , ( , , , ):


from urllib.request import urlopen
from html.parser import HTMLParser
import json

class Covid19DataLoader(HTMLParser):
    page_url = "https://yandex.ru/web-maps/covid19"

    def __init__(self):
        super().__init__()
        self.config_found = False
        self.config = None

    def load(self):
        with urlopen(self.page_url) as response:
            page = response.read().decode("utf8")
        self.feed(page)
        return self.config['covidData']

    def handle_starttag(self, tag, attrs):
        if tag == 'script':
            for k, v in attrs:
                if k == 'class' and v == 'config-view':
                    self.config_found = True

    def handle_data(self, data):
        if self.config_found and not self.config:
            self.config = json.loads(data)

?


, тАФ HTML-, Chart.js. - , string.Template:


def get_html(covid_data):
    template_str = open(page_path, 'r', encoding='utf-8').read()
    template = Template(template_str)
    page = template.substitute(
        covid_data=json.dumps(covid_data),
        data_info=get_info(covid_data)
    )
    return page

page_path :


<!DOCTYPE html>
<html>
<head><!-- ... --></head>
    <body>
    <!-- ... -->
    <div>$data_info</div>
    <script type="text/javascript">
        let covid_data = $covid_data
        // ...
    </script>
</body>
</html>

! ! !


?


. Python:


from http.server import BaseHTTPRequestHandler
from lib.data_loader import Covid19DataLoader
from lib.page_maker import get_html

class Handler(BaseHTTPRequestHandler):
    def do_GET(self):
        if self.path == '/':
            self.send_response(200)
            self.send_header('Content-Type', 'text/html')
            self.end_headers()
            try:
                response = get_html(Covid19DataLoader().load())
                self.wfile.write(response.encode('utf-8'))
            except Exception as e:
                self.send_error(500)
                print(f'{type(e).__name__}: {e}')
        else:
            self.send_error(404)

, GitLab Pages, !


, , , .
: . (, cron). , !



Aatish Bhatia, Y , X тАФ .


, 3 , . " ?" , , , - ( ) , !


from datetime import timedelta
from functools import reduce

y_axis_window = timedelta(days=3).total_seconds()

def get_cases_in_window(data, current_time):
    window_open_time = current_time - y_axis_window
    cases_in_window = list(filter(lambda s: window_open_time <= s['ts'] < current_time, data))
    return cases_in_window

def differentiate(data):
    result = [data[0]]
    for prev_i, cur_sample in enumerate(data[1:]):
        result.append({
            'ts': cur_sample['ts'],
            'value': cur_sample['value'] - data[prev_i]['value']
        })
    return result

def get_trend(histogram):
    trend = []
    new_cases = differentiate(histogram)
    for sample in histogram:
        current_time = sample['ts']
        total_cases = sample['value']
        new_cases_in_window = get_cases_in_window(new_cases, current_time)
        total_new_cases_in_window = reduce(lambda a, c: a + c['value'], new_cases_in_window, 0)
        trend.append({'x': total_cases,'y': total_new_cases_in_window})
    return trend

def get_trends(data_items):
    return { area['name']: get_trend(area['histogram']) for area in data_items }


, ( CSS Grid, ), . , - . .


?


Docker, , тАФ VPS, docker-compose up --build -d, cron - ( , ?? , ...), , , http.server , . GitLab CI ssh ( ).


, , , .


GitLab Pages:


import os
from lib.data_loader import Covid19DataLoader
from lib.data_processor import get_trends
from lib.page_maker import get_html

page_dir = 'public'
page_name = 'index.html'

print('Updating Covid-19 data from Yandex...')
raw_data = Covid19DataLoader().load()
print('Calculating trends...')
trends = get_trends(raw_data['items'])
page = get_html({'raw_data': raw_data, 'trends': trends})

if not os.path.isdir(page_dir):
    os.mkdir(page_dir)
page_path = os.path.join(page_dir, page_name)
open(page_path, 'w', encoding='utf-8').write(page)
print(f'Page saved as "{page_path}"')

, https://himura.gitlab.io/covid19, .gitlab-ci.yml:


image: python
pages:
    stage: deploy
    only: [ master ]
    script:
        - python ./get_static_html.py
    artifacts:
      paths: [ public ]

Pipeline Schedules:



- :



тАФ :



?


, GitLab: https://gitlab.com/himura/covid19


, , 2 . , - MVP, , - . , , тАФ . known issues:


  • ( css grid )
  • ,

рдореБрдЭреЗ рдЙрдореНрдореАрдж рд╣реИ рдХрд┐ рд▓реЗрдЦ рджрд┐рд▓рдЪрд╕реНрдк рдФрд░ / рдпрд╛ рдЙрдкрдпреЛрдЧреА рдерд╛, рдФрд░ рдореБрдЭреЗ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдпрд╣ рднреА рдЙрдореНрдореАрдж рд╣реИ рдХрд┐ рдЬрд▓реНрдж рд╣реА рд╣рдо рд╕рднреА рджреЗрдЦреЗрдВрдЧреЗ рдХрд┐ рд░реЗрдЦрд╛рдВрдХрди рдХреА рд░реЗрдЦрд╛рдПрдВ рдХреИрд╕реЗ рдиреАрдЪреЗ рдЖрддреА рд╣реИрдВред
рд╕реНрд╡рд╕реНрде рд░рд╣реЗрдВ рдФрд░ рдЕрдкрдиреЗ рдХреЛрдб рдкрд░ рдирд┐рд░реНрднрд░рддрд╛ рди рдЬреЛрдбрд╝реЗрдВ рдЬреЛ рдЖрдк рдмрд┐рдирд╛ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ!


All Articles