Encoding 为什么PowerShell会在抓取的HTML中损坏非ASCII字符?
我正在从维基百科收集机场信息。我想保留机场名称中的非ASCII字符 在web浏览器中,浏览器的外观如下所示: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
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
WebResponseObject的ToString方法天真地将响应解码为ASCII
默认情况下,使用替换回退为未知字节生成问号
我在这里没有看到任何文档,但我认为selectxml调用ToString将管道对象转换为Xml。这是合理的行为,但在这里不起作用,因为BasicHtmlWebResponseObject的设计中存在错误
我猜是Windows-1252解码,因为它是我的默认代码页。但这不可能;字符
í
在Windows-1252中有编码,但在输出中被?
替换。使用默认值时,您可能需要使用底层.NET类型和方法来1。将web请求的结果视为字节序列2。使用HTTP响应头确定编码和3。在解析为XML之前,使用该编码转换为字符串。(即,我假设没有指定编码的
头,因此编码不会以字符串形式传递给选择XML
,因此默认值…@Richard哦,亲爱的,我希望不会。不妨选择C。@Richard这毕竟是一个C#问题,但不是一个我可以轻松解决的问题!请参阅我在Microsoft Connect上提出的问题。: