-
-
Save Andreev-A/f74007d7ee639f96447d4f0ac92cdfa0 to your computer and use it in GitHub Desktop.
Создание Web-сервисов на Python
Week 2
Практическое задание по Beautiful Soup
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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