Как сохранить структуру таблицы, когда она читается из PDF и сохраняется в кадре данных? - PullRequest
0 голосов
/ 04 января 2019

Я использовал read_pdf из tabula, чтобы прочитать таблицу, представленную в PDF, указав параметры области. Я хочу сохранить структуру таблицы как есть (включая строки между столбцами и строками (если применимо)). Я читал, что matplotlib можно использовать, но когда я пытаюсь поместить таблицу чтения в CSV, структура таблицы исчезает, и между строками столбца остаются только пробелы. Мой код -

from tabula import read_pdf
import csv
path = "---"
df = read_pdf(path, stream=True , encoding="utf-8", guess = False, nospreadsheet = True, area = (112.37, 35.34, 153.36, 212.43))
print(df)
df.to_csv("path to destination csv file")

import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.xaxis.set_visible(False) 
ax.yaxis.set_visible(False)

ax.table(cellText=df.values, colLabels=df.columns, loc='center')
fig.tight_layout()
plt.show()

Когда я просматриваю содержимое целевого CSV-файла, строки между столбцами не сохраняются. Например, в приведенном ниже файле PDF я хочу прочитать данные из таблицы и поместить их в файл csv, сохранив строки между столбцами, тогда как мой код не сохраняет строки.

[1]

тогда как я хочу, чтобы мой код создавал CSV-файл, который раздваивает или рисует линии между столбцами, как это-

required table in csv

PDF-файл включен в пример Мой оригинальный PDF отображает следующий вывод, когда я использовал matplotlib. enter image description here, тогда как я хочу, чтобы это выглядело так-> (только часть внутри черных линий с раздвоением) enter image description here

Ответы [ 2 ]

0 голосов
/ 04 января 2019

Отдельный ответ - этот код форматирует «четко определенный» CSV

tata,ta,for,kattatom
1234,45,79,45
1234,45,79,45

в «utf8-art»:

┌────┬──┬───┬────────┐
│tata│ta│for│kattatom│
├────┼──┼───┼────────┤
│1234│45│79 │45      │
├────┼──┼───┼────────┤
│1234│45│79 │45      │
└────┴──┴───┴────────┘

UTF8-art добавляется кфайл output.txt.


import csv 

def create_table(file_name):
    """Takes a file_name to a csv. Produces utf8-art of the data. 
    Missing columns will be assumed to miss at end and replaced 
    by empty columns."""
    # mostly untested code - works for the 2 examples mentioned here
    with open(file_name,"r") as f:
        reader = csv.reader(f) 
        w = get_widths(reader)
        row_count = w["last"] 
        del w["last"]
        f.seek(0)
        return create_table_string(reader, w, row_count)

def get_widths(csv_reader):
    widths = {}
    row_count = 0
    for row in csv_reader:
        if row: # ignore empties
            row_count += 1
            for idx,data in enumerate(row):
                widths[idx] = max(widths.get(idx,0),len(data))

    widths["last"] = row_count
    return widths

# supply other set of lines if you like
deco = {k:v for k,v in zip("hv012345678","─│┌┬┐├┼┤└┴┘")} 


def base_row(widths, row, max_key, _v, _h, _l, _m, _r):
    decoration = []
    text_data = []

    decoration.append(_l + _h*widths[0])
    for i in range(1,max_key):
        decoration.append(_m + _h*widths[i])
    decoration.append(_m + _h*widths[max_key] + _r)

    if row:
        for i,data in enumerate(row): 
            text_data.append(_v + "{:<{}}".format(data, widths[i]))

        for empty in range(i+1,max_key+1):
            text_data.append(_v + " "*widths[empty])
        text_data[-1]+=_v

    return [decoration, text_data]

def get_first_row(widths,row):
    return base_row(widths, row, max(widths.keys()), deco["v"], deco["h"], 
                    deco["0"], deco["1"], deco["2"])

def get_middle_row(widths,row):
    return base_row(widths, row, max(widths.keys()),  deco["v"], deco["h"],
                    deco["3"], deco["4"], deco["5"])

def get_last_row(widths):
    decoration, _ = base_row(widths, [], max(widths.keys()), deco["v"], 
                             deco["h"], deco["6"], deco["7"], deco["8"])

    return [decoration]


def create_table_string(reader, widths, row_count): 
    output = []
    r = 0 
    for row in reader:
        if row:
            r += 1
            if r==1:
                output.extend(get_first_row(widths, row))
            else:
                output.extend(get_middle_row(widths, row))

    output.extend( get_last_row(widths))
    return output

Использование:

#create sample csv
with open("data.csv","w") as f:
    f.write("""tata,ta,for,kattatom
1234,45,79,45
1234,45,79,45""")

# open outputfile for append
with open("output.txt", "a", encoding="UTF8") as output:
    output.write("\n" + "-" * 40 + "\n\n")

    # get utf8 art
    for line in create_table("data.csv"):
        output.write(''.join(line)+"\n")

Ввод csv:

tata,ta,for,kattatom
1234,45,79,45
1234,45,79,45

затем:

tata,ta,for,kattatom
1234,45,79,45,8,0
1234,45,79,45

Вывод:

┌────┬──┬───┬────────┐
│tata│ta│for│kattatom│
├────┼──┼───┼────────┤
│1234│45│79 │45      │
├────┼──┼───┼────────┤
│1234│45│79 │45      │
└────┴──┴───┴────────┘

----------------------------------------

┌────┬──┬───┬────────┬─┬─┐
│tata│ta│for│kattatom│ │ │
├────┼──┼───┼────────┼─┼─┤
│1234│45│79 │45      │8│0│
├────┼──┼───┼────────┼─┼─┤
│1234│45│79 │45      │ │ │
└────┴──┴───┴────────┴─┴─┘
0 голосов
/ 04 января 2019

Формат csv ( c [характер / omma] s разделенные v значения) являются значениями, разделенными (одним и тем же) символом-разделителем.csv основано на тексте - в нем нет «строк».

Существуют символы Юникода, которые можно использовать для "формирования линий":

    U+2500    ─   e2 94 80    &#9472; ─   BOX DRAWINGS LIGHT HORIZONTAL
    U+2501    ━   e2 94 81    &#9473; ━   BOX DRAWINGS HEAVY HORIZONTAL
    U+2502    │   e2 94 82    &#9474; │   BOX DRAWINGS LIGHT VERTICAL
    U+2503    ┃   e2 94 83    &#9475; ┃   BOX DRAWINGS HEAVY VERTICAL
... snipp ...
    U+250C    ┌   e2 94 8c    &#9484; ┌   BOX DRAWINGS LIGHT DOWN AND RIGHT
    U+250D    ┍   e2 94 8d    &#9485; ┍   BOX DRAWINGS DOWN LIGHT AND RIGHT HEAVY
    U+250E    ┎   e2 94 8e    &#9486; ┎   BOX DRAWINGS DOWN HEAVY AND RIGHT LIGHT
... snipp ...
    U+2533    ┳   e2 94 b3    &#9523; ┳   BOX DRAWINGS HEAVY DOWN AND HORIZONTAL
    U+2534    ┴   e2 94 b4    &#9524; ┴   BOX DRAWINGS LIGHT UP AND HORIZONTAL
    U+2535    ┵   e2 94 b5    &#9525; ┵   BOX DRAWINGS LEFT HEAVY AND RIGHT UP LIGHT
... snipp ...
    U+2548    ╈   e2 95 88    &#9544; ╈   BOX DRAWINGS UP LIGHT AND DOWN HORIZONTAL HEAVY
    U+2549    ╉   e2 95 89    &#9545; ╉   BOX DRAWINGS RIGHT LIGHT AND LEFT VERTICAL HEAVY
    U+254A    ╊   e2 95 8a    &#9546; ╊   BOX DRAWINGS LEFT LIGHT AND RIGHT VERTICAL HEAVY
    U+254B    ╋   e2 95 8b    &#9547; ╋   BOX DRAWINGS HEAVY VERTICAL AND HORIZONTAL

источник

Но выпришлось бы «набирать» каждый фрагмент строки самостоятельно, чтобы имитировать таблицу в юникоде:

┍━━━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━┳━━━━━━━━┓
┃   tata         ┃   ta    ┃    fo   ┃  ka     ┃
┝━━━━━━━━━━━━━━━╈━━━━━━━━╈━━━━━━━━╈━━━━━━━━┧
┃   1234         ┃   45    ┃   79    ┃  45     ┃
┝━━━━━━━━━━━━━━━╈━━━━━━━━╈━━━━━━━━╈━━━━━━━━┧
┃   1234         ┃   45    ┃   79    ┃  45     ┃
┕━━━━━━━━━━━━━━━┻━━━━━━━━┻━━━━━━━━┻━━━━━━━━┛

Однако это не CSV - это больше похоже на удобочитаемое человеком ascii-art .Соответствующий csv будет выглядеть следующим образом:

tata,ta,fo,ka
1234,45,79,45
1234,45,79,45

(при использовании , в качестве символа seperator - замените его на символ, который вам больше нравится: [" ","|",";",\t])


Отказ от ответственности:

Я преднамеренно плохо разбираюсь в ascii-art и решаю не соответствовать точно соответствующим линиям Юникода (LIGHT, HEAVY), чтобы донести свою мысль.Это специально - называй меня ленивым.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...