Encoding 为什么PowerShell会在抓取的HTML中损坏非ASCII字符?

Encoding 为什么PowerShell会在抓取的HTML中损坏非ASCII字符?,encoding,web-scraping,powershell-3.0,Encoding,Web Scraping,Powershell 3.0,我正在从维基百科收集机场信息。我想保留机场名称中的非ASCII字符 在web浏览器中,浏览器的外观如下所示: function Get-Airports ($Uri) { Invoke-WebRequest -Uri $Uri -UseBasicParsing | Select-Xml -XPath '//table/tr[td]' | % { $Kids = $_.Node.ChildNodes [PSCustomObject] @{ Iata = $K

我正在从维基百科收集机场信息。我想保留机场名称中的非ASCII字符

在web浏览器中,浏览器的外观如下所示:

function Get-Airports ($Uri) {
  Invoke-WebRequest -Uri $Uri -UseBasicParsing |
  Select-Xml -XPath '//table/tr[td]' |
  % {
    $Kids = $_.Node.ChildNodes
    [PSCustomObject] @{
      Iata = $Kids[0].InnerText
      Icao = $Kids[1].InnerText
      AirportName = $Kids[2].InnerText
      LocationServed = $Kids[3].InnerText
    }
  }
}
$Airports = Get-Airports 'http://en.wikipedia.org/wiki/List_of_airports_by_IATA_code:_Z'
<title>國際民航組織機場代碼 (Z) - 维基百科,自由的百科全书</title>
<title>?????????????????????????????? (Z) - ????????????????????????????????????</title>

DBE机场被称为“多尔尼贝尼索夫机场”。ZBK机场被称为“阿布贾克机场”。我希望输出中的值相同

我使用如下函数来抓取数据:

function Get-Airports ($Uri) {
  Invoke-WebRequest -Uri $Uri -UseBasicParsing |
  Select-Xml -XPath '//table/tr[td]' |
  % {
    $Kids = $_.Node.ChildNodes
    [PSCustomObject] @{
      Iata = $Kids[0].InnerText
      Icao = $Kids[1].InnerText
      AirportName = $Kids[2].InnerText
      LocationServed = $Kids[3].InnerText
    }
  }
}
$Airports = Get-Airports 'http://en.wikipedia.org/wiki/List_of_airports_by_IATA_code:_Z'
<title>國際民航組織機場代碼 (Z) - 维基百科,自由的百科全书</title>
<title>?????????????????????????????? (Z) - ????????????????????????????????????</title>
该函数获取给定的URI,隐式地将HTML响应转换为XML,使用XPath提取表数据行,然后将每个列值映射到新PowerShell对象的属性

要获取以Z开头的所有机场,我使用如下命令:

function Get-Airports ($Uri) {
  Invoke-WebRequest -Uri $Uri -UseBasicParsing |
  Select-Xml -XPath '//table/tr[td]' |
  % {
    $Kids = $_.Node.ChildNodes
    [PSCustomObject] @{
      Iata = $Kids[0].InnerText
      Icao = $Kids[1].InnerText
      AirportName = $Kids[2].InnerText
      LocationServed = $Kids[3].InnerText
    }
  }
}
$Airports = Get-Airports 'http://en.wikipedia.org/wiki/List_of_airports_by_IATA_code:_Z'
<title>國際民航組織機場代碼 (Z) - 维基百科,自由的百科全书</title>
<title>?????????????????????????????? (Z) - ????????????????????????????????????</title>
$Airports
变量包含新PowerShell对象的集合,表中的每个数据行对应一个

此命令显示刮板会损坏包含非ASCII字符的名称:

$Airports |
? { $_.AirportName -like '*[?]*' } |
Format-Table
机场名称中不应包含问号。我希望这个命令不会产生任何输出

相反,有几个对象的名称中有两个问号,其中一个非ASCII字符将出现在web浏览器中:

Iata  Icao   AirportName                              LocationServed                                               
----  ----   -----------                              --------------                                               
ZBE   LKZA   Doln?? Benesov Airport                   Z??b??eh, Czech Republic                                     
ZBK          ??abljak Airport                         ??abljak, Montenegro                                         
ZBM   CZBM   Bromont (Roland D??sourdy) Airport       Bromont, Quebec, Canada                                      
ZLG          La G??era Airport                        La G??era, Western Sahara                                    
ZLT          La Tabati??re Airport (TC: CTU5)         La Tabati??re, Quebec, Canada                                
ZOS   SCJO   Ca??al Bajo Carlos Hott Siebert Airport  Osorno, Chile                                                
ZPC   SCPC   Puc??n Airport                           Puc??n, Chile                                                
ZQW   EDRZ   Zweibr??cken Airport                     Zweibr??cken, Germany                                        
ZTB          T??te-??-la-Baleine Airport (TC: CTB6)   T??te-??-la-Baleine, Quebec, Canada     
这当然是一个字符编码问题。Wikipedia生成了一个新的字符集,但看起来PowerShell正在将其解码为或其他一些单字节字符集

我在cmdlet或cmdlet上找不到允许我指定UTF-8的开关

有没有简洁的方法来解决这个问题?任何方法都可以,但我认为我缺少一件简单的事情。

简短回答:使用Content属性 在Get Airports中,将管道的开头替换为以下表达式:

(Invoke-WebRequest -Uri $Uri -UseBasicParsing).Content
该函数将产生预期的结果

没有带问号的机场名称

详细回答:Invoke WebRequest有故障 Invoke WebRequest返回的实例。它的ToString方法破坏了响应内容

中国机场列表中充满了非ASCII字符,因此提供了一个很好的测试用例。此代码通过Content属性和ToString方法刮取该页面并提取标题:

$uri = 'http://zh.wikipedia.org/wiki/國際民航組織機場代碼_(Z)'
$response = (Invoke-WebRequest -Uri $uri -UseBasicParsing)
$pattern = '\<title\>.+\</title\>'
[Regex]::Match($response.Content, $pattern).Value
[Regex]::Match($response.ToString(), $pattern).Value
该方法可自动检测正确的解码

BasicHtmlWebResponseObject从WebResponseObject开始执行以下操作:

// Microsoft.PowerShell.Commands.WebResponseObject
public sealed override string ToString()
{
    char[] chars = Encoding.ASCII.GetChars(this.Content);
    for (int i = 0; i < chars.Length; i++)
    {
        if (!this.IsPrintable(chars[i]))
        {
            chars[i] = '.';
        }
    }
    return new string(chars);
}
//Microsoft.PowerShell.Commands.WebResponseObject
公共密封重写字符串ToString()
{
char[]chars=Encoding.ASCII.GetChars(this.Content);
for(int i=0;i