Извлечение имён файлов с html-страницы
Как извлечь имена файлов и директорий из html-страницы, посчитав количество по типам? Например: txt - 17 файлов, css - 2 файла, директорий - 5.
import requests
from bs4 import BeautifulSoup
response = requests.get('https://github.com/maverickNerd/wordlists/')
page = BeautifulSoup(response.text, 'html5lib')
page_files = page.find_all(class_='react-directory-row-name-cell-small-screen')
files_txt = []
for item in page_files:
print(item.text)
print(f"Total {len(item)} ")
Ответы (1 шт):
BeautifulSoup 4.12.2Selenium 4.34.0
Общего решения для произвольного сайта нет, поскольку для извлечения имен файлов и директорий нужно знать контекст. В случае с GitHub, в качестве такого контекста вы используете атрибут class для сужения поиска. Если отталкиваться от этого, то дальнейшая обработка page_files из вашего кода может выглядеть так:
from collections import Counter
answer = Counter(
'<directory>' if y.attrs['aria-label'].endswith('(Directory)')
else '<no extension>' if '.' not in y.text
else y.text.rsplit('.', maxsplit=1)[-1]
for y in (x.findChild('a') for x in page_files)
)
Здесь мы предполагаем, что выделенные вами участки содержат ссылки на файлы и папки с атрибутом aria-label, который для папок заканчивается на "(Directory)".
Альтернатива - смотреть на путь к файлу внутри репозитория по атрибуту href, где первая позиция - это имя пользователя, вторая - имя репозитория, а третья равна blob для файлов и tree для директорий:
# Пример ожидаемых ссылок:
# '/maverickNerd/wordlists/tree/master/technology' - директория technology в репозитории wordlists пользователя maverickNerd
# '/maverickNerd/wordlists/blob/master/README.md' - файл README.md там же
get_type = lambda x: ('<directory>' if x[3] == 'tree'
else '<no extension>' if '.' not in x[-1]
else x[-1].rsplit('.', maxsplit=1)[-1])
links = (x.findChild('a').attrs['href'].split('/')
for x in page_files)
answer = Counter(map(get_type, links))
Нужно принять во внимание, что при переходе во внутренние папки репозитория GitHub вернет HTML c JS-кодом, генерирующим итоговую страницу. Для его выполнения понадобится дополнительный инструмент, например Selenium, иначе поиск тегов по атрибуту class ничего не вернет:
from bs4 import BeautifulSoup, Tag
from collections import Counter
from selenium import webdriver
def get_page_source(path):
driver = webdriver.Chrome()
driver.get(path)
rendered_html = driver.page_source
driver.quit()
return rendered_html
def extract_links(html: str) -> list[Tag]:
page = BeautifulSoup(html, 'html5lib')
cells = page.find_all(class_='react-directory-row-name-cell-small-screen')
links = [x for x in (x.findChild('a') for x in cells) if x]
return links
def count_file_types(links: list[Tag]) -> dict[str, int]:
return Counter(
'<directory>' if x.attrs['aria-label'].endswith('(Directory)')
else '<no extension>' if '.' not in x.text
else x.text.rsplit('.', maxsplit=1)[-1]
for x in links
)
path = 'https://github.com/maverickNerd/wordlists/tree/master/Uploads'
file_types = count_file_types(extract_links(get_page_source(path)))
print(file_types)
# Результат для 'https://github.com/maverickNerd/wordlists/tree/master/Uploads'
Counter({'jpg': 42,
'txt': 16,
'<no extension>': 11,
'png': 11,
'csv': 8,
'gif': 7,
'php': 5,
'<directory>': 4,
'xml': 4,
'docx': 4,
'mvg': 4,
'zip': 3,
'svg': 3,
'rar': 2,
'cfg': 1,
'img': 1,
'torrent': 1,
'swf': 1,
'readme': 1,
'opml': 1})