2

我在 PowerShell 中编写了一些屏幕抓取代码,并惊讶地发现解析几个 HTML 表格需要大约 30 秒。我把它剥离出来,试图找出所有时间都花在了哪里,它似乎在getElementsByTagName通话中。

我在下面包含了一个脚本,在我的家庭桌面、工作桌面和家庭平板上,每次迭代大约需要 1-2 秒(完整结果粘贴在下面)。但是,PowerShell 社区中的其他人报告的时间要短得多(每次迭代只有几毫秒)。

我正在努力寻找缩小问题范围的任何方法,而且 OS/PS/.NET/IE 版本似乎没有模式。

我目前正在运行它的桌面是全新的 Windows 8 安装,仅安装了 PS3 和 .NET 4.5(以及所有 Windows 更新补丁)。没有 Visual Studio。没有 PowerShell 配置文件。

$url = "http://www.icy-veins.com/restoration-shaman-wow-pve-healing-gear-loot-best-in-slot"
$response = (iwr $url).ParsedHtml

# Loop through the h2 tags
$response.body.getElementsByTagName("h2") | foreach {

    # Get the table that comes after the heading
    $slotTable = $_.nextSibling

    # Grab the rows from the table, skipping the first row (column headers)
    measure-command { $rows = $slotTable.getElementsByTagName("tr") | select -Skip 1 } | select TotalMilliseconds
}

来自我的桌面的结果(工作 PC 和 slate 给出几乎相同的结果):

TotalMilliseconds
-----------------
        1575.7633
        2371.5566
        1073.7552
        2307.8844
        1779.5518
        1063.9977
        1588.5112
        1372.4927
        1248.7245
        1718.3555
         3283.843
        2931.1616
        2557.8595
        1230.5093
         995.2934

但是,Google+ PowerShell 社区中的一些人报告了这样的结果

 TotalMilliseconds
 -----------------
           76.9098
          112.6745
           56.6522
          140.5845
           84.9599
           48.6669
           79.9283
           73.4511
           94.0683
           81.4443
           147.809
          139.2805
          111.4078
           56.3881
           41.3386

我已经尝试过 PowerShell ISE 和标准控制台,没有区别。对于正在做的工作,这些时间似乎有点过时,从Google+ 社区的帖子来看,它可以走得更快!

4

3 回答 3

5

您是否尝试禁用进度?

$ProgressPreference = "SilentlyContinue"

就我而言,这解决了严重的性能问题Invoke-WebRequest

于 2013-12-20T10:29:30.940 回答
5

请参阅我的评论:https ://connect.microsoft.com/PowerShell/feedback/details/778371/invoke-webrequest-getelementsbytagname-is-incredibly-slow-on-some-machines#tabs

我在 64 位运行脚本时遇到了同样的缓慢,但是在 32 位模式下运行时,一切都非常快!

Lee Holmes 能够重现该问题,这是他的文章

“问题是他正在将 COM 对象通过管道传送到另一个 cmdlet——在本例中为 Select-Object。发生这种情况时,我们会尝试按属性名称绑定参数。枚举 COM 对象的属性名称非常慢——所以我们正在花费我们将 86% 的时间用于两个非常基本的 CLR API 调用:

(...) // 从 COM 类型中获取函数描述 typeinfo.GetFuncDesc(index, out pFuncDesc); (…) // 从 COM 函数描述中获取函数名 typeinfo.GetDocumentation(funcdesc.memid, out strName, out strDoc, out id, out strHelp); (……)

我们也许可以在这里用缓存做一些聪明的事情。

一种解决方法是不通过管道进入 Select-Object,而是使用语言功能:

# Grab the rows from the table, skipping the first row (column headers)
$allRows = @($slotTable.getElementsByTagName("tr"))
$rows = $allRows[1..$allRows.Count]

"

于 2014-03-10T03:33:05.577 回答
0

我在新的 Windows 8 系统上注意到了同样的现象。我有一个 104MB 的文件存储在远程 Web 服务器上,下载需要 2 到 5 分钟,具体取决于服务器负载、带宽等。通过 FF、IE10、Chrome、cURL 进行了尝试,甚至设置了一个测试 FTP 服务器并尝试了Windows FTP 命令。我一直得到相同的结果。

然而,同一个文件(这并不夸张)需要将近 3 HOURS 才能传输。

$file = 'C:\User\me\Desktop\file.mp4'
$site = 'http://my.site/file.mp4'
Invoke-WebRequest $site -Method Get -OutFile $file

看起来很简单——站点不是 https,文件不是可执行文件或 Windows 可能认为“不安全”的任何东西,并且不需要身份验证。它只需要永远完成。

我认为我的 AV 的实时扫描可能是罪魁祸首,但禁用它并没有明显的区别。这里可能有一些内存分配在起作用吗?类似于如何将 -ReadCount 选项添加到 Get-Content 可以更快地获取大文件的内容?我找不到 Invoke-WebRequest 的任何此类选项。

于 2013-02-02T01:01:02.667 回答