Поиск по блогу

воскресенье, 19 января 2014 г.

Постановка задачи "обработка файлов в папках

Пока я твердо знаю, только то, что при парсинге интернет у меня в компьютере будет собираться уйма "сырых" файлов, из которых я буду компоновать новые файлы-таблицы... Через 3-5 месяцев мне будет трудно вспомнить, что и зачем я делал, где и что лежит... Как не забивать свой винчестер таким мусором? Как разложить все по полочкам?
Я уже знаю, что есть интересные возможности для работы со специальными базами данных... Но для начала разберемся с текстовыми файлами.
Сейчас у меня довольно смутное представление не только о том, как организовать работу с файлами, но и о конкретных командах (функциях, модулях) языка Питон. Наверняка, есть несколько вариантов... Потому будем одновременно рассматривать две "разных" темы: постановка задачи, модули Питон..., и не стоит отказываться от попыток найти пользователскую библиотеку для организации хранилища текстовых файлов.

Постановка задачи: файлы CSV, первое приближение

В данный момент мне нравится вот такая схема работы с файлами:
0. В отдельные подпаки проекта скачиваем исходные файлы CSV с одинаковыми таблицами (число и порядок столбцов совпадают)
00. Таким образом, исходные данные могут хранится в дереве папок.
...
1. Задаем папку и в ней (и в подпапках) находим все файлы, удовлетворяющие нескольким параметрам-условиям.
2. Параметры файла мы кодируем в его имени (имя - это строка_с_разделителями), условие поиска - маска строки.
3. Формируем список имен файлов для обработки и предаем его модулям - конвертерам (обработчикам), результаты записываем в другие папки.
4. Важную роль играют соглашения об именах папок и форматах таблиц данных (их лучше записывать в манифесты)

Модули: Перебираем файлы в папке

Сначала найдем несколько примеров: Directory listing in Python Calling an external command in Python - не смог пропустить, здесь много примеров How to list all files of a directory in Python ... этот последний и возьмем за основу
Здесь рассматриваются варианты os.listdir(), glob, dircache, path... в зависимости от того, выбрать файлы из одной директории или поддерева директорий, отделить файлы от папок...
Пока будем считать, что все нашаи файлы только в одной папке, все файлы однотипные (например, однотипные CSV таблицы ...две первые строки пустые, далее - строка заголовка, столбцы одинаковые везде...)
In []:
# I have to know, where am I ... I have to decide absolute or relative filepath I am going to use...
In [4]:
from os import listdir
from os.path import isfile, join
mypath='C:\\Users\\kiss\\Documents\\IPython Notebooks\\web\\raw_to_csv'
onlyfiles = [ f for f in listdir(mypath) if isfile(join(mypath,f)) ]
In [5]:
onlyfiles
Out[5]:
['cr_1.ipynb', 'cr_folder.ipynb']

Модули: Пока есть сомнения насчет конструкции " ...if isfile(join(mypath,f) ...", надо буде разобраться... Пока просто посмотрим на эти функции:

In [10]:
help(listdir)
Help on built-in function listdir in module nt:

listdir(...)
    listdir(path) -> list_of_strings
    
    Return a list containing the names of the entries in the directory.
    
        path: path of directory to list
    
    The list is in arbitrary order.  It does not include the special
    entries '.' and '..' even if they are present in the directory.


In [11]:
help(isfile)
Help on function isfile in module genericpath:

isfile(path)
    Test whether a path is a regular file


In [12]:
help(join)
Help on function join in module ntpath:

join(a, *p)
    Join two or more pathname components, inserting "\" as needed.
    If any component is an absolute path, all previous path components
    will be discarded.


Откуда берутся эти "новые" модули..., например, ntpath ??? Они, либо из системных библиотек, либо вызываются в OS (мы импоритровали из этого модуля) и наследуются там... Посмотрим:
In [15]:
os.path??
In []:
#..... Да из os.path вызывается изрфдное количесвто модулей
import os
import sys
import stat
import genericpath
import warnings

from genericpath import *
.....
Ниже в этом посте я еще раз импортирую os ... Делать этого не надо было, я просто тупо скопировал код из чужого примера...

Возвращаемся к постановке задачи

Итак, мы получили список файлов в директории, теперь мы можем организовать итерации по этому списку, чтобы сделать что-нибудь с каждым файлом), а потом записать новый файл в новую (соседнюю?) папку.
По умолчанию рабочая директория там, откуда мы запустили ipython..., или ее можно настроить..., или задать программно базовый путь... и к нему приклеивать относительные... Пока не знаю, как лучше..., потому договоримся, что, дабы не путаться... каждый раз будем запускать Питон из папки проектов. Получается, что еще проще задавать базовый (абсолютный путь), как в grab...
Вот примеры кода определеним абсолютного и относительного пути How to get an absolute file path in Python
In [7]:
# Сначала найдем текущую рабочую папку, чтобы выбрать имя реального файла (см. ячейку ниже)
!chcp 65001
!dir
Active code page: 65001
 Volume in drive C has no label.
 Volume Serial Number is 6017-2A0B

 Directory of C:\Users\kiss\Documents\IPython Notebooks\web\oboobs

18.01.2014  19:35    <DIR>          .
18.01.2014  19:35    <DIR>          ..
18.01.2014  21:38    <DIR>          .ipynb_checkpoints
13.01.2014  15:17             1В 248 Anaconda Command Prompt.lnk
10.01.2014  14:00           151В 258 c2_27.ipynb
10.01.2014  19:52            16В 865 c2_27_2.ipynb
14.01.2014  16:21            26В 268 c2_30.ipynb
16.01.2014  14:33            35В 957 c2_30_self.ipynb
15.01.2014  20:56            25В 808 c2_36_utf.ipynb
16.01.2014  17:28            26В 121 c2_3_1.ipynb
09.01.2014  00:16             5В 347 c2_blogging.ipynb
10.01.2014  15:52            58В 528 c2_class.ipynb
11.01.2014  14:20            50В 260 c2_dinamyc_type.ipynb
09.01.2014  00:28           139В 989 c2_help_doc.ipynb
11.01.2014  00:10            82В 503 c2_modules.ipynb
16.01.2014  15:59            24В 308 c2_nbconvert_err1.ipynb
13.01.2014  13:39           130В 825 c2_string.ipynb
10.01.2014  18:10           141В 575 C2_visibility.ipynb
05.01.2014  18:36             1В 151 C3_PyCon US 2013_video.ipynb
10.01.2014  14:39            16В 473 Classes_1.ipynb
18.01.2014  19:28            15В 683 cr_1.ipynb
18.01.2014  21:52             8В 838 cr_folder.ipynb
30.12.2013  13:24            36В 697 CSV-donload-urlparse-CSV .ipynb
27.12.2013  08:13                 0 debug.log
03.01.2014  14:49            15В 764 debugger.ipynb
17.01.2014  21:56            39В 760 err_ipyth_cmd.ipynb
20.12.2013  19:18            14В 879 Grab_Spider_asinhron-Copy0.ipynb
19.12.2013  21:53            46В 655 Grab_Spider_asinhron19_12_2013.ipynb
02.01.2014  16:07           110В 988 Hacks_simple_blogger.ipynb
03.01.2014  12:47            26В 973 markdown.ipynb
01.01.2014  12:45           265В 273 Nissan_and_other_1.html
29.12.2013  20:57            67В 217 Nissan_and_other_1.ipynb
30.12.2013  13:57                34 result_1.txt
16.01.2014  16:26                 0 result_2.txt
17.12.2013  15:40                 0 spider.py
20.12.2013  18:59            33В 223 spider_1-Copy19_12_2013-XpathSelector.ipynb
24.12.2013  23:14            11В 562 spider_1-Copy19_12_2013.ipynb
24.12.2013  15:40             3В 815 spider_1.py
24.12.2013  22:01             3В 815 spider_2.py
31.12.2013  14:22             5В 391 write_file_csv.ipynb
16.01.2014  15:15            32В 739 СЃ2_28_1.ipynb
20.12.2013  19:49            17 975 Способы создания заданий.ipynb
              39 File(s)      1В 691В 765 bytes
               3 Dir(s)  410В 834В 513В 920 bytes free

Можно получить абсолютный путь... из относительного http://stackoverflow.com/questions/51520/how-to-get-an-absolute-file-path-in-python/51523#51523
In [9]:
import os
os.path.abspath("c2_27.ipynb") # Файл из рабочей папки
Out[9]:
'C:\\Users\\kiss\\Documents\\IPython Notebooks\\web\\oboobs\\c2_27.ipynb'
Пока не ясно, сколько однотипных проектов будет в одной папке. Может быть очень много, поскольку безопаснее "забирать файлы" небольшими порциями, дабы не забанили, как робота...
In []:
----Projects
       !----Project auto
                  !----Nissan
                  !----Ford
                         !----2008
                                !----jan
                                      !----man < 18
                                      !----
                                      !----
После того, как я нарисовал эту схему, стало ясно, что надо организовывать сквозной поиск в папке и подпапках по шаблону (имени файла). http://stackoverflow.com/questions/120656/directory-listing-in-python/120701#120701
In [18]:
#import os
dirnames =['C:\\Users\\kiss\\Documents\\IPython Notebooks\\web\\raw_to_csv\\fold_in']
for dirname, dirnames, filenames in os.walk('.'):
    # print path to all subdirectories first.
    for subdirname in dirnames:
        print os.path.join(dirname, subdirname)

    # print path to all filenames.
    for filename in filenames:
        print os.path.join(dirname, filename)

    # Advanced usage:
    # editing the 'dirnames' list will stop os.walk() from recursing into there.
    if '.git' in dirnames:
        # don't go into any .git directories.
        dirnames.remove('.git')
.\.ipynb_checkpoints
.\Anaconda Command Prompt.lnk
.\c2_27.ipynb
.\c2_27_2.ipynb
.\c2_30.ipynb
.\c2_30_self.ipynb
.\c2_36_utf.ipynb
.\c2_3_1.ipynb
.\c2_blogging.ipynb
.\c2_class.ipynb
.\c2_dinamyc_type.ipynb
.\c2_help_doc.ipynb
.\c2_modules.ipynb
.\c2_nbconvert_err1.ipynb
.\c2_string.ipynb
.\C2_visibility.ipynb
.\C3_PyCon US 2013_video.ipynb
.\Classes_1.ipynb
.\cr_1.ipynb
.\cr_folder.ipynb
.\CSV-donload-urlparse-CSV .ipynb
.\debug.log
.\debugger.ipynb
.\err_ipyth_cmd.ipynb
.\Grab_Spider_asinhron-Copy0.ipynb
.\Grab_Spider_asinhron19_12_2013.ipynb
.\Hacks_simple_blogger.ipynb
.\markdown.ipynb
.\Nissan_and_other_1.html
.\Nissan_and_other_1.ipynb
.\result_1.txt
.\result_2.txt
.\spider.py
.\spider_1-Copy19_12_2013-XpathSelector.ipynb
.\spider_1-Copy19_12_2013.ipynb
.\spider_1.py
.\spider_2.py
.\write_file_csv.ipynb
.\�2_28_1.ipynb
.\������� �������� �������.ipynb
.\.ipynb_checkpoints\c2_27-checkpoint.ipynb
.\.ipynb_checkpoints\c2_27_2-checkpoint.ipynb
.\.ipynb_checkpoints\c2_30-checkpoint.ipynb
.\.ipynb_checkpoints\c2_30_self-checkpoint.ipynb
.\.ipynb_checkpoints\c2_36_utf-checkpoint.ipynb
.\.ipynb_checkpoints\c2_3_1-checkpoint.ipynb
.\.ipynb_checkpoints\c2_blogging-checkpoint.ipynb
.\.ipynb_checkpoints\c2_class-checkpoint.ipynb
.\.ipynb_checkpoints\c2_dinamyc_type-checkpoint.ipynb
.\.ipynb_checkpoints\c2_help_doc-checkpoint.ipynb
.\.ipynb_checkpoints\c2_modules-checkpoint.ipynb
.\.ipynb_checkpoints\c2_nbconvert_err1-checkpoint.ipynb
.\.ipynb_checkpoints\c2_string-checkpoint.ipynb
.\.ipynb_checkpoints\C2_visibility-checkpoint.ipynb
.\.ipynb_checkpoints\Classes_1-checkpoint.ipynb
.\.ipynb_checkpoints\cr_1-checkpoint.ipynb
.\.ipynb_checkpoints\cr_folder-checkpoint.ipynb
.\.ipynb_checkpoints\CSV-donload-urlparse-CSV -checkpoint.ipynb
.\.ipynb_checkpoints\debugger-checkpoint.ipynb
.\.ipynb_checkpoints\err_ipyth_cmd-checkpoint.ipynb
.\.ipynb_checkpoints\Hacks_simple_blogger-checkpoint.ipynb
.\.ipynb_checkpoints\markdown-checkpoint.ipynb
.\.ipynb_checkpoints\Nissan_and_other_1-checkpoint.ipynb
.\.ipynb_checkpoints\write_file_csv-checkpoint.ipynb
.\.ipynb_checkpoints\�2_28_1-checkpoint.ipynb

Не понял, почему этот код гуляет (walk) по материнским папкам в дереве. Надо будет почитать...
Вот пример, который, вроде бы, именно то, что надо http://stackoverflow.com/questions/3207219/how-to-list-all-files-of-a-directory-in-python
In [25]:
#import os

def get_filepaths(directory):
    """This function will generate the file names in a directory 
       tree by walking the tree either top-down or bottom-up. For each 
       directory in the tree rooted at directory top (including top itself), 
       it yields a 3-tuple (dirpath, dirnames, filenames).
    """
    file_paths = []  # List which will store all of the full filepaths.
    # Walk the tree.
    for root, directories, files in os.walk(directory):
        for filename in files:
            # Join the two strings in order to form the full filepath.
            filepath = os.path.join(root, filename)
            file_paths.append(filepath)  # Add it to the list.
    return file_paths  # Self-explanatory.

# Run the above function and store its results in a variable.   
full_file_paths = get_filepaths("C:\\Users\\kiss\\Documents\\IPython Notebooks\\web\\raw_to_csv")
In [26]:
full_file_paths
Out[26]:
['C:\\Users\\kiss\\Documents\\IPython Notebooks\\web\\raw_to_csv\\cr_1.ipynb',
 'C:\\Users\\kiss\\Documents\\IPython Notebooks\\web\\raw_to_csv\\cr_folder.ipynb',
 'C:\\Users\\kiss\\Documents\\IPython Notebooks\\web\\raw_to_csv\\fold_in\\222.txt']
The path I provided in the above function contained 3 files— two of them in the root directory, and another in a subfolder called "SUBFOLDER." You can now do things like:
print full_file_paths which will print the list:
['/Users/johnny/Desktop/TEST/file1.txt',
'/Users/johnny/Desktop/TEST/file2.txt',
'/Users/johnny/Desktop/TEST/SUBFOLDER/file3.dat']
If you'd like, you can open and read the contents, or focus only on files with the extension ".dat" like in the code below:
In [27]:
for f in full_file_paths:
    if f.endswith(".txt"):
        print f
C:\Users\kiss\Documents\IPython Notebooks\web\raw_to_csv\fold_in\222.txt

Итак, вариант наверху приемлемый, но не использует возможности маскирования..., хотя, может быть просто поискать? адо бы изучить подробнее матчасть.
А вот пример с другой библиотекой http://docs.python.org/2/library/glob.html
In [31]:
import glob
print glob.glob("C:\\Users\\kiss\\Documents\\IPython Notebooks\\web\\raw_to_csv\\*.txt")
# Пытаемся найти файл в подпапке:                                        fold_in\222.txt
#               C:\Users\kiss\Documents\IPython Notebooks\web\raw_to_csv\fold_in\222.txt
[]

Модули: вот первый вариант для сквозного формирования списка файлов

Another way to do it using just the glob module. Just seed the rglob method with a starting base directory and a pattern to match and it will return a list of matching file names. http://stackoverflow.com/questions/2186525/use-a-glob-to-find-files-recursively-in-python/2186565#2186565
In [32]:
import glob
import os

def _getDirs(base):
    return [x for x in glob.iglob(os.path.join( base, '*')) if os.path.isdir(x) ]

def rglob(base, pattern):
    list = []
    list.extend(glob.glob(os.path.join(base,pattern)))
    dirs = _getDirs(base)
    if len(dirs):
        for d in dirs:
            list.extend(rglob(os.path.join(base,d), pattern))
    return list
In [36]:
rglob('C:\\Users\\kiss\\Documents\\IPython Notebooks\\web\\raw_to_csv','*.ipynb') 
Out[36]:
['C:\\Users\\kiss\\Documents\\IPython Notebooks\\web\\raw_to_csv\\cr_1.ipynb',
 'C:\\Users\\kiss\\Documents\\IPython Notebooks\\web\\raw_to_csv\\cr_folder.ipynb',
 'C:\\Users\\kiss\\Documents\\IPython Notebooks\\web\\raw_to_csv\\fold_in\\cr_1.ipynb']
Для начала подойдет - сквозной поиск по маске осуществляется простым вызовом функции rglob (base, pattern)... И пути полные... а сам пример выше...
Вот документация http://docs.python.org/2/library/glob.html, где есть примеры использования:
The glob module finds all the pathnames matching a specified pattern according to the rules used by the Unix shell. No tilde expansion is done, but *, ?, and character ranges expressed with [] will be correctly matched.
For a literal match, wrap the meta-characters in brackets. For example, '[?]' matches the character '?'.
Очевидно, что знак '?' можно испоьзовать для того, чтобы маскировать выбор по параметрам имени файла.


Посты чуть ниже также могут вас заинтересовать

Комментариев нет:

Отправить комментарий