15

我正在尝试编写一个 PowerShell 脚本来从网站上获取所有名为“newstitle”的类中的文本。

这就是我所拥有的:

function check-krpano {
    $geturl=Invoke-WebRequest http://krpano.com/news/
    $news=$geturl.parsedhtml.body.GetElementsByClassName("newstitle")[0]
    Write-Host  "$news"
}

check-krpano

它显然需要更多的调整,但到目前为止,它不起作用。

我设法使用 GetElementById 编写了一个脚本,但我不知道 GetElementsByClassName 的语法,老实说,我还没有找到很多关于它的信息。

笔记:

我已经勾选了我的问题的正确答案,但这不是我选择在我的脚本中使用的解决方案。

尽管我能够使用 2 种方法在包含某个类的标签中找到内容,但它们比搜索链接要慢得多。

这是使用 Measure-Command 的输出:

  • 使用 parsedhtml.body -> 29.6 秒搜索包含类“newstitle”的 div
  • 使用 Allelements -> 10.4 秒搜索包含类“newstitle”的开发人员
  • 搜索其元素“href”包含#news -> 2.4 秒的链接

因此,我将 Links 方法答案标记为有用。

这是我的最终脚本:

function check-krpano {
    Clear-Host
    $geturl=Invoke-WebRequest http://krpano.com/news
    $news = ($geturl.Links |Where href -match '\#news\d+' | where class -NotMatch 'moreinfo+' )
    $news.outertext | Select-Object -First 5
}

check-krpano
4

5 回答 5

21

如果您知道如何让 GetElementsByClassName 工作,我想知道。我昨天刚遇到这个,没时间了,所以我想出了一个解决方法:

$geturl.ParsedHtml.body.getElementsByTagName('div') | 
    Where {$_.getAttributeNode('class').Value -eq 'newstitle'}
于 2013-07-13T00:13:04.820 回答
19

getElementsByClassName不直接返回数组,而是通过 COM 代理结果。正如您所发现的,操作员不会自动转换为数组[]。您可以使用列表评估语法 ,@()首先将其强制为数组,以便您可以访问单个元素:

@($body.getElementsByClassName("foo"))[0].innerText

顺便说一句,如果您使用对象管道,则会自动执行转换,例如:

$body.getElementsByClassName("foo") | Select-Object -First 1

它也通过foreach构造自动执行:

foreach ($element in $body.getElementsByClassName("foo"))
{
    $element.innerText
}
于 2014-03-01T15:08:54.253 回答
3

在我的一生中,也不能让这种方法起作用!

不过,这取决于您在结果中需要什么,这可能会有所帮助;

function check-krpano {
$geturl=Invoke-WebRequest http://krpano.com/news

$news=($geturl.Links|where href -match '\#news\d+')[0]

$news

}

check-krpano

还给我:

innerHTML : krpano 1.16.5 released
innerText : krpano 1.16.5 released
outerHTML : <A href="#news1165">krpano 1.16.5 released</A>
outerText : krpano 1.16.5 released
tagName   : A
href      : #news1165

当然,您可以直接使用这些属性,所以如果您只想知道最新发布的 krpano 版本,可以这样做:

function check-krpano {
$geturl=Invoke-WebRequest http://krpano.com/news

$news=($geturl.Links|where href -match '\#news\d+')[0]

$krpano_version = $news.outerText.Split(" ")[1]

Write-Host $krpano_version

}

check-krpano

1.16.5在撰写本文时返回。

希望能实现你想要的,尽管方式不同。

编辑:

这可能比通过 select-object 管道快一点:

function check-krpano {
$geturl=Invoke-WebRequest http://krpano.com/news  

($geturl.Links|where href -match '\#news\d+'|where class -notmatch 'moreinfo+')[0..4].outerText  

}
于 2013-07-13T00:46:07.730 回答
1

我意识到这是一个老问题,但我想为其他可能试图通过使用 COM 对象控制 Internet Explorer 来实现相同目标的人添加一个答案,如下所示:

$ie = New-Object -com internetexplorer.application
$ie.navigate($url)
while ($ie.Busy -eq $true) { Start-Sleep -Milliseconds 100; }

我通常更喜欢像原始海报那样使用 Invoke-WebRequest,但我发现我似乎需要一个完整的 IE 实例才能看到所有 JavaScript 生成的 DOM 元素,即使我期望 parsedhtml .body 包括它们。

我发现我可以做这样的事情来通过类名获取元素集合:

$titles = $ie.Document.body.getElementsByClassName('newstitle')
foreach ($storyTitle in $titles) {
     Write-Output $storyTitle.innerText
}

在使用 PowerShell 搜索 DOM 时,我观察到原始发帖人指出的同样非常缓慢的性能,但是使用 PowerShell 3.0 和 IE11,Measure-Command 显示我的类集合在 280 毫秒内可以在 125 KB HTML 文档中找到。

于 2017-08-03T01:12:14.973 回答
0

它似乎适用于 PowerShell 5.1:

function check-krpano {
    $geturl = Invoke-WebRequest -Uri "http://krpano.com/news/"
    $news = $geturl.ParsedHtml.body.getElementsByClassName("newstitle")
    Write-Host "$($news[0].innerHTML)"
}

check-krpano

输出:

<A href="#news1206">krpano 1.20.6</A><SPAN class=smallcomment style="FLOAT: right"><A href="https://krpano.co
m/forum/wbb/index.php?page=Thread&amp;postID=81651#post81651"><IMG class=icon16m src="../design/ico-forumlink
.png"> krpano Forum Link</A></SPAN>
于 2020-05-10T13:30:05.110 回答