在脚本中使用GetElementsByClassName

时间:2013-07-12 23:07:27

标签: powershell

我正在尝试编写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搜索包含类'newstitle'的div - > 29.6秒
  • 使用Allelements搜索包含“newstitle”类的开发者 - > 10.4秒
  • 搜索其元素'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

5 个答案:

答案 0 :(得分:18)

如果你弄清楚如何让GetElementsByClassName起作用,我想知道。我昨天碰到了这个并没时间用完,所以我想出了一个解决方法:

$geturl.ParsedHtml.body.getElementsByTagName('div') | 
    Where {$_.getAttributeNode('class').Value -eq 'newstitle'}

答案 1 :(得分:18)

getElementsByClassName不会直接返回数组,而是通过COM代理结果。如您所知,使用[]运算符不能自动转换为数组。您可以使用列表评估语法@()将其强制转换为数组,以便您可以访问各个元素:

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

另外,如果您使用对象管道,则会自动执行转换 ,例如:

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

它也是使用foreach构造自动执行的:

foreach ($element in $body.getElementsByClassName("foo"))
{
    $element.innerText
}

答案 2 :(得分: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  

}

答案 3 :(得分:2)

我意识到这是一个老问题,但我想通过使用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文档中找到。

答案 4 :(得分: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>