@@ -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 )