从网页Powershell获取表格

时间:2017-01-18 22:15:07

标签: html powershell powershell-v5.0

我正在尝试使用PowerShell从网页中提取HTML表格,但是我无法调用表格本身。页面上有两个表,一个用于输入,另一个用于输出,理想情况下我想检查输出表是否包含任何内容(除了指示没有结果的特定字符串),以及是否确实将信息表示为表成文件。

我尝试过使用Invoke-Webrequest的{​​{1}}属性,但这些表没有特定的元素名称或ID,也没有“class”或“title”标签来区分二。使用ParsedHtml属性确实显示了几个COMObject(格式为.IHTMLDocument2_all),我觉得我需要以某种方式调用以获得我需要的东西,但我无法弄清楚如何这样做。

有没有办法调用那些COMObjects,所以我可以从它们内部提取信息?

以下是我试图从中获取结果的表格的HTML(当没有结果时):

TypeName: System.__ComObject#{3050f539-98b5-11cf-bb82-00aa00bdce0b}

当有结果时,有几个标题用于显示结果,在此代码中:

<Center>
<TABLE CELLSPACING=0 CELLPADDING=0 BORDER=2><TR><TD>
<TABLE  CELLSPACING=0 CELLPADDING=2 BORDER=0>
<TR><TD BGCOLOR=3399FF ALIGN=CENTER><NOBR><FONT FACE="Arial" SIZE=+1><B>&nbsp;&nbsp; Search Results &nbsp;&nbsp;</B></FONT></NOBR></TD></TR>
<TR><TD><TABLE WIDTH=100% CELLSPACING=0 CELLPADDING=2 BORDER=0>
    <Center>
    <table width="100%" cellpadding="5" cellspacing="0">

        <tr>
            <td>No assets were found for the search</td>
        </tr>
</TABLE></TD></TR>
</TABLE></TD></TR>
</TABLE>
</Center>

理想情况下,我想检查资产是否已找到,如果是,请将结果从标题1,2,3,6和7下拉成可用的表单(很可能是表格或.csv文件) )。非常感谢任何帮助。

1 个答案:

答案 0 :(得分:1)

好的,所以如果你问周围大多数人会强烈反对使用RegEx解析HTML。他们可能是对的,但我很顽固,觉得RegEx足够灵活,可以处理某些任务,即使在HTML中也是如此。所以我在相关问题中调整了我的答案,以便我认为对你有用。

这依赖于这样一个事实,即包含您要查找的数据的最内层表以行开头:

<table width="100%" cellpadding="5"

...并且没有嵌入其他表格。所以它非常具体,但它适用于您提供的示例。

我在你的例子中创建了一个here-string:

$Sample = @"
<Center>
<TABLE CELLSPACING=0 CELLPADDING=0 BORDER=2><TR><TD>
<TABLE  CELLSPACING=0 CELLPADDING=2 BORDER=0>
<TR><TD BGCOLOR=3399FF ALIGN=CENTER><NOBR><FONT FACE="Arial" SIZE=+1><B>&nbsp;&nbsp; Search Results &nbsp;&nbsp;</B></FONT></NOBR></TD></TR>
<TR><TD><TABLE WIDTH=100% CELLSPACING=0 CELLPADDING=2 BORDER=0>
    <Center>
    <table width="100%" cellpadding="5" cellspacing="0">

        <tr bgcolor=A9A9A9>

        <th>HEADER1</th>
        <th>HEADER2</th>
        <th>HEADER3</th>
        <th>HEADER4</th>
        <th>HEADER5</th>
        <th>HEADER6</th>
        <th>HEADER7</th>
        <th>HEADER8</th>
        <th>HEADER9</th>
        <th>HEADER10</th>
        <th>HEADER11</th>
        <th>HEADER12</th>
        <th>HEADER13</th>

        </tr>

            <tr >

                <td nowrap><font size= "-1" color=000000>**RESULTSA**</td>
                <td nowrap><font size= "-1" color=000000>**RESULTSA**</td>
                <td nowrap><font size= "-1" color=000000>**RESULTSA</td>

                <td nowrap><font size= "-1" color=000000>**RESULTSA**</td>
                <td nowrap><font size= "-1" color=000000>**RESULTSA**</td>
                <td nowrap><font size= "-1" color=000000>**RESULTSA**</td>
                <td nowrap><font size= "-1" color=000000>**RESULTSA**</td>
                <td nowrap><font size= "-1" color=000000>**RESULTSA**</td>

                <td nowrap><font size= "-1" color=000000>**RESULTSA**</td>
                <td nowrap><font size= "-1" color=000000>**RESULTSA**</td>

                <td nowrap><font size= "-1" color=000000> </td>
                <td nowrap><font size= "-1" color=000000>**RESULTSA**</td>
                <td nowrap><font size= "-1" color=000000> </td>

            <tr>

            <tr bgcolor=C0C0C0>

                <td nowrap><font size= "-1" color=000000>**RESULTSB**</td>
                <td nowrap><font size= "-1" color=000000>**RESULTSB**</td>
                <td nowrap><font size= "-1" color=000000>**RESULTSB**</td>

                <td nowrap><font size= "-1" color=000000>**RESULTSB**</td>
                <td nowrap><font size= "-1" color=000000>**RESULTSB**</td>
                <td nowrap><font size= "-1" color=000000>**RESULTSB**</td>
                <td nowrap><font size= "-1" color=000000>**RESULTSB**</td>
                <td nowrap><font size= "-1" color=000000>**RESULTSB**</td>

                <td nowrap><font size= "-1" color=000000>**RESULTSB**</td>
                <td nowrap><font size= "-1" color=000000>**RESULTSB**</td>

                <td nowrap><font size= "-1" color=000000> </td>
                <td nowrap><font size= "-1" color=000000>**RESULTSB**</td>
                <td nowrap><font size= "-1" color=000000> </td>

            <tr>

            <tr >

                <td nowrap><font size= "-1" color=000000>**RESULTSC**</td>
                <td nowrap><font size= "-1" color=000000>**RESULTSC**</td>
                <td nowrap><font size= "-1" color=000000>**RESULTSC**</td>

                <td nowrap><font size= "-1" color=000000>**RESULTSC**</td>
                <td nowrap><font size= "-1" color=000000>**RESULTSC**</td>
                <td nowrap><font size= "-1" color=000000>**RESULTSC**</td>
                <td nowrap><font size= "-1" color=000000>**RESULTSC**</td>
                <td nowrap><font size= "-1" color=000000>**RESULTSC**</td>

                <td nowrap><font size= "-1" color=000000>**RESULTSC**</td>
                <td nowrap><font size= "-1" color=000000>**RESULTSC**</td>

                <td nowrap><font size= "-1" color=000000> </td>
                <td nowrap><font size= "-1" color=000000>**RESULTSC**</td>
                <td nowrap><font size= "-1" color=000000> </td>

            <tr>
</TABLE></TD></TR>
</TABLE></TD></TR>
</TABLE>
</Center>
"@

然后我使用RegEx查找上面提到的特定字符串,并抓取所有内容到下一个</table>标记。

[regex]$regex = '(?s)<table width="100%" cellpadding="5" .*?</TABLE>'
$tables = $regex.matches($Sample).groups.value

之后,我将其拆分为<tr>标签以获取单独的行。

ForEach($String in $tables){
    $TableRows = $string -split '<tr.*?>'

接下来的三位都是我在变量中捕获的一行。

首先在每一行我查找列或标题,然后我用逗号加入它们。

$CurTable = $TableRows | ForEach-Object{$_ -split "(?s)</T(?:D|H)>.*?<T(?:D|H).*?>" -join ","

然后我替换了剩余的<TD></TD><TH></TH>标记,以删除任何前导或尾随标记。我还删除了<font>标签以保持清洁,以及任何换行符,因为任何单个给定行应该只有一行。

-replace "<(/?T(D|H|R|ABLE)|font).*?>" -replace "[\r\n]"

然后从行的开头或结尾修剪任何空格或逗号,并仅输出在其上有文本的行,我们实际上最终得到一个非常标准的CSV。

| ForEach-Object{$_.Trim(' ,')} | ?{![string]::IsNullOrWhiteSpace($_)}

拥有CSV后,您可以轻松地将其转换为对象,只选择所需的属性,然后导出为CSV,或使用Out-GridView,如果只是Format-Table,则只需 If($CurTable -is [array]){ $CurTable |ConvertFrom-Csv|Select 'HEADER1','HEADER2','HEADER3','HEADER6','HEADER7' #|Export-Csv "C:\Path\To\Output\Results.csv" -NoTypeInformation }Else{ $CurTable } } 想看文字。或者过滤结果......使用那里的数据非常容易。

现在,有可能没有结果,在这种情况下,你最终得到的只是一个字符串,而不是一个CSV。我所做的是为了检查结果是否是一个数组。如果是数组,则需要使用数据。如果它不是数组,则结果表中没有任何内容,我选择将其输出到屏幕。以下是我处理的方法:

[regex]$regex = '(?s)<table width="100%" cellpadding="5" .*?</TABLE>'
$tables = $regex.matches($Sample).groups.value
ForEach($String in $tables){
    $TableRows = $string -split '<tr.*?>'
    $CurTable = $tablerows|%{$_ -split "(?s)</T(?:D|H)>.*?<T(?:D|H).*?>" -join "," -replace "<(/?T(D|H|R|ABLE)|font).*?>" -replace "[\r\n]"} | ForEach-Object{$_.Trim(' ,')} | ?{![string]::IsNullOrWhiteSpace($_)}
    If($CurTable -is [array]){
        $CurTable |ConvertFrom-Csv|Select 'HEADER1','HEADER2','HEADER3','HEADER6','HEADER7' #|Export-Csv "C:\Path\To\Output\Results.csv" -NoTypeInformation
    }Else{
        $CurTable
    }
}

我的回答很长,但实际的功能代码归结为:

HEADER1 : **RESULTSA**
HEADER2 : **RESULTSA**
HEADER3 : **RESULTSA
HEADER6 : **RESULTSA**
HEADER7 : **RESULTSA**

HEADER1 : **RESULTSB**
HEADER2 : **RESULTSB**
HEADER3 : **RESULTSB**
HEADER6 : **RESULTSB**
HEADER7 : **RESULTSB**

HEADER1 : **RESULTSC**
HEADER2 : **RESULTSC**
HEADER3 : **RESULTSC**
HEADER6 : **RESULTSC**
HEADER7 : **RESULTSC**

这将导致:

PagesController

希望这足以让你合作以获得你需要的东西。