Компьютерный форум OSzone.net  

Компьютерный форум OSzone.net (http://forum.oszone.net/index.php)
-   Скриптовые языки администрирования Windows (http://forum.oszone.net/forumdisplay.php?f=102)
-   -   Файлы большого объема html сохранить в csv, изменив структуру (http://forum.oszone.net/showthread.php?t=344593)

v79italya 29-03-2020 16:31 2915023

Файлы большого объема html сохранить в csv, изменив структуру
 
Добрый день. В приложении ссылки находятся три файла.
Файл csv - желаемый результат.
Файл html - материал для обработки, приложил один, а так их несколько.
Файл xlsx - получаемый результат в Excel в надстройке Power Query. Если в папке один файл html, то Power Query его обработает за минуту-пол-тары. Если скопировать пару раз этот же файл, то PQ три файла обработает за минут пять. Если же размножить до десяти, то на обработку уходит более 15 минут. Результат не очень.
http://forum.oszone.net/thread-150969-4.html
Глядя в этой теме как лихо скрипты расправляются с файлами csv, хотел бы решить и эту задачу, используя скрипт. То есть обработать папку с файлами html, изменив структуру данных и сохранив в csv. Возможно ли это и сколько времени потребуется на обработку?



https://drive.google.com/open?id=1ob...li253cDbc-GMU_

DJ Mogarych 30-03-2020 09:05 2915079

html-файлы создаются для отображения уже готовой информации в виде, понятном человеку. Обрабатывать их, особенно таблицы с огромным количеством объединённых строк - занятие крайне неблагодарное и непродуктивное.
Что создаёт эти html-таблицы, откуда они выгружаются?

v79italya 30-03-2020 09:24 2915081

Цитата:

Цитата DJ Mogarych
откуда они выгружаются? »

выгружаются из R-Keeper (программа в ресторанах)
Цитата:

Цитата DJ Mogarych
особенно таблицы с огромным количеством объединённых строк »

одним из вариантов обработки в Power Query было перевернуть данные(то, что было справа, стало слево) и добавить null-ей до общего количества значений 18 штук, затем перевернуть обратно

DJ Mogarych 30-03-2020 10:27 2915090

Этот R-Keeper умеет выгружать данные во что-то другое?
Там вроде бы есть экспорт в DBF или MSSQL.

v79italya 30-03-2020 10:37 2915092

Цитата:

Цитата DJ Mogarych
умеет выгружать данные во что-то другое? »

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

DJ Mogarych 30-03-2020 10:44 2915094

Цитата:

Цитата v79italya
при открытии больших файлов часть данных теряется »

Какая прелесть.
В любом случае, можно, наверное, делать нечеловеческие усилия и парсить этот HTML, но я бы не советовал. Надо выгружать во что-то более осмысленное. Я немножко пытался парсить, но безрезультатно.

YuS_2 30-03-2020 12:27 2915113

Цитата:

Цитата v79italya
одним из вариантов обработки в Power Query было перевернуть данные(то, что было справа, стало слево) и добавить null-ей до общего количества значений 18 штук, затем перевернуть обратно »

слишком частное решение, помимо rowspan-ов, в таблице могут оказаться и colspan-ы, тогда этот метод не сработает... во всяком случае, правильно не сработает.

Цитата:

Цитата DJ Mogarych
можно, наверное, делать нечеловеческие усилия и парсить этот HTML, но я бы не советовал. Надо выгружать во что-то более осмысленное. »

именно так!
Чтобы распарсить rowspan-ы, потребуются немаленькие усилия... если бы таблица была простой, то и парсить её было бы просто.
Правильнее - получать доступ к исходным данным и уже потом заниматься их обработкой.

v79italya 30-03-2020 16:06 2915139

DJ Mogarych, отсюда ноги растутhttps://www.planetaexcel.ru/forum/in...-v-power-qwery
Мне было интересно возможно ли быстрая обработка файлов

Iska 30-03-2020 18:54 2915150

v79italya, быстрая обработка возможна для реляционных баз данных. Почему авторы R-Keeper не озаботились экспортом во что-то вменяемое — хрен его знает.

DJ Mogarych 30-03-2020 20:35 2915160

Так озаботились же вроде, просто разобраться надо.

Iska 30-03-2020 20:40 2915161

DJ Mogarych, а… ну, да.

v79italya 30-03-2020 22:27 2915169

Цитата:

Цитата Iska
быстрая обработка возможна для реляционных баз данных »

реляционные данные это, я так понял, без всяких объединений.
Вот смотрите, если в PQ(на обработку ушло 30 секунд на этот файл) слегка обработать и после сохранить в csv, то на выходе прикрепленный файл. Такой файл можно быстро обработать(извлечь текст между NOWRAP> и </TD>, удалить &nbsp;)?

Sham 31-03-2020 15:41 2915254

Вложений: 1
для себя кстати распарсил, но выкладывать вряд-ли буду. Там помимо colspan'ов ещё всякого нежданчика может быть...

v79italya 31-03-2020 20:40 2915284

Цитата:

Цитата Sham
кстати распарсил »

Сколько времени уходит на обработку файла?

YuS_2 01-04-2020 11:54 2915371

Цитата:

Цитата v79italya
Сколько времени уходит на обработку файла? »

Распарсить-то возможно. Но время будет невменяемым, с таким подходом.
На тот файл .html, который был показан, будет уходить минут от 5 до 15, как минимум...

v79italya 01-04-2020 12:26 2915378

Цитата:

Цитата YuS_2
будет уходить минут от 5 »

Значит, обработка в Power Query за минуту не такой уж и медленный вариант.
А я думал что PQ много в чем тормозит

YuS_2 01-04-2020 15:33 2915438

Цитата:

Цитата v79italya
Значит, обработка в Power Query за минуту не такой уж и медленный вариант. »

Если результат устраивает, то можно считать быстро...
Вот парсер на powershell
Код:

$infile = '15p.html'
$outfile = '15p_out.csv'
$timefile = 'time.txt'
measure-command{
$skip = 2 # Пропуск первых строк таблицы, для формирования заголовков
$html = new-object -com "HTMLFile"
$html.ihtmldocument2_write($(gc $infile -raw -enc utf8))

$table = $html.getelementsbytagname("table")
$tr = $table[0]|%{$_.getelementsbytagname("tr")}
$head = $tr[$skip]|%{$_.getelementsbytagname("td")}
$rowind = ,1 * $head.count

$headers = $null
$tr[$skip..$tr.count]|%{
        $row = $_.getelementsbytagname("td") | select innertext,rowspan,colspan 
        if ($headers) {
                $str = [ordered]@{}
                $rowspan = new-object 'int[]' $head.count
                $k=0
                foreach ($item in $row){
                        while ($rowind[$k] -gt 1){
                                $str[$headers[$k]] = $null
                                $rowind[$k] -= 1
                                $rowspan[$k] = 1
                                $k++
                        }
                        $str[$headers[$k]] = $item.innertext.trim()
                        $rowspan[$k] = $item.rowspan
                        $k++
                }
                for($i=0;$i -lt $rowind.count;$i++){
                        if ($rowspan[$i] -gt 1){$rowind[$i] = $rowspan[$i]}
                }
                [pscustomobject]$str
        } else {
                $headers = $row.innertext.trim()
        }
}|export-csv $outfile -notype -enc utf8 -d ';'
}|out-file $timefile

Возможно, не оптимально, но что уж получилось...
rowspan-ы учитываются...
colspan-ы не учитываются...
Пробуйте... у меня парсился файл 11 минут.

DJ Mogarych 01-04-2020 20:57 2915472

YuS_2, вы героический человек.

v79italya 01-04-2020 21:28 2915481

YuS_2, спасибо. Завтра опробую

Iska 02-04-2020 00:08 2915503

Цитата:

Цитата DJ Mogarych
YuS_2, вы героический человек. »

Не то слово ;). Присоединюсь.

YuS_2 02-04-2020 08:10 2915518

Цитата:

Цитата DJ Mogarych
героический человек »

Да чего там героического? :)
Как оказалось, глаза боятся, а руки делают... немного гугля, чуть-чуть ковыряния в доках и загашниках со скриптами, в итоге получилось rowspan-ы расковырять. На всё про все, час-полтора с перерывами...
Тем не менее, время обработки, всё равно, невменяемое, имхо. Для небольших таблиц сгодится, а для объемных - лучше таки воспользоваться чем-то другим...

v79italya 03-04-2020 15:02 2915687

YuS_2, вчера запускал и не понимал что происходит и происходит ли что нибудь.
Сегодня еще раз запустил скрипт и ушел на полчаса. Через пол-часа смотрю, появился csv заполненный и txt, в котором узнал что парсило девять минут. Согласен что девять минут - это много.
Вывод такой: по любому парсеры быстро не работают :)

DJ Mogarych 03-04-2020 16:16 2915700

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

v79italya 03-04-2020 16:51 2915709

Цитата:

Цитата DJ Mogarych
Парсеры всякой неудобоваримой шляпы »

дам ссылку на эту тему автору темы, от которой ноги растут. Пусть примет к сведению

YuS_2 05-04-2020 13:34 2915883

Вложений: 1
Выдалось время одновременно с желанием понажимать кнопки... :)
Скрипт теперь "умеет" учитывать и rowspan-ы, и colspan-ы, плюс немного описания:
script.ps1
Код:

<#
.SYNOPSIS
        Парсер таблиц .html

.Description
        Скрипт парсит таблицы в формате HTML и записывает данные в формате CSV
        - для каждой таблицы отдельный файл. Учитываются объединенные ячейки по
        строкам и(или) по колонкам, ROWSPAN и COLSPAN.
        Число колонок определяется автоматически, по тегам TH. Имена заголовков
        присваиваются из значений элементов TH. При отсутствии тегов TH, число
        колонок определяется по максимальному числу ячеек в строках, при этом
        наименование заголовков        будет формироваться автоматически, с префиксом
        'H' и с номерами по порядку.
        Размеры строк таблицы должны быть в пределах количества заголовков, т.е.
        структура таблицы должна быть правильной, в том числе, с учетом ROWSPAN
        и COLSPAN

.Parameter Infile
        Обязательный: Указывается файл в котором необходимо распарсить таблицу(ы)

.Parameter Outfile
        Необязательный: Имя для выходных файлов .csv. Указывается только имя, без
        расширения. К имени будет добавлен номер таблицы по порядку.

.Example
        .\script.ps1 -Infile 'test.html'
       
.Example
        .\script.ps1 -Infile 'test.html' -Outfile 'd:\folder\name_file'

.Example
        .\script.ps1 'test.html' 'name_file'

.Example
        .\script.ps1

.Notes
        Created By YuS
        Version: 1.02
        Date: 16/04/2020
        Purpose/Change:        Устранение багов кода. Исключение вложенных таблиц.
        Version: 1.01
        Date: 06/04/2020
        Purpose/Change:        Оптимизирован алгоритм чтения ячеек. Удален лишний цикл и
        буферный счетчик.
        Version: 1.00
        Date: 05/04/2020
        Purpose/Change:        Первая версия

.Link
        http://forum.oszone.net/showpost.php?p=2915883&postcount=25
#>

param (
        #[parameter(Mandatory=$true)]
        [string]$infile= 'test1.html',
        [string]$outfile = 'table'
)

measure-command{

$html = new-object -com "HTMLFile"
$html.ihtmldocument2_write($(gc $infile -raw -enc utf8))
$tables = $html.getelementsbytagname("table")

# Исключение вложенных таблиц:
$tables|?{($_.getelementsbytagname('table')|%{$_}).count -eq 0}|%{$n=0}{
# Обработка всех элементов TABLE, включая вложенные (вероятна ошибка структуры таблицы).
# Необходимо закомментировать строку кода выше и раскомментировать эту:
#$tables|%{$n=0}{
        $headers = @();$n++
        $tr = $_|%{$_.getelementsbytagname("tr")}
        if($headers = $tr|?{$_.firstchild().tagname -eq 'th'}|
        %{$_.getelementsbytagname("th")}|select -exp innertext){
                $headers = $headers.trim()
        } else {
                $headers = 1..([linq.parallelenumerable]::max(
                        [linq.parallelenumerable]::asparallel($tr.lastchild().cellindex)
                )+1)|%{"H$_"}
        }
        $rowind = ,1 * $headers.count
        $tr.where({$_.firstchild().tagname -eq 'td'})|%{
                $row = $_.getelementsbytagname("td") | select innertext,rowspan,colspan
                try {
                        $str = [ordered]@{}
                        $k=0
                        foreach ($item in $row){
                                if ($rowind[$k] -gt 1){
                                        while ($rowind[$k] -gt 1){
                                                $str[$headers[$k]] = $null
                                                $rowind[$k] -= 1
                                                $k++
                                        }
                                }
                                if (($colspan = $item.colspan) -gt 1) {
                                        $str[$headers[$k]] = if($item.innertext){
                                                $item.innertext.trim()
                                        } else {$null}
                                        if ($item.rowspan -gt 1){$rowind[$k] = $item.rowspan}
                                        $k++
                                        while ($colspan -gt 1){
                                                $str[$headers[$k]] = $null
                                                $colspan -=1
                                                if ($rowind[$k] -gt 1){$rowind[$k]-=1}
                                                $k++
                                        }
                                } else {
                                        $str[$headers[$k]] = if($item.innertext){
                                                $item.innertext.trim()
                                        } else {$null}
                                        if ($item.rowspan -gt 1){$rowind[$k] = $item.rowspan}
                                        $k++
                                }
                        }
                        [pscustomobject]$str
                } catch {
                        write-host Разметка заголовков не соответствует размерам строк -for red
                        write-host $_ -for cyan
                }
        } |export-csv $($outfile+"_"+$n+'.csv') -notype -enc utf8 -d ';'
}

} #|out-file time.txt -enc utf8


1. Оптимизировать алгоритм чтения ячеек не удалось, но кое-что оптимизировано.
2. Объемные таблицы, всё также обрабатываются не быстро.
3. Парсит все имеющиеся таблицы в dom-структуре.
Вдруг кому-то ещё пригодится...

v79italya 05-04-2020 14:20 2915890

Цитата:

Цитата DJ Mogarych
Парсеры всякой неудобоваримой шляпы »

Там этот парень еще тему открыл. Теперь парсит xmlhttps://www.planetaexcel.ru/forum/in...52525253BFID=1

Sham 06-04-2020 18:49 2916071

Вложений: 1
Цитата:

Цитата v79italya
Сколько времени уходит на обработку файла? »

Мой jscript на регулярках за 24 секунды тот файл (14M). Зависит от процессора. Можно, конечно, и через com htmlfile, но это ж все 14М в DOM парсятся - сколько это по памяти будет?

v79italya 07-04-2020 07:25 2916111

Цитата:

Цитата Sham
jscript на регулярках за 24 секунды тот файл (14M). Зависит от процессора. Можно, конечно, и через com htmlfile, но это ж все 14М в DOM парсятся - сколько это по памяти будет? »

Не знаю сколько это по памяти)
У меня на нетбуке за 50 сек обработал. По моему, результат достаточно хороший.
Спасибо

YuS_2 28-04-2020 22:43 2919313

Цитата:

Цитата YuS_2
Скрипт теперь "умеет" учитывать и rowspan-ы, и colspan-ы, плюс немного описания »

Ещё вариант скрипта для парсинга html
http://forum.oszone.net/post-2919294.html#post2919294
- работает быстрее, т.к. принцип работы основан на внешнем модуле, по типу парсинга XML.
- парсер не зависит от встроенного парсера html в powershell, который зависит от Internet Explorer
- будет работать в Powershell Core

v79italya 29-04-2020 16:39 2919404

Цитата:

Цитата YuS_2
работает быстрее »

очень хорошо. Спасибо


Время: 17:12.

Время: 17:12.
© OSzone.net 2001-