如何从HTML表中提取特定值并使用PowerShell将它们水平复制到文件中?

时间:2014-11-17 23:55:08

标签: html regex powershell

代码

select-string -Path "input.txt" -Pattern '<td>[A-Z][a-z]+' -AllMatches | % { $_.Matches } | % { $_.Value } > 'outcome.txt'

select-string -Path "input.txt" -Pattern '\d+K' -AllMatches | % { $_.Matches } | % { $_.Value } > 'outcome2.txt'

输入

<table>
  <tr>
    <th>City</th>
    <th>Population</th>
  </tr>
  <tr>
    <td>Amsterdam</td>
    <td>900K</td>
  </tr>
  <tr>
    <td>Rotterdam</td>
    <td>700K</td>
  </tr>
  <tr>
    <td>The Hague</td>
    <td>500K</td>
  </tr>
  <tr>
    <td>Utrecht</td>
    <td>300K</td>
  </tr>  
</table>

当前结果

outcome.txt

<td>Amsterdam
<td>Rotterdam
<td>The
<td>Utrecht

outcome2.txt

900K
700K
500K
300K

预期结果

Amsterdam 900K
Rotterdam 700K
The Hague 500K
Utrecht 300K

问题

水平显示

首先,outcome.txt和outcome2.txt的结果可以手动合并,但这是一个示例,实际文件包含数千行和100多列。

特定提取

其次,实际的正则表达式会更广泛,行可以包含超过500个字符,并且应该进行特定的正则表达式,例如,在<td>Utrecht</td>的情况下,预期结果为Utrecht而不是<td>Utrecht

更新

foreach ($line in [System.IO.File]::ReadLines("input.txt")) {
#  if ($line -match '<td>(.*)</td>\n<td>(\d+)</td>') {
  if ($line -match '<td>(.*)(</td>)') {  
     $matches[1] + $matches[2]
  }  
}

结果:

Amsterdam</td>
900K</td>
Rotterdam</td>
700K</td>
The Hague</td>
500K</td>
Utrecht</td>
300K</td>

目前的问题是out-commented \n与第二行不匹配,而测试表明可以使用第二个括号提取第二个元素。

1 个答案:

答案 0 :(得分:2)

要有另一种方法,已经有人创建了cmdlet,通过将表转换为对象来为您完成艰苦的工作。从荣誉PowerShell Code Repository到Joel Bennett。

function ConvertFrom-Html {
   #.Synopsis
   #   Convert a table from an HTML document to a PSObject
   #.Example
   #   Get-ChildItem | Where { !$_.PSIsContainer } | ConvertTo-Html | ConvertFrom-Html -TypeName Deserialized.System.IO.FileInfo
   #   Demonstrates round-triping files through HTML
   param(
      # The HTML content
      [Parameter(ValueFromPipeline=$true)]
      [string]$html,

      # A TypeName to inject to PSTypeNames 
      [string]$TypeName
   )
   begin { $content = "$html" }
   process { $content += "$html" }
   end {
      [xml]$table = $content -replace '(?s).*<table[^>]*>(.*)</table>.*','<table>$1</table>'

      $header = $table.table.tr[0]  
      $data = $table.table.tr[1..1e3]

      foreach($row in $data){ 
         $item = @{}

         $h = "th"
         if(!$header.th) {
            $h = "td"
         }
         for($i=0; $i -lt $header.($h).Count; $i++){
            if($header.($h)[$i] -is [string]) {
               $item.($header.($h)[$i]) = $row.td[$i]
            } else {
               $item.($header.($h)[$i].InnerText) = $row.td[$i]
            }
         }
         Write-Verbose ($item | Out-String)
         $object = New-Object PSCustomObject -Property $item 
         if($TypeName) {
            $Object.PSTypeNames.Insert(0,$TypeName)
         }
         Write-Output $Object
      }
   }
}

使用您的表数据作为输入,上面输出以下内容:

Get-Content "input.txt" | ConvertFrom-Html

City      Population
----      ----------
Amsterdam 900K      
Rotterdam 700K      
The Hague 500K      
Utrecht   300K    

这应该更容易使用,具体取决于你要去的地方....比如说Export-CSV或者其他类似东西。以数据为对象,您几乎可以去任何地方。