• Как оптимизировать работу с файлами в Python?

    Или лучше в VBA погрузиться для решения подобных задач?

    VBA - однопоточный, расспаралелить не получится.

    но если только собрать названия листов, то странно большое время у Вас для такой задачи.
    Я тут на коленке набросал код на VBA, так он 200 файлов за 4 минуты обработал, и это без оптимизации кода (excel 32, win 10, 4ядра по 3ГГц).
    Можете запустить у себя, для этого открыть новую книгу, открыть редактор макросов, выбрать лист на котором будете работать и вставить следующий код (полной заменой)
    Код для сбора списка листов из всех книг директории
    Function FilenamesCollection(ByVal FolderPath As String, Optional ByVal Mask As String = "", _
                                 Optional ByVal SearchDeep As Long = 999) As Collection
        ' © EducatedFool  excelvba.ru/code/FilenamesCollection
        ' Получает в качестве параметра путь к папке FolderPath,
        ' маску имени искомых файлов Mask (будут отобраны только файлы с такой маской/расширением)
        ' и глубину поиска SearchDeep в подпапках (если SearchDeep=1, то подпапки не просматриваются).
        ' Возвращает коллекцию, содержащую полные пути найденных файлов
        ' (применяется рекурсивный вызов процедуры GetAllFileNamesUsingFSO)
    
        Set FilenamesCollection = New Collection    ' создаём пустую коллекцию
        Set FSO = CreateObject("Scripting.FileSystemObject")    ' создаём экземпляр FileSystemObject
        GetAllFileNamesUsingFSO FolderPath, Mask, FSO, FilenamesCollection, SearchDeep ' поиск
        Set FSO = Nothing     ' очистка строки состояния Excel
    End Function
     
    Function GetAllFileNamesUsingFSO(ByVal FolderPath As String, ByVal Mask As String, ByRef FSO, _
                                     ByRef FileNamesColl As Collection, ByVal SearchDeep As Long)
        ' перебирает все файлы и подпапки в папке FolderPath, используя объект FSO
        ' перебор папок осуществляется в том случае, если SearchDeep > 1
        ' добавляет пути найденных файлов в коллекцию FileNamesColl
        On Error Resume Next: Set curfold = FSO.GetFolder(FolderPath)
        If Not curfold Is Nothing Then    ' если удалось получить доступ к папке
    
            ' раскомментируйте эту строку для вывода пути к просматриваемой
            ' в текущий момент папке в строку состояния Excel
            ' Application.StatusBar = "Поиск в папке: " & FolderPath
    
            For Each fil In curfold.Files    ' перебираем все файлы в папке FolderPath
                If fil.Name Like "*" & Mask Then FileNamesColl.Add fil.Path
            Next
            SearchDeep = SearchDeep - 1    ' уменьшаем глубину поиска в подпапках
            If SearchDeep Then    ' если надо искать глубже
                For Each sfol In curfold.SubFolders    ' перебираем все подпапки в папке FolderPath
                    GetAllFileNamesUsingFSO sfol.Path, Mask, FSO, FileNamesColl, SearchDeep
                Next
            End If
            Set fil = Nothing: Set curfold = Nothing    ' очищаем переменные
        End If
    End Function
    
    Sub LoopThroughFiles(ByVal sDirName As String, ByRef lRow As Long, ByVal sMask As String)
       On Error Resume Next
       Dim folder$, coll As Collection
       Dim EX As Excel.Application
       Dim wkb As Workbook
       Dim wks As Worksheet
       Dim file As Variant
       Dim i As Long
       Dim v As Variant
       
     
        folder$ = sDirName
        If Dir(folder$, vbDirectory) = "" Then
            MsgBox "Не найдена папка «" & folder$ & "»", vbCritical
            Exit Sub        ' выход, если папка не найдена
        End If
     
        Set coll = FilenamesCollection(folder$, sMask)        ' получаем список файлов по маске из папки
        If coll.Count = 0 Then
    '        MsgBox "В папке «" & Split(folder$, "\")(UBound(Split(folder$, "\")) - 1) & "» нет ни одного подходящего файла!", _
                   vbCritical, "Файлы для обработки не найдены"
            Exit Sub        ' выход, если нет файлов
        End If
     
       Set EX = New Application
       EX.Visible = False
       
       ' перебираем все найденные файлы
       For Each file In coll
        
          Cells(lRow, 2) = CStr(file)
          
          Set wkb = EX.Workbooks.Open(Filename:=file)
    
          ' Если книга не пуста
          If wkb.Sheets.Count > 0 Then
             i = 1
             ReDim v(1 To wkb.Sheets.Count)
             ' Получаем названия листов
             For Each wks In wkb.Sheets
                v(i) = wks.Name
                i = i + 1
             Next wks
    
          End If
    
          Cells(lRow, 3) = Join(v, ",")
    
          wkb.Close False
                
          DoEvents
          
          lRow = lRow + 1
        
          DoEvents
        Next file
        
       Set wks = Nothing: Set wkb = Nothing: Set EX = Nothing
       Set colShts = Nothing
        
    End Sub
    
    Sub LoopThroughDirs()
       Dim lLastRow As Long
       Dim lRow As Long
       Dim i As Long
       Dim v As Variant
       Dim dTime As Double
    
       lRow = 2
       lLastRow = Cells(Rows.Count, 1).End(xlUp).Row
       
       v = Range(Cells(2, 1), Cells(lLastRow, 2))
       
       dTime = Time()
       For i = LBound(v) To UBound(v)
          Application.StatusBar = "Обрабатывается директория " & i & " из " & UBound(v)
          Call LoopThroughFiles(v(i, 1), lRow, "*.xls")
          Call LoopThroughFiles(v(i, 1), lRow, "*.xlsx")
          Call LoopThroughFiles(v(i, 1), lRow, "*.xlsm")
          DoEvents
       Next i
       MsgBox "Готово за " & CStr(CDate(Time() - dTime))
    End Sub


    для запуска в первой колонке заполнить директории которые он будет смотреть. Просматриваются вложенные директории до 999 грубины.

    Запустить процедуру LoopThroughDirs, для этого поставить курсор на название и нажать F5

    Результат
    5f05adc35867d361594006.png
    Ответ написан
    1 комментарий
  • Как оптимизировать работу с файлами в Python?

    SoreMix
    @SoreMix Куратор тега Python
    yellow
    1) можно ли распараллелить обработку файлов по директориям с помощью библиотеки multiprocessing ? Если можно помогите с примером кода - как это правильно сделать?


    Примерно так должно работать, если не напутал. Но нужно будет добавить какое нибудь дополнительное отслеживание прогресса. Например, записывать еще один файл с названиями excel файлов, из которых уже вытащили названия листов. Потому что pool разобьет, и по порядку делать не будет конечно же.
    from multiprocessing import Pool
    
    def get_all_files():
        files = []
        for dir in os.listdir('C:\\Users\Иван Данчук\Documents\Тест_shutil'):
            path = f'C:\\Users\Иван Данчук\Documents\Тест_shutil\{dir}'
            for file in os.listdir(path):
                files.append(os.path.join(path, file))
        return files
    
    def get_sheetnames(file_path):
        wb = load_workbook(file_path)
        with open('sheetnames.txt', 'a', encoding='utf-8') as f:
            f.write('\n'.join(wb.sheetnames[0:10])+'\n')
    
    files = get_all_files()
    with Pool(5) as p:
        p.map(get_sheetnames, files)


    2) можно ли этот код оптимизировать для обработки?

    Лучше не создавать новый воркбук, записывать в него данные после каждой операции. Либо сместите влево код, чтобы выполнился только один раз, а лучше всего записать в файл, как я делал выше. Все равно я так понял значение не имеет где эти данные лежат. Если нужно имя из каждой папки - тоже можно разбить либо на разные текстовики, либо сделать словарь, куда заносить имена листов.

    3) и стоит ли такие масштабные вещи с Excel'ьками проводить в Python? Или лучше в VBA погрузиться для решения подобных задач?

    Вообще, у вас очень много файлов. Время все равно придется потратить.
    Ответ написан
    1 комментарий
  • Как найти скачанные файлы?

    milssky
    @milssky
    Координатор племени фиолетовых обезьянок
    Что-нибудь типа такого. В open() можно указать куда и с какими именами будут сохранятся файлики.
    for elem in Acc_no_data:
        sleep(10)
        Acc_no = re.findall(r'\d+', elem.find('td', class_='small').text.replace('-',''))[3]
        # print(Acc_no)
        date = elem.find_all('td')[3].text
        get_file = requests.get(f'https://www.sec.gov/Archives/edgar/data/{CIK}/{Acc_no}/Financial_Report.xlsx', headers=user_agent)
        if get_file.status_code == 200:
            with open(f'{CIK}_{Acc_no}.xlsx', 'wb') as f:
                f.write(get_file.content)
    Ответ написан
    Комментировать
  • Как найти скачанные файлы?

    SoreMix
    @SoreMix Куратор тега Python
    yellow
    Это немного не так работает. Делаете запрос на нужный URL, вы получаете информацию в байтах. Дальше просто нужно открыть запись в файл, выбрав режим WB (Write-Bytes), и просто записать полученную по ссылке информацию, которая доступна в r.content

    import requests
    
    url = 'https://www.sec.gov/Archives/edgar/data/1090872/000104746909010861/Financial_Report.xls'
    r = requests.get(url)
    
    with open('report.xls', 'wb') as f:
        f.write(r.content)
    Ответ написан
    Комментировать