Skip to content

Instantly share code, notes, and snippets.

@Andreev-A
Forked from szuev/wikistat.py
Created February 7, 2022 20:55
Show Gist options
  • Select an option

  • Save Andreev-A/f74007d7ee639f96447d4f0ac92cdfa0 to your computer and use it in GitHub Desktop.

Select an option

Save Andreev-A/f74007d7ee639f96447d4f0ac92cdfa0 to your computer and use it in GitHub Desktop.

Revisions

  1. @szuev szuev created this gist Jun 13, 2019.
    103 changes: 103 additions & 0 deletions wikistat.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,103 @@
    from bs4 import BeautifulSoup
    import re
    import os


    # Вспомогательная функция, её наличие не обязательно и не будет проверяться
    def build_tree(start, end, path):
    link_re = re.compile(r"(?<=/wiki/)[\w()]+") # Искать ссылки можно как угодно, не обязательно через re
    files = dict.fromkeys(os.listdir(path)) # Словарь вида {"filename1": None, "filename2": None, ...}
    # TODO Проставить всем ключам в files правильного родителя в значение, начиная от start
    link_list = [start]
    while link_list:
    for id, link in enumerate(link_list):
    with open("{}{}".format(path, link), encoding='utf-8') as data:
    file_links = link_re.findall(data.read())
    for lnk in [i for i in file_links if i in files.keys()]:
    if files.get(lnk) is None:
    files[lnk] = link
    if lnk == end:
    return files
    link_list.append(lnk)
    link_list.pop(id)
    return files


    # Вспомогательная функция, её наличие не обязательно и не будет проверяться
    def build_bridge(start, end, path):
    files = build_tree(start, end, path)
    # TODO Добавить нужные страницы в bridge
    parent = end
    bridge = [parent]
    while parent != start:
    parent = files[parent]
    if parent is not None:
    bridge.append(parent)
    else:
    bridge.append(start)
    parent = start
    return bridge[::-1]


    def parse(start, end, path):
    """
    Если не получается найти список страниц bridge, через ссылки на которых можно добраться от start до end, то,
    по крайней мере, известны сами start и end, и можно распарсить хотя бы их: bridge = [end, start]. Оценка за тест,
    в этом случае, будет сильно снижена, но на минимальный проходной балл наберется, и тест будет пройден.
    Чтобы получить максимальный балл, придется искать все страницы. Удачи!
    """

    bridge = build_bridge(start, end, path) # Искать список страниц можно как угодно, даже так: bridge = [end, start]
    # Когда есть список страниц, из них нужно вытащить данные и вернуть их
    out = {}
    for file in bridge:
    with open("{}{}".format(path, file), encoding='utf-8') as data:
    soup = BeautifulSoup(data, "lxml")

    body = soup.find(id="bodyContent")

    # TODO посчитать реальные значения
    # imgs = 5 # Количество картинок (img) с шириной (width) не меньше 200
    imgs = len((body.find_all('img', width=lambda x: int(x or 0) > 199)))

    # headers = 10 # Количество заголовков, первая буква текста внутри которого: E, T или C
    headers = len([i.text for i in body.find_all(name=re.compile(r'[hH1-6]{2}')) if i.text[0] in 'ETC'])

    # linkslen = 15 # Длина максимальной последовательности ссылок, между которыми нет других тегов
    linkslen = 0
    link_found = body.find_next('a')
    while link_found:
    local_linklen = 1
    for i in link_found.find_next_siblings():
    if i.name == 'a':
    local_linklen += 1
    else:
    break
    linkslen = max(linkslen, local_linklen)
    link_found = link_found.find_next('a')

    # lists = 20 # Количество списков, не вложенных в другие списки
    lists = 0
    html_lists = body.find_all(['ul', 'ol'])
    for html_list in html_lists:
    if not html_list.find_parents(['ul', 'ol']):
    lists += 1

    out[file] = [imgs, headers, linkslen, lists]

    return out


    if __name__ == '__main__':
    correct = {
    'Stone_Age': [13, 10, 12, 40],
    'Brain': [19, 5, 25, 11],
    'Artificial_intelligence': [8, 19, 13, 198],
    'Python_(programming_language)': [2, 5, 17, 41],
    }
    start = 'Stone_Age'
    end = 'Python_(programming_language)'
    path = './wiki/'

    print('parse result:', parse(start, end, path))
    print('correct result', correct)