Найти - Пользователи
Полная версия: Парсинг html таблиц от FastReport
Начало » Центр помощи » Парсинг html таблиц от FastReport
1 2 3
Cyr
Генератор отчётов FastReport выгружает таблички в html, в которых ячейки представлены тегами <div>
Это выглядит так:
 <div class="s8" style="left:946.39px;top:61.83px;width:61.37px;height:42.89px;"><div class="s7">Стоимость, руб.</div></div>
<div class="s10" style="left:88.33px;top:61.83px;width:53.81px;height:42.89px;"><div class="s9">Дата</div></div>
<div class="s12" style="left:143.14px;top:61.83px;width:46.25px;height:42.89px;"><div class="s11">Время</div></div>
<div class="s14" style="left:190.39px;top:61.83px;width:492.29px;height:42.89px;"><div class="s13">Вид услуги</div></div>
<div class="s16" style="left:683.68px;top:61.83px;width:63.26px;height:42.89px;"><div class="s15">Набранный номер, точка доступа</div></div>
<div class="s18" style="left:747.94px;top:61.83px;width:93.5px;height:42.89px;"><div class="s17">Местонахождение при использовании услуги</div></div>
<div class="s20" style="left:842.44px;top:61.83px;width:102.95px;height:42.89px;"><div class="s19">Объём</div></div>
<div class="s22" style="left:-0.5px;top:61.83px;width:87.83px;height:42.89px;"><div class="s21">Номер устройства (IMEI)</div></div>
<div class="s23" style="left:0px;top:106.22px;width:1009.26px;height:24.45px;">&nbsp;</div>
<div class="s25" style="left:88.33px;top:105.72px;width:53.81px;height:23.45px;"><div class="s24">04.10.2021</div></div>
<div class="s27" style="left:143.14px;top:105.72px;width:46.25px;height:23.45px;"><div class="s26">06:54:47</div></div>
<div class="s29" style="left:190.39px;top:105.72px;width:492.29px;height:23.45px;"><div class="s28">Исх. на мобильные дом. региона, Билайн; Пензенская Область, моб. связь, Билайн</div></div>
<div class="s31" style="left:683.68px;top:105.72px;width:63.26px;height:23.45px;"><div class="s30">89699900000</div></div>
<div class="s33" style="left:747.94px;top:105.72px;width:93.5px;height:23.45px;"><div class="s32">Пензенская обл.</div></div>
<div class="s35" style="left:842.44px;top:105.72px;width:48.14px;height:23.45px;"><div class="s34">9,00</div></div>
<div class="s37" style="left:-0.5px;top:105.72px;width:87.83px;height:23.45px;"><div class="s36"></div></div>
<div class="s38" style="left:891.58px;top:105.72px;width:53.81px;height:23.45px;"><div class="s24">Секунда</div></div>
<div class="s40" style="left:946.39px;top:105.72px;width:61.37px;height:23.45px;"><div class="s39">0,00</div></div>
<div class="s23" style="left:0px;top:130.67px;width:1009.26px;height:24.45px;">&nbsp;</div>
Как получить данные из этого отчёта? С учётом того что некоторые ячейки могут быть пустые.
Я пробовал так:
kol4 = tree.xpath('//div[contains(@style, "left:190.39px;")]/div/text()') #Вид услуги
print (kol4, len(kol4))
kol7 = tree.xpath('//div[contains(@style, "left:842.44px;")]/div/text()') #Объём
print (kol7, len(kol7))
kol8 = tree.xpath('//div[contains(@style, "left:891.58px")]/div/text()') #Ед.изм.
print (kol8, len(kol8))
kol4 = tree.xpath('//div[(@class="s29" or @class="s47")]/div/node()') #Вид услуги
kol7 = tree.xpath('//div[(@class="s35" or @class="s53")]/div/node()') #Объём
kol8 = tree.xpath('//div[(@class="s38" or @class="s56")]/div/node()') #Ед.изм.
Но из-за пустых ячеек, которые xpath не берёт, получается разное количество значений. И записи по строкам невозможно составить правильно.
Cyr
Решил тупо в лоб эту задачу
def spliting(line):
start=line.rfind('">')+2
end=line.rfind('</div></div>')
mes='"'+line[start:end]+'"'
return mes

f = open('c:/Downloads/Детализация.html', encoding="utf-8")
for line in f:
if line.rfind('left:190.39px;')>0:
print (spliting(line), end=';')
elif line.rfind('left:842.44px;')>0:
print (spliting(line), end=';')
elif line.rfind('left:891.58px;')>0:
print (spliting(line))
py.user.next
Cyr
С учётом того что некоторые ячейки могут быть пустые.
Проблема в том, что ты ищешь по атрибуту style. Это самое глупое, что можно было сделать.

Cyr
Как получить данные из этого отчёта?
Где здесь отчёт? Это лишь маленький кусочек чего-то целого. И что значит “некоторые ячейки могут быть пустые”? Это отсутствие тегов для них или просто наличие тегов, но отсутствие текста в них?
Cyr
py.user.next
Проблема в том, что ты ищешь по атрибуту style. Это самое глупое, что можно было сделать.
Отступы слева в стиле определяют положение колонок таблицы. По ним определяем что это за колонка. По class тоже можно искать. Но в одной колонке они бывают с несколькими именами.

py.user.next
Где здесь отчёт? Это лишь маленький кусочек чего-то целого.
Это заголовок и первая строка из таблицы. Дальше там строки повторяются.

py.user.next
И что значит “некоторые ячейки могут быть пустые”? Это отсутствие тегов для них или просто наличие тегов, но отсутствие текста в них?
Отсутствие текста в последних тегах div.
py.user.next
Cyr
Отступы слева в стиле определяют положение колонок таблицы.
Не, это понятно. Просто стили меняются каждые три секунды. По ним нельзя ориентироваться, потому что через неделю их сделают другими и вся твоя программа сломается из-за этого. И так будет повторяться каждый раз. Надо более стабильные признаки выбирать (один признак или устойчивую группу признаков).

Cyr
По class тоже можно искать.
Приведи полный пример. Приведи таблицу на три записи хотя бы. На ней и можно поискать стабильные признаки для определения строк и для определения полей в строках. Не говорю колонки, так как колонки не всегда являются минимальными элементами, составляющими строку.

Cyr
Отсутствие текста в последних тегах div.
Отсутствующий текст видно хорошо. Надо просто по-другому записывать его поиск. То есть не факт, что там именно XPath надо применять.

Короче, приведи более полную таблицу для тестов, чтобы по ней можно было провести анализ и написать код, который её разбирает правильно. А уже потом этот код можно будет оттестировать на настоящей таблице.
xam1816
Выложи сюда вот этот файл
 c:/Downloads/Детализация.html
Cyr
xam1816
Выложи сюда вот этот файл
Во вложении реальный файл с нереальными номерами.
py.user.next
Отсутствующий текст видно хорошо. Надо просто по-другому записывать его поиск. То есть не факт, что там именно XPath надо применять.
Ну вот корректно работающий скрипт:
 # -*- coding: utf-8 -*-
# Скрипт импорта детализации html в csv
def spliting(line):
    start=line.rfind('">')+2
    end=line.rfind('</div></div>')
    mes=line[start:end]
    return mes.replace('&nbsp;&nbsp;', ' ')
    
f = open('c:/Downloads/Детализация.html', encoding="utf-8")
out = open('c:/Downloads/Детализация.csv', 'w')
for line in f:
    if line.rfind('class="s29"')>0:   # Вид услуги исх.
        out.write ('"'+spliting(line)+'";')
    elif line.rfind('class="s47"')>0: # Вид услуги вх. 
        out.write ('"'+spliting(line)+'";')    
    elif line.rfind('class="s35"')>0: # Объём исх. 
        out.write (spliting(line)+';')
    elif line.rfind('class="s53"')>0: # Объём вх. 
        out.write (spliting(line)+';')         
    elif line.rfind('class="s38"')>0: # Ед.изм. исх
        out.write ('"'+spliting(line)+'"\n')
    elif line.rfind('class="s56"')>0: # Ед.изм. вх. 
        out.write ('"'+spliting(line)+'"\n')
out.close
Наверное есть более правильный метод решения задачи.
py.user.next
Cyr
Прикреплённый файлы:
attachment Детализация.html (220,2 KБ)
Там несколько страниц. Их надо соединить в одну? Соединить несколько страниц в одну и потом каждый блок из девяти полей превратить в одну строку в CSV-файле?
Cyr
py.user.next
Соединить несколько страниц в одну и потом каждый блок из девяти полей превратить в одну строку в CSV-файле?
Мой скрипт корректно выбирает нужные поля (всего 3) по class, соединяет их в строку. И проходит он по всем страницам. div, в которых колонтитулы и остальные поля он игнорирует же.
Скрипт совсем нечитаемый?
py.user.next
Cyr
Мой скрипт корректно выбирает нужные поля (всего 3) по class из всех страниц.
Опиши, что нужно сделать, без своего скрипта. Словами опиши. Вот файл детализации, из него надо выбрать поля с тем-то и тем-то и сохранить их так-то и так-то.

Потому что твой скрипт реально пугает типа такими вот фрагментами
Cyr
 out.close
Ты не думал, что close - это функция такая и её надо вызвать с помощью круглых скобочек?

Естественно, никто не пишет CSV-файлы, проставляя там разделитель вручную. Да и разделитель в CSV-файлах должен быть запятой, потому что CSV - это Comma-Separated Values, где слово comma переводится как запятая. И признак окончания записи в таком файле не \n, а \r\n. Ну, ты этого не знаешь всего, это видно.

Так что не надо свой чудо-скрипт пихать нам; описывай словами задачу, а мы будем думать уже, как это правильно сделать.
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB