【问题标题】:Getting Table from Webpage Powershell从网页 Powershell 获取表格
【发布时间】:2017-01-18 22:15:06
【问题描述】:

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

我尝试过使用Invoke-WebrequestParsedHtml 属性,但这些表没有特定的元素名称或ID,也没有“类”或“标题”标签来区分两者。使用.IHTMLDocument2_all 属性确实显示了几个COMObjects(格式为TypeName: System.__ComObject#{3050f539-98b5-11cf-bb82-00aa00bdce0b}),我觉得我需要以某种方式调用以获得我需要的东西,但我不知道该怎么做。

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

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

<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>

当有结果时,有几个标题在下面显示结果,在这段代码中:

<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>**RESULTS**</td>
                <td nowrap><font size= "-1" color=000000>**RESULTS**</td>
                <td nowrap><font size= "-1" color=000000>**RESULTS</td>

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

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

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

            <tr>

            <tr bgcolor=C0C0C0>

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

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

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

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

            <tr>

            <tr >

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

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

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

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

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

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

【问题讨论】:

  • 你能得到页面的 HTML 吗?您也许可以使用我在this other question 的回答来获取您正在寻找的信息。
  • 能不能给个网址或者给个例子?
  • 恐怕这是一个由我工作的公司设计并专门用于我工作的公司的网站,托管在我们的 Intranet 上,我无法提供完整的网站。但是,我将使用 html 的 sn-p 编辑我的问题
  • @TheMadTechnician 在发布这个问题之前我确实看过这个问题,不幸的是,除了我使用 parsedhtml 得到的唯一 comobjects 之外,我找不到任何表 ID,我终生无法找到我访问
  • 你说有两张桌子。输入表的 HTML 是什么样的,它总是在结果表之前吗?是否总是有一个输入表和一个结果表(即使结果是什么都没有找到)?

标签: html powershell powershell-5.0


【解决方案1】:

好的,所以如果你四处打听,大多数人都会强烈反对使用 RegEx 解析 HTML。他们可能是对的,但我很固执,觉得 RegEx 足够灵活,可以处理某些任务,即使在 HTML 中也是如此。因此,我已将链接问题中的答案调整为我认为对您有用的内容。

这取决于您最内层的表格(包含您要查找的数据)以以下行开头:

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

...并且其中没有嵌入另一个表。所以它相当具体,但它适用于您提供的示例。

我从您的示例中创建了一个此处的字符串:

$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 查找我上面提到的特定字符串,并抓取下一个 &lt;/table&gt; 标记之前的所有内容。

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

之后,我将其拆分为 &lt;tr&gt; 标签以获得单独的行。

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

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

我首先在每一行查找列或标题,并用逗号将它们连接起来。

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

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

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

然后修剪行首或行尾的任何空格或逗号,只输出带有文本的行,我们实际上最终得到了一个非常标准的 CSV。

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

获得 CSV 后,您可以轻松地将其转换为对象,只选择您想要的属性,然后导出为 CSV,或者使用 Out-GridView,如果您只想查看文本。或者过滤结果......从那里处理数据变得非常容易。

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

    If($CurTable -is [array]){
        $CurTable |ConvertFrom-Csv|Select 'HEADER1','HEADER2','HEADER3','HEADER6','HEADER7' #|Export-Csv "C:\Path\To\Output\Results.csv" -NoTypeInformation
    }Else{
        $CurTable
    }
}

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

[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**

希望这足以让您获得所需的东西。

【讨论】:

  • 因此,表单上的另一个表(输入表)确实具有您用于正则表达式语句的相同开启器,但是有一个标题(搜索结果标题)我相信我应该是能够以与您在这里相同的方式使用。我要玩一会儿,看看效果如何。
  • 你在使用这个方法的时候,是不是先用invoke-webrequest访问网站,再用regex,在你的例子中设置webrequest html等于$sample?我对 powershell 还很陌生,我不完全了解您是如何获得结果的
  • 是的,我没有要运行的网页,但您可以使用Invoke-WebRequest 并使用其结果来运行代码,可能使用ParsedHTML 属性。
  • 不幸的是,我似乎仍然遇到了一个奇怪的错误。 '方法调用失败,因为 [Microsoft.PowerShell.Commands.HtmlWebResponseObject] 不包含名为 'op_Subtraction' 的方法。在 line:2 char:1 + $html- $site.content + ~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidOperation: (op_Subtraction:String) [], RuntimeException + FullyQualifiedErrorId : MethodNotFound' 这特别奇怪,因为我没有尝试使用任何方法,如 'op_Subtraction'。
  • 这与我的代码无关,看起来您在某些时候正在运行$html - $site.content。是不是应该是= 而不是-
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-05-21
  • 1970-01-01
  • 2020-02-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多