7.16. Case Study HTML Kangur

7.16.1. Case Study

"""
https://www.kangur-krakow.pl/viewpage.php?page_id=664
top 10 najlepszych szkół
wyszukiwanie ucznia po nazwisku
znalezienie najlepszej szkoły po kategorii wiekowej

>>> _get_nextid(674)
675
>>> _get_nextid(675)
678
>>> _get_nextid(676)
677
>>> _get_nextid(677)
679
>>> _get_nextid(679)
680
>>> _get_nextid(680)
681
>>> _get_nextid(681)
682
>>> _get_nextid(682)
683
>>> _get_nextid(683)
684
>>> _get_nextid(684)
685
>>> _get_nextid(685)
686
>>> _get_nextid(686)
687
>>> _get_nextid(687)
688
"""

# %%

import re
import pandas as pd
import requests
from pathlib import Path

# %%

DATA = Path('/tmp/pybook-pandas/')
DATA.mkdir(exist_ok=True)

LAUREAT = 'https://www.kangur-krakow.pl/viewpage.php?page_id=671'
WYNIKI = 'https://www.kangur-krakow.pl/viewpage.php?page_id=673'
WYROZNIENIA_INDEX = 'https://www.kangur-krakow.pl/viewpage.php?page_id=674'

# %%

def _get_nextid(page_id,
                baseurl='https://www.kangur-krakow.pl/viewpage.php?page_id=',
                encoding='iso-8859-2'):
    response = requests.get(baseurl + str(page_id))
    response.encoding = encoding
    html = response.text
    pattern = r'<a href="/viewpage.php\?page_id=(\d+)">zobacz kolejne wyniki</a>'
    match = re.search(pattern, html)
    if match is None:
        pattern = r'<a href="/viewpage.php\?page_id=(\d+)">idź na koniec</a>'
        match = re.search(pattern, html)
    if match:
        return int(match.group(1))


def get_wyroznienia(start_pageid=674,
            baseurl='https://www.kangur-krakow.pl/viewpage.php?page_id=',
            encoding='iso-8859-2'):
    def get(page_id):
        url = baseurl + str(page_id)
        return pd.read_html(url, encoding=encoding, header=0)[0]
    result = []
    nextid = start_pageid
    result.append(get(nextid))
    while nextid := _get_nextid(nextid):
        result.append(get(nextid))
    return pd.concat(result)

# %%

laureat = (
    pd
    .read_html(LAUREAT, encoding='iso-8859-2', header=1)[0]
    .drop(columns=['LP'])
    .rename(columns={
        'LP': 'miejsce',
        'KOD SZKOLY': 'szkola',
        'KATEGORIA': 'kategoria',
        'IMIĘ': 'imie',
        'NAZWISKO': 'nazwisko',
        'WYNIK': 'wynik'
    })
    .assign(imie=lambda df: df['imie'].str.capitalize())
    .assign(nazwisko=lambda df: df['nazwisko'].str.capitalize())
)

wyniki = (
    pd
    .read_html(WYNIKI, encoding='iso-8859-2', header=0)[0]
    .drop(columns=['LP'])
    .rename(columns={
        'LP': 'miejsce',
        'KOD SZKOLY': 'szkola',
        'KATEGORIA': 'kategoria',
        'IMIĘ': 'imie',
        'NAZWISKO': 'nazwisko',
        'WYNIK': 'wynik'
    })
    .assign(imie=lambda df: df['imie'].str.capitalize())
    .assign(nazwisko=lambda df: df['nazwisko'].str.capitalize())
)

wyroznienia = (
    get_wyroznienia()
    .drop(columns=['LP'])
    .rename(columns={
        'LP': 'miejsce',
        'KOD SZKOLY': 'szkola',
        'KATEGORIA': 'kategoria',
        'IMIĘ': 'imie',
        'NAZWISKO': 'nazwisko',
        'WYNIK': 'wynik'
    })
    .assign(imie=lambda df: df['imie'].str.capitalize())
    .assign(nazwisko=lambda df: df['nazwisko'].str.capitalize())
)

wszystko = (
    pd
    .concat([laureat, wyniki, wyroznienia])
    .convert_dtypes()
)

# %%

laureat.to_csv(DATA/'laureat.csv', index=False)
wyniki.to_csv(DATA/'wyniki.csv', index=False)
wyroznienia.to_csv(DATA/'wyroznienia.csv', index=False)
wszystko.to_csv(DATA/'wszystko.csv', index=False)


# %% Zamiana nazwiska z imieniem (bład w danych)

najczesciej_wystepujace_nazwiska = (
    wyroznienia
    .groupby('nazwisko')['nazwisko']
    .value_counts()
    .sort_values(ascending=False)
    .head(50)
)

najczesciej_wystepujace_nazwiska.to_csv(DATA/'najczesciej_wystepujace_nazwiska.csv')

# na podstawie najczesciej_wystepujace_nazwiska
# ręcznie układasz słownik imion
IMIONA = [
    'Wojciech',
    'Adam',
    'Jakub',
    'Zofia',
]

podmienione = (wyroznienia
 .query('nazwisko in @IMIONA')
 .assign(
    noweimie=lambda df: df['nazwisko'],
    nazwisko=lambda df: df['imie'],
    imie=lambda df: df['noweimie'])
 .drop(columns='noweimie')
)

podmienione

# %%

top10_szkol = (
    wszystko
    .groupby('szkola')['szkola']
    .value_counts()
    .sort_values(ascending=False)
    .head(10)
)
# >>> top10_szkol
# szkola
# KKDD    41
# KKBE    36
# KKPY    36
# KKGT    31
# KKGF    28
# KKBW    27
# KKEU    27
# KTEJ    27
# KTCK    25
# KTBR    25
# Name: count, dtype: int64

top10_szkol.to_csv(DATA/'top10_szkol.csv')

# %%

def convert_pl_letters(name):
    PL_LETTERS = {'ą': 'a', 'ć': 'c', 'ę': 'e', 'ł': 'l', 'ń': 'n',
                  'ó': 'o', 'ś': 's', 'ż': 'z', 'ź': 'z', 'Ą': 'A',
                  'Ć': 'C', 'Ę': 'E', 'Ł': 'L', 'Ń': 'N', 'Ó': 'O',
                  'Ś': 'S', 'Ż': 'Z', 'Ź': 'Z'}
    return ''.join(PL_LETTERS.get(letter, letter) for letter in name)


def search(name):
    name = convert_pl_letters(name)
    szkola = wszystko.query('szkola.str.contains(@name, case=False)')
    kategoria = wszystko.query('kategoria.str.contains(@name, case=False)')
    imiona = wszystko.query('imie.str.contains(@name, case=False)')
    nazwiska = wszystko.query('nazwisko.str.contains(@name, case=False)')
    return pd.concat([szkola, kategoria, imiona, nazwiska], ignore_index=True)

# >>> search('Żurek')
#   szkola kategoria        imie  nazwisko       wynik
# 0   KTBN        1M      Kacper   Mazurek  wyróżniony
# 1   KKHJ        1M     Martyna   Mazurek  wyróżniony
# 2   KKGF        2B        Maja  Szczurek  wyróżniony
# 3   KKRS        1B   Stanislaw     Zurek  wyróżniony
# 4   KMAM        2B   Gabriella     Zurek  wyróżniony
# 5   KOBD        2M  Aleksander     Zurek  wyróżniony
# 6   KKOR        2M     Zuzanna     Zurek  wyróżniony
# 7   KPAR        ZA       Kamil     Zurek  wyróżniony

# %%

top3_szkoly_w_danej_kategorii = (
    wszystko
    .loc[:, ['kategoria', 'szkola']]
    .groupby('kategoria')
    .value_counts()
    .reset_index()
    .groupby('kategoria')
    .head(3)
    .reset_index(drop=True)
)

top3_szkoly_w_danej_kategorii
#    kategoria szkola  count
# 0         1B   KKGT     10
# 1         1B   KKGF      8
# 2         1B   KKBW      7
# 3         1J   KKDD     12
# 4         1J   KKKU     10
# 5         1J   KKIK      7
# 6         1K   KTEJ      9
# 7         1K   KKPY      6
# 8         1K   KKAA      5
# 9         1M   KKBE      9
# 10        1M   KKDZ      8
# 11        1M   KKFL      8
# 12        1S   KKFZ     10
# 13        1S   KTBR      9
# 14        1S   KKCZ      8
# 15        2B   KKGF      9
# 16        2B   KTEJ      7
# 17        2B   KKBW      5
# 18        2J   KKDD     11
# 19        2J   KKFZ      7
# 20        2J   KTBR      7
# 21        2K   KKAA      7
# 22        2K   KKCN      4
# 23        2K   KEAL      3
# 24        2M   KKEU      9
# 25        2M   KKPY      9
# 26        2M   KKCF      8
# 27        2S   KKDD     14
# 28        2S   KKBA      6
# 29        2S   KTBR      5
# 30        ZA   KKSU     10
# 31        ZA   KKBE      9
# 32        ZA   KKBH      8

top3_szkoly_w_danej_kategorii.to_csv(DATA/'top3_szkoly_w_danej_kategorii.csv', index=False)