如何使用PowerShell解析网站的HTML

10

我正在尝试检索有关网站的一些信息,我想查找特定的标签/类,然后返回包含的文本值(innerHTML)。这是到目前为止我所拥有的代码:

$request = Invoke-WebRequest -Uri $url -UseBasicParsing
$HTML = New-Object -Com "HTMLFile"
$src = $request.RawContent
$HTML.write($src)


foreach ($obj in $HTML.all) { 
    $obj.getElementsByClassName('some-class-name') 
}

我认为将HTML转换为HTML对象存在问题,因为当我尝试“Select-Object”时,看到了许多未定义的属性和空结果。

所以,在花费两天时间后,我该如何使用PowerShell解析HTML呢?

既然使用正则表达式解析HTML是一个大忌,那么我应该怎么做呢?似乎什么都不起作用。


1
看看HTMLAgility nuget包。它是原始的.NET,但在处理HTML时会极大地帮助你。 - Maximilian Burszley
3个回答

9

由于没有其他人发布答案,我用以下代码得到了一个可行的解决方案:

$request = Invoke-WebRequest -Uri $URL -UseBasicParsing
$HTML = New-Object -Com "HTMLFile"
[string]$htmlBody = $request.Content
$HTML.write([ref]$htmlBody)
$filter = $HTML.getElementsByClassName($htmlClassName)

有些网址中,$filter变量为空,而其他网址中则为非空。总的来说,这对您的情况可能有效,但似乎PowerShell不适合于更复杂的解析。


4
我想指出,这个解决方案仅适用于部署在Windows上的PowerShell。COM对象通常在PowerShell v7.x.x中不可用。 - KUTlime
如果.write()抛出错误,请使用此答案 - stackprotector

5

在 PowerShell 5+ 中,您可以这样做:

$searchClass = "banana" <# in this example we parse all elements of class "banana" but you can use any class name you wish #>
$myURI = "url.com" <# replace url.com with any website you want to scrape from #>

[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 <# using TLS 1.2 is vitally important #>
$req = Invoke-Webrequest -URI $myURI
$req.ParsedHtml.getElementsByClassName($searchClass) | %{Write-Host $_.innerhtml}

#for extra credit we can parse all the links
$req.ParsedHtml.getElementsByTagName('a') | %{Write-Host $_.href} #outputs all the links


非常感谢。我刚刚修正了一个错误。应该是 innerHTML 而不是 innterHTML - Krzysztof Madej
当我查询 IHTMLDocument2 时,我只看到了两个方法,write 和 close。 getElementsByClassName 是在哪里声明的?我如何查找可用于 ParsedHtml 属性的其他方法? - silicontrip
15
很抱歉,2020年使用PowerShell 7.0.3时,这个功能不起作用。回应("$req")将没有名为ParsedHtml的属性。这是仅限于PowerShell经典版的功能吗? - Chris
尝试: $req = Invoke-Webrequest -URI $myURI -usebasicparsing - Ben R
2
@BenR:“此参数已被弃用。从PowerShell 6.0.0开始,所有Web请求仅使用基本解析。此参数仅包含向后兼容性,任何使用它都不会影响cmdlet的操作。” - N. I.

1
如果安装第三方模块是一个选择的话:
  • PSParseHTML模块封装了HTML Agility PackAngleSharp .NET库(NuGet包);您可以使用其中任何一个进行HTML解析;后者需要选择使用-Engine AngleSharp;至于它们各自的DOM(对象模型)

    • HTML Agility Pack是默认使用的,它提供了一个与标准System.Xml.XmlDocument .NET类型([xml])提供的类似于XML DOM的对象模型。请参考此答案以了解其使用示例。

    • AngleSharp需要通过-Engine AngleSharp选择使用,它基于官方的W3C规范,因此提供了与Web浏览器中可用的HTML DOM相同的功能。特别值得注意的是,这意味着它的.QuerySelector().QuerySelectorAll()方法可以使用通常的CSS选择器,如下所示。

  • 使用此模块的另一个优点是它不仅跨版本,而且跨平台;也就是说,您可以在Windows PowerShell以及PowerShell (Core) 7+中使用它,并且通过后者还可以在类Unix平台上使用。


一个基于AngleSharp引擎的自包含示例,它解析英文维基百科的首页,并提取所有HTML元素,其class属性值为vector-menu-content-list。
# Install the PSParseHTML module on demand
If (-not (Get-Module -ErrorAction Ignore -ListAvailable PSParseHTML)) {
  Write-Verbose "Installing PSParseHTML module for the current user..."
  Install-Module -Scope CurrentUser PSParseHTML -ErrorAction Stop
}

# Using the AngleSharp engine, parse the home page of the English Wikipedia
# into an HTML DOM.
$htmlDom = ConvertFrom-Html -Engine AngleSharp -Url https://en.wikipedia.org

# Extract all HTML elements with a 'class' attribute value of 'vector-menu-content-list'
# and output their text content (.TextContent)
$htmlDom.QuerySelectorAll('.vector-menu-content-list').TextContent

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接