Извлечение имён файлов с 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 шт):

Автор решения: Vitalizzare ушел в монастырь

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})
→ Ссылка