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
  • Save Andreev-A/f74007d7ee639f96447d4f0ac92cdfa0 to your computer and use it in GitHub Desktop.
Save Andreev-A/f74007d7ee639f96447d4f0ac92cdfa0 to your computer and use it in GitHub Desktop.
Создание Web-сервисов на Python Week 2 Практическое задание по Beautiful Soup
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)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment