2016-10-07 31 views
1

我試圖解析一個網站來收集價格和產品的詳細信息。該腳本在循環中工作,但速度很慢。所以我試圖運行一個多線程PowerShell腳本作爲一項工作。Powershell - foreach數組作爲作業(本地/多線程)

我已經嘗試了很多的建議,但我努力得到的結果出來,即使我可以看到它的工作(網頁請求屏幕閃爍起來)

我只選擇最後的10但我稍後會加油門。只是無法讓它輸出。基本上我想所有的結果都回到$ arr。


#Import Danmurphy Sitelist 
[xml] $XmlDocument = (New-Object System.Net.WebClient).DownloadString("http://www.example.com/sites.xml") 

#get websites listed 
$ImportedProducts = $XmlDocument.DocumentElement.url | select -Last 10 

"Killing existing jobs . . ." 
Get-Job | Remove-Job -Force 
"Done." 

#loop through the products 

#Create Array 
$arr = @() 

#$argumentlist 

#ScriptBlock 
$ScriptBlock = { 
Param($product,$arr) 

if ($product.loc -like "http://www.example.com/product/*"){ 

$uri = $product.loc 
$WebResponse = Invoke-WebRequest -Uri $uri -SessionVariable WS 


#mainpricetest 
$mainprice = $WebResponse.AllElements | ? { $_.Class -eq 'price-main' } | select innerText 

$MainPriceArray = $mainprice.innerText.Split(' ') 

$MainUnitArry = $MainPriceArray[1..10] 

$MainDollar = $MainPriceArray[0] 

$MainUnit = $MainUnitArry -join ' ' 


$item = New-Object PSObject 
$item | Add-Member -type NoteProperty -Name 'Product Site' -Value $($product.loc) 
$item | Add-Member -type NoteProperty -Name 'Main Price' -Value $($MainDollar) 
$item | Add-Member -type NoteProperty -Name 'Main Unit' -Value $($MainUnit) 



$arr += $item 

} 
} 

foreach ($product in $ImportedProducts){ 
Start-Job -InputObject $ImportedProducts -ScriptBlock $ScriptBlock -ArgumentList $product,$arr 
} 

$data = Get-Job * | Receive-Job 

#Show Array 
$arr 
+0

爲什麼不直接從scriptblock中移除'$ arr + = $ item'並用'$ data'捕獲輸出? – Matt

回答

1

所以,你可能需要使用該運行空間。運行空間是一件非常複雜的事情,幸運的是我們有Posh-RSJob,它可以爲你處理所有事情。 https://github.com/proxb/PoshRSJob

您可以傳遞腳本塊,因此您只需要很少的調整。 大概是這樣的:

foreach ($product in $ImportedProducts){ 
    Start-RSJob -ScriptBlock $ScriptBlock 
} 
Get-RSjob | Receive-RSJob 
+0

我已經有很好的標記這項工作,但我似乎無法得到輸出。有更多的數據總是假的。 我試圖按照Bill Hurt的建議添加寫輸出$項。 '啓動RSJob -InputObject $ ImportedProducts -ScriptBlock $腳本塊-ArgumentList $產品-Throtle' 和 '不要{$ ARR + = GET-RSJob -State完成| Receive-RSJob } while(Get-RSJob -State Running)' –

+1

廢棄。看起來像RSJobs只需要在管道中使用。 謝謝,這工作: '$ ImportedProducts | foreach {Start-RSJob -ScriptBlock $ ScriptBlock -ArgumentList $ _ -Throttle 10} do { $ arr + = Get-RSJob -State Completed | Receive-RSJob Get-RSJob-狀態已完成| Remove-RSJob } while(Get-RSJob -State Running) ' –

1

如果你想要得到的結果爲$改編,你不能從腳本塊內,你試圖做這樣做。並行運行的多個腳本塊不允許訪問變量的單個副本,而無需執行不值得進入的其他步驟。

您的問題的答案是將每個腳本塊的輸出寫爲常規輸出。該輸出將被緩存,直到您使用Receive-Job將結果從作業中取出,然後以單線程方式將其捕獲到$ arr變量中。下面是鱈魚應該讓你在那裏的大部分方式。

#Import Danmurphy Sitelist 
[xml] $XmlDocument = (New-Object System.Net.WebClient).DownloadString("http://www.example.com/sites.xml") 

#get websites listed 
$ImportedProducts = $XmlDocument.DocumentElement.url | select -Last 10 

"Killing existing jobs . . ." 
Get-Job | Remove-Job -Force 
"Done." 

#loop through the products 

#Create Array 
$arr = @() 

#$argumentlist 

#ScriptBlock 
$ScriptBlock = { 
    Param($product) 

    if ($product.loc -like "http://www.example.com/product/*"){ 

    $uri = $product.loc 
    $WebResponse = Invoke-WebRequest -Uri $uri -SessionVariable WS 


    #mainpricetest 
    $mainprice = $WebResponse.AllElements | ? { $_.Class -eq 'price-main' } | select innerText 

    $MainPriceArray = $mainprice.innerText.Split(' ') 

    $MainUnitArry = $MainPriceArray[1..10] 

    $MainDollar = $MainPriceArray[0] 

    $MainUnit = $MainUnitArry -join ' ' 


    $item = New-Object PSObject 
    $item | Add-Member -type NoteProperty -Name 'Product Site' -Value $($product.loc) 
    $item | Add-Member -type NoteProperty -Name 'Main Price' -Value $($MainDollar) 
    $item | Add-Member -type NoteProperty -Name 'Main Unit' -Value $($MainUnit) 



    Write-Output $item 

    } 
} 

foreach ($product in $ImportedProducts){ 
    Start-Job -InputObject $ImportedProducts -ScriptBlock $ScriptBlock -ArgumentList $product 
} 

do { 
    $arr += Get-Job -State Completed | Receive-Job -AutoRemoveJob 
} while (Get-Job -State Running) 

#Show Array 
$arr 
+0

謝謝你的工作! –