如何使用native PowerShell命令从html文件中提取特定表?

时间:2014-09-19 18:45:28

标签: html powershell csv cmdlets

我使用PAL工具(https://pal.codeplex.com/)从Windows中的perfmon日志生成HTML报告。在PAL处理来自perfmon的.blg文件之后,它将信息转储到HTML文档中,该文档包含有关系统执行方式的各种数据点的表。我目前正在编写一个脚本,查看所有HTML文件的目录内容,并对所有HTML文件执行get-content。

我想要做的是为具有不同行数的特定表刮掉此get-content blob的转储。是否可以使用本机PowerShell cmdlet查找特定表,计算每个表中的行数,以及转储所需的表和表行?

以下是我试图抓取的表格式示例:

<H3>Overall Counter Instance Statistics</H3>
<TABLE ID="table6" BORDER=1 CELLPADDING=2>
<TR><TH><B>Condition</B></TH><TH><B>\LogicalDisk(*)\Disk Transfers/sec</B></TH><TH><B>Min</B></TH><TH><B>Avg</B></TH><TH><B>Max</B></TH><TH><B>Hourly Trend</B></TH><TH><B>Std Deviation</B></TH><TH><B>10% of Outliers Removed</B></TH><TH><B>20% of Outliers Removed</B></TH><TH><B>30% of Outliers Removed</B></TH></TR>
<TR><TD>No Thresholds</TD><TD>MACHINENAME/C:</TD><TD>1</TD><TD>7</TD><TD>310</TD><TD>0</TD><TD>11</TD><TD>5</TD><TD>5</TD><TD>5</TD></TR>
<TR><TD>No Thresholds</TD><TD>MACHINENAME/D:</TD><TD>0</TD><TD>0</TD><TD>0</TD><TD>0</TD><TD>0</TD><TD>0</TD><TD>0</TD><TD>0</TD></TR>
<TR><TD>No Thresholds</TD><TD>MACHINENAME/E:</TD><TD>0</TD><TD>24</TD><TD>164</TD><TD>-1</TD><TD>11</TD><TD>22</TD><TD>21</TD><TD>20</TD></TR>
<TR><TD>No Thresholds</TD><TD>MACHINENAME/HarddiskVolume5</TD><TD>0</TD><TD>0</TD><TD>2</TD><TD>0</TD><TD>0</TD><TD>0</TD><TD>0</TD><TD>0</TD></TR>
<TR><TD>No Thresholds</TD><TD>MACHINENAME/L:</TD><TD>0</TD><TD>0</TD><TD>0</TD><TD>0</TD><TD>0</TD><TD>0</TD><TD>0</TD><TD>0</TD></TR>
<TR><TD>No Thresholds</TD><TD>MACHINENAME/T:</TD><TD>0</TD><TD>7</TD><TD>430</TD><TD>0</TD><TD>21</TD><TD>3</TD><TD>2</TD><TD>2</TD></TR>
</TABLE>

表ID在所有输出文件中都是常量,但表行的数量不是。任何帮助表示赞赏!

2 个答案:

答案 0 :(得分:7)

好的,这没有经过全面测试,但可以在PS 2.0中使用IE11的示例表:

# Parsing HTML with IE.
$oIE = New-Object -ComObject InternetExplorer.Application
$oIE.Navigate("file.html")
$oHtmlDoc = $oIE.Document

# Getting table by ID.
$oTable = $oHtmlDoc.getElementByID("table6")

# Extracting table rows as a collection.
$oTbody = $oTable.childNodes | Where-Object { $_.tagName -eq "tbody" }
$cTrs = $oTbody.childNodes | Where-Object { $_.tagName -eq "tr" }

# Creating a collection of table headers.
$cThs = $cTrs[0].childNodes | Where-Object { $_.tagName -eq "th" }
$cHeaders = @()
foreach ($oTh in $cThs) {
    $cHeaders += `
        ($oTh.childNodes | Where-Object { $_.tagName -eq "b" }).innerHTML
}

# Converting rows to a collection of PS objects exportable to CSV.
$cCsv = @()
foreach ($oTr in $cTrs) {
    $cTds = $oTr.childNodes | Where-Object { $_.tagName -eq "td" }
    # Skipping the first row (headers).
    if ([String]::IsNullOrEmpty($cTds)) { continue }
    $oRow = New-Object PSObject
    for ($i = 0; $i -lt $cHeaders.Count; $i++) {
        $oRow | Add-Member -MemberType NoteProperty -Name $cHeaders[$i] `
            -Value $cTds[$i].innerHTML
    }
    $cCsv += $oRow
}

# Closing IE.
$oIE.Quit()

# Exporting CSV.
$cCsv | Export-Csv -Path "file.csv" -NoTypeInformation

老实说,我没有针对最佳代码。这只是一个如何在PS中使用DOM对象并将它们转换为PS对象的示例。

答案 1 :(得分:6)

我看到你接受了答案,但我想我也会在这里添加一个RegEx解决方案。这个没有COM对象,并且应该是PSv2友好的我很确定。

$Path = 'C:\Path\To\File.html'
[regex]$regex = "(?s)<TABLE ID=.*?</TABLE>"
$tables = $regex.matches((GC C:\Temp\test.txt -raw)).groups.value
ForEach($String in $tables){
    $table = $string.split("`n")
    $CurTable = @()
    $CurTableName = ([regex]'TABLE ID="([^"]*)"').matches($table[0]).groups[1].value
    $CurTable += ($table[1] -replace "</B></TH><TH><B>",",") -replace "</?(TR|TH|B)>"
    $CurTable += $table[2..($table.count-2)]|ForEach{$_ -replace "</TD><TD>","," -replace "</?T(D|R)>"}
    $CurTable | convertfrom-csv | export-csv "C:\Path\To\Output\$CurTableName.csv" -notype
}

那应该为找到的每个表输出一个CSV文件。例如table6.csv,table9.csv等。如果你想为每个HTML文件输出CSV,你可以将整个事物包装在ForEach循环中,如:

ForEach($File in (Get-ChildItem "$Path\*.html")){
    Insert above code here
}

您需要修改$tables =行,使其为GC $file.fullname,以便在迭代时加载每个文件。

然后只需将Export-Csv修改为:

$CurTable | convertfrom-csv | export-csv "C:\Path\To\Output\$($File.BaseName)\$CurTableName.csv" -notype

因此,如果您的Server01.html中包含3个表,您将获得一个名为Server01的文件夹,其中包含3个CSV文件,每个表一个。