Уведомления

Группа в Telegram: @pythonsu

#1 Окт. 21, 2015 17:07:56

i.z
Зарегистрирован: 2015-10-21
Сообщения: 9
Репутация: +  0  -
Профиль   Отправить e-mail  

Парсинг csv

Здравствуйте уважаемые участники форума, пытаюсь разобраться с парсингом csv файлов. У меня есть файл в котором представлено множество колонок, из него необходимо выбрать несколько (номера известны) с их параметрами. Cложность заключается в том, что каждую из колонок необходимо переименовать.
Посоветуйте пожалуйста рабочую модель, чтобы было от чего отталкиваться. Спасибо.

Офлайн

#2 Окт. 21, 2015 21:25:22

i.z
Зарегистрирован: 2015-10-21
Сообщения: 9
Репутация: +  0  -
Профиль   Отправить e-mail  

Парсинг csv

Поискал по форуму везде обсуждается парсинг XML, а мне нужно все с точностью наоборот. Необходимо произвести парсинг CSV с выгрузкой в XML. На просторах интернета я нашел прекрасный скрипт который работает несколько иначе, чем необходимо мне.
Спрашиваю в данной ветке, так как надеюсь, что мне помогут разобраться, дать некоторые комментарии.
Насколько я смог разобраться сам, данный скрипт меняет название колонок на тэги в xml, работая по диапазону. Хочется понять можно ли переделать этот код, чтобы искал только по выбранным полям и выгружал переименованные тэги в xml.

import csv
csvFile = 'myData.csv'
xmlFile = 'myData.xml'
csvData = csv.reader(open(csvFile))
xmlData = open(xmlFile, 'w')
xmlData.write('<?xml version="1.0"?>' + "\n")
# there must be only one top-level tag
xmlData.write('<csv_data>' + "\n")
rowNum = 0
for row in csvData:
    if rowNum == 0:
        tags = row
        # replace spaces w/ underscores in tag names
        for i in range(len(tags)):
            tags[i] = tags[i].replace(' ', '_')
    else: 
        xmlData.write('<row>' + "\n")
        for i in range(len(tags)):
            xmlData.write('    ' + '<' + tags[i] + '>' \
                          + row[i] + '</' + tags[i] + '>' + "\n")
        xmlData.write('</row>' + "\n")
            
    rowNum +=1
xmlData.write('</csv_data>' + "\n")
xmlData.close()

Спасибо.

Офлайн

#3 Окт. 22, 2015 01:33:57

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 10016
Репутация: +  857  -
Профиль   Отправить e-mail  

Парсинг csv

Приведи пример входного файла и выходного файла, который должен из него получиться.



Офлайн

#4 Окт. 22, 2015 10:10:15

i.z
Зарегистрирован: 2015-10-21
Сообщения: 9
Репутация: +  0  -
Профиль   Отправить e-mail  

Парсинг csv

Входной файл содержит структуру:

nazvanie-oblast-opisanie-total
ob'ekt1-15-Opisanie-20

На выходе должен получится xml:

<row>
<title>ob'ekt1</title>
<area>15</area>
<description>Opisanie</opisanie>
<total>20</total>
</row>

Где колонка “nazvanie” приобретает тэг <title>
Колонка “oblast” приобретает тэг <area>
Колонка “opisanie” приобретает тэг <description>
А “total” остается неизменной.

С переименованием я кстати разобрался. Не знаю насколько это корректно с точки зрения профессионалов, но у меня получилось несколько строк:

tags[i] = tags[i].replace(' ', '_')

Где я поступил следующим образом:
tags[i] = tags[i].replace('nazvanie', 'title')
tags[i] = tags[i].replace('oblast', 'area')
tags[i] = tags[i].replace('opisanie', 'description')

Замена происходит, а это самое главное. Теперь ищу ответ на вопрос “Как вывести в xml только те строки, которые мне необходимы”, так как по нынешнему состоянию скрипта он хоть и заменяет все как нужно, но проходится по всем полям, и все поля так или иначе добавляет в область <row> </row>.

Офлайн

#5 Окт. 22, 2015 11:03:43

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 10016
Репутация: +  857  -
Профиль   Отправить e-mail  

Парсинг csv

Напиши входную строку со всеми полями и выходной xml с выбранными из неё полями.

i.z
Входной файл содержит структуру:
Это не входной файл, а просто выбранные поля из входного файла. А входной файл так и остался неизвестным.
Предлагаешь нам догадаться, какой у тебя там входной файл.

i.z
Теперь ищу ответ на вопрос “Как вывести в xml только те строки, которые мне необходимы”
Вот, теперь ты поля строками называешь.

i.z
Не знаю насколько это корректно с точки зрения профессионалов
.replace() там вообще нигде не должно быть.



Отредактировано py.user.next (Окт. 22, 2015 11:10:03)

Офлайн

#6 Окт. 22, 2015 13:17:49

i.z
Зарегистрирован: 2015-10-21
Сообщения: 9
Репутация: +  0  -
Профиль   Отправить e-mail  

Парсинг csv

py.user.next
Это не входной файл, а просто выбранные поля из входного файла. А входной файл так и остался неизвестным.
Предлагаешь нам догадаться, какой у тебя там входной файл.
Прошу прощения, добавляю файл с которым работаю.

Прикреплённый файлы:
attachment zemla.csv (92,7 KБ)

Офлайн

#7 Окт. 22, 2015 13:45:38

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 10016
Репутация: +  857  -
Профиль   Отправить e-mail  

Парсинг csv

Вот две строки

>>> s1
'13,13,"Земельный участок в д.Курово г/п Дмитров",zemelnyj-uchastok-v-dkurovo-gp-dmitrov,da,tatyana,images/logo/d-kurovo/d-kurovo-logo.png,item-photo/d-kurovo,"д. Курово, Дмитровский район, Московская область, Россия",uchastki,"<p style=""text-align: justify;""><span style=""font-family: terminal, monaco; font-size: 14pt;"">Продается земельный участок под застройку индивидуального жилого дома. Участок 8 соток в д.Курово г/п Дмитров.</span></p>\n\n<p style=""text-align: justify;""><span style=""font-family: terminal, monaco; font-size: 14pt;"">Категория земель: земли населенных пунктов.</span></p>\n\n<p style=""text-align: justify;""><span style=""font-family: terminal, monaco; font-size: 14pt;"">Разрешенное использование: для ведения личного подсобного хозяйства.</span></p>\n\n<p style=""text-align: justify;""><span style=""font-family: terminal, monaco; font-size: 14pt;"">После строительства дома, возможность прописаться (зарегистрироваться) по месту. Свет, газ на участке.</span></p>\n\n<p style=""text-align: justify;""><span style=""font-family: terminal, monaco; font-size: 14pt;"">Кадастровый номер участка 50:04:0150401:353. Курортное место Подмосковья.</span></p>\n\n<p style=""text-align: justify;""><span style=""font-family: terminal, monaco; font-size: 14pt;"">У деревни находится популярный горнолыжный курорт ""Сорочаны"".Участок граничит с отелем ""Свежий Ветер"". Идеальное расположение в экологически чистом месте, центре активного отдыха. Хорошая транспортная доступность.</span></p>",,,"д. Курово, Дмитровский район, Московская область, Россия",zemli-selskohozyajstvennogo-naznacheniya,digs,8,da,da,da,asfalt,"2 400 000 rub"\n'
>>> s2
'14,14,"Недостроенный жилой дом на 15 сот. д.Рождествено",prodaetsya-nedostroennyj-zhiloj-dom-na-15-sot-drozhdestveno,da,tatyana,images/logo/d-shebanovo/d-shebanovo.png,item-photo/d-shebanovo,"деревня Шебаново, Московская область, Россия",uchastki,"<p style=""text-align: justify;""><span style=""font-family: terminal, monaco; font-size: 14pt;"">Продается недостроенный кирпичный дом на земельном участке под ИЖС на 15 (по факту 20) сотках в д.Рождествено Габовское с/п Дмитровского района.</span></p>\n\n<p style=""text-align: justify;""><span style=""font-family: terminal, monaco; font-size: 14pt;"">Недостроенный кирпичный дом размером 10х12 метров, построен 1 этаж из облицовочного кирпича (цвет слоновая кость и шоколад).</span></p>\n\n<p style=""text-align: justify;""><span style=""font-family: terminal, monaco; font-size: 14pt;"">На участке имеется хоз.блок деревянно-щитовой 2,5 х 6 м.</span></p>\n\n<p style=""text-align: justify;""><span style=""font-family: terminal, monaco; font-size: 14pt;"">Участок ровный спланированный, хороший подъезд. На участке по границе с соседом имеется пруд размером 10х5м.</span></p>\n\n<p style=""text-align: justify;""><span style=""font-family: terminal, monaco; font-size: 14pt;"">Имеется тех. условия на подключение электричества 15 кВт 3-х фазное. Газ по границе. Лес в 50 м от участка.</span></p>",,,"деревня Шебаново, Московская область, Россия",zemli-naselyonnyh-punktov,digs,15,da,da,net,grunt,"2 890 000 rub"\n'
>>>

Приведи конечный xml для них (как будто только эти две строки в файле).

Вот названия колонок
>>> c
'id,sku,name,alias,"Есть изображение? (#1)","Агент отвечающий за объект (#2)","Основное фото (#3)","Галлерея (#4)","Карта (#5)","Тип недвижимости (#6)","Property Details (#7)","Agent (#8)","Mark (#9)","Адрес (#10)","Категория земель (#11)","Разрешенное использование (#12)","Количество соток (#13)","Электричество (#14)","Газ (#15)","Водопровод (#16)","Дорога (#17)",price_value_1\n'
>>>
Какие выбираются и как переименовываются?



Отредактировано py.user.next (Окт. 22, 2015 13:55:02)

Офлайн

#8 Окт. 22, 2015 15:29:55

i.z
Зарегистрирован: 2015-10-21
Сообщения: 9
Репутация: +  0  -
Профиль   Отправить e-mail  

Парсинг csv

По скрипту который опубликован в самом начале выбирается все подряд, и на выходе мы имеем вот такую структуру

<?xml version=“1.0”?>
<csv_data>
<sub>
<id>13</id>
<sku>13</sku>
<name>Земельный участок в д.Курово г/п Дмитров</name>
<alias>zemelnyj-uchastok-v-dkurovo-gp-dmitrov</alias>
<author>Super User</author>
<created>2015-09-30 00:00:00</created>
<category>Земельные участки|||zemelnye-uchastki</category>
<tags></tags>
<Есть_изображение?_(#1)>da</Есть_изображение?_(#1)>
<Агент_отвечающий_за_объект_(#2)>tatyana</Агент_отвечающий_за_объект_(#2)>
<Основное_фото_(#3)>images/logo/d-kurovo/d-kurovo-logo.png</Основное_фото_(#3)>
<Галлерея_(#4)>item-photo/d-kurovo</Галлерея_(#4)>
<Карта_(#5)>д. Курово, Дмитровский район, Московская область, Россия</Карта_(#5)>
<Тип_недвижимости_(#6)>uchastki</Тип_недвижимости_(#6)>
<Property_Details_(#7)><p style=“text-align: justify;”><span style=“font-family: terminal, monaco; font-size: 14pt;”>Продается земельный участок под застройку индивидуального жилого дома. Участок 8 соток в д.Курово г/п Дмитров.</span></p>
<p style=“text-align: justify;”><span style=“font-family: terminal, monaco; font-size: 14pt;”>Категория земель: земли населенных пунктов.</span></p>
<p style=“text-align: justify;”><span style=“font-family: terminal, monaco; font-size: 14pt;”>Разрешенное использование: для ведения личного подсобного хозяйства.</span></p>
<p style=“text-align: justify;”><span style=“font-family: terminal, monaco; font-size: 14pt;”>После строительства дома, возможность прописаться (зарегистрироваться) по месту. Свет, газ на участке.</span></p>
<p style=“text-align: justify;”><span style=“font-family: terminal, monaco; font-size: 14pt;”>Кадастровый номер участка 50:04:0150401:353. Курортное место Подмосковья.</span></p>
<p style=“text-align: justify;”><span style=“font-family: terminal, monaco; font-size: 14pt;”>У деревни находится популярный горнолыжный курорт “Сорочаны”.Участок граничит с отелем “Свежий Ветер”. Идеальное расположение в экологически чистом месте, центре активного отдыха. Хорошая транспортная доступность.</span></p></Property_Details_(#7)>
<Agent_(#8)></Agent_(#8)>
<Mark_(#9)></Mark_(#9)>
<Адрес_(#10)>д. Курово, Дмитровский район, Московская область, Россия</Адрес_(#10)>
<Категория_земель_(#11)>zemli-selskohozyajstvennogo-naznacheniya</Категория_земель_(#11)>
<Разрешенное_использование_(#12)>digs</Разрешенное_использование_(#12)>
<Количество_соток_(#13)>8</Количество_соток_(#13)>
<Электричество_(#14)>da</Электричество_(#14)>
<Газ_(#15)>da</Газ_(#15)>
<Водопровод_(#16)>da</Водопровод_(#16)>
<Дорога_(#17)>asfalt</Дорога_(#17)>
<price_value_1>2 400 000 rub</price_value_1>

Но это естественно не подходит, к тому же мне не нужна большая часть этих данных.
Из того что нужно:

<?xml version=“1.0”?>
<csv_data>
<sub>
<id>13</id>
<name>Земельный участок в д.Курово г/п Дмитров</name>
<Тип_недвижимости_(#6)>uchastki</Тип_недвижимости_(#6)>
<Property_Details_(#7)><p style=“text-align: justify;”><span style=“font-family: terminal, monaco; font-size: 14pt;”>Продается земельный участок под застройку индивидуального жилого дома. Участок 8 соток в д.Курово г/п Дмитров.</span></p>
<p style=“text-align: justify;”><span style=“font-family: terminal, monaco; font-size: 14pt;”>Категория земель: земли населенных пунктов.</span></p>
<p style=“text-align: justify;”><span style=“font-family: terminal, monaco; font-size: 14pt;”>Разрешенное использование: для ведения личного подсобного хозяйства.</span></p>
<p style=“text-align: justify;”><span style=“font-family: terminal, monaco; font-size: 14pt;”>После строительства дома, возможность прописаться (зарегистрироваться) по месту. Свет, газ на участке.</span></p>
<p style=“text-align: justify;”><span style=“font-family: terminal, monaco; font-size: 14pt;”>Кадастровый номер участка 50:04:0150401:353. Курортное место Подмосковья.</span></p>
<p style=“text-align: justify;”><span style=“font-family: terminal, monaco; font-size: 14pt;”>У деревни находится популярный горнолыжный курорт “Сорочаны”.Участок граничит с отелем “Свежий Ветер”. Идеальное расположение в экологически чистом месте, центре активного отдыха. Хорошая транспортная доступность.</span></p></Property_Details_(#7)>
<Разрешенное_использование_(#12)>digs</Разрешенное_использование_(#12)>
<Количество_соток_(#13)>8</Количество_соток_(#13)>
<Электричество_(#14)>da</Электричество_(#14)>
<Газ_(#15)>da</Газ_(#15)>
<Водопровод_(#16)>da</Водопровод_(#16)>
<Дорога_(#17)>asfalt</Дорога_(#17)>
<price_value_1>2 400 000 rub</price_value_1>
</sub>

Не подходят те тэги, которые выводятся кириллицей.
Их необходимо заменить на латинские. Как я уже говорил:

<Количество_соток_(#13)>8</Количество_соток_(#13)>

заменить

<area>8</area>.

Но чтобы задача выводилась совершенно идеально необходимо в тегах:
<Property_Details_(#7)></Property_Details_(#7)>
Убрать весь html оставив только текст.

Но а эталоном и скриптом исполняющим любые желания этот код станет в том случае, если в <price_value_1>2 400 000 rub</price_value_1> латинское обозначение рублей “rub” переместится в атрибуты тэга, и получит вот такую конструкцию:

<price_value_1 valuta="rub">2 400 000</price_value_1>


Отредактировано i.z (Окт. 22, 2015 15:33:10)

Офлайн

#9 Окт. 22, 2015 17:22:41

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 10016
Репутация: +  857  -
Профиль   Отправить e-mail  

Парсинг csv

#!/usr/bin/env python3
 
import csv
import xml.etree.ElementTree as ET
import lxml.html
 
def read_csv(fname):
    with open(fname, encoding='utf-8', newline='') as f:
        f.readline()
        reader = csv.reader(f)
        for i in reader:
            yield i
 
def convert_csv_to_xml(csvstream, csvnums, xmlroot, xmlnode, xmlnames):
    out = '<?xml version="1.0"?>'
    doc = ET.Element(xmlroot)
    for i in csvstream:
        selected = select_fields(i, csvnums)
        section = make_xml_section(xmlnode, xmlnames, selected)
        node_clean_html(section[3])
        node_value_to_attr(section[10], 'valuta')
        doc.append(section)
    out += ET.tostring(doc, encoding='unicode')
    return out
 
def select_fields(lst, numbers):
    out = [i for n, i in enumerate(lst, 1)
           if n in numbers]
    return out
 
def make_xml_section(parent, names, lst):
    sub = ET.Element(parent)
    for name, value in zip(names, lst):
        e = ET.Element(name)
        e.text = str(value)
        sub.append(e)
    return sub
 
def node_clean_html(node):
    if node.text:
        node.text = clean(node.text)
 
def clean(s):
    doc = lxml.html.fromstring(s)
    return ''.join(doc.xpath(r'.//text()'))
 
def node_value_to_attr(node, attr_name):
    pref, suff = node.text.rsplit(None, 1)
    node.set(attr_name, suff)
    node.text = pref
 
def write_xml(fname, xmldata):
    with open(fname, 'w', encoding='utf-8') as fout:
        print(xmldata, file=fout)
 
def main():
    ifname = 'zemla.csv'
    csv_nums = [1, 3, 10,
                11, 16, 17,
                18, 19, 20,
                21, 22]
 
    ofname = 'zemla.xml'
    xml_root = 'csv_data'
    xml_node = 'sub'
    xml_names = ['id', 'name', 'type',
                 'details', 'permit', 'number',
                 'electricity', 'gas', 'water',
                 'road', 'price']
 
    csv_stream = read_csv(ifname)
    xmldata = convert_csv_to_xml(
        csv_stream,
        csv_nums,
        xml_root,
        xml_node,
        xml_names
    )
    write_xml(ofname, xmldata)
 
if __name__ == '__main__':
    main()



Отредактировано py.user.next (Окт. 25, 2015 01:14:10)

Офлайн

#10 Окт. 23, 2015 11:38:16

i.z
Зарегистрирован: 2015-10-21
Сообщения: 9
Репутация: +  0  -
Профиль   Отправить e-mail  

Парсинг csv

py.user.next - это просто филигранно, огромное спасибо. Буду сидеть разбираться, что и как работает.

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version