Имя пользователя:
Пароль:  
Помощь | Регистрация | Забыли пароль?  | Правила  

Компьютерный форум OSzone.net » Программирование, базы данных и автоматизация действий » Скриптовые языки администрирования Windows » PowerShell - [решено] Скрипт парсера потребляет много памяти и не отрабатывает полностью

Ответить
Настройки темы
PowerShell - [решено] Скрипт парсера потребляет много памяти и не отрабатывает полностью

Старожил


Сообщения: 216
Благодарности: 15

Профиль | Отправить PM | Цитировать


Изменения
Автор: Uragan66
Дата: 15-12-2019
Добрый вечер всем!
Прошу помощи у знатоков тонкостей работы PoSh.
Написал парсер, создающий плейлист одного сайта.
Скрипт работает вроде неплохо, правда достаточно долго, но это думаю связано с длительными ответами от сервера.
Но при работе скрипта постоянно растёт память, потребляемая PoSh, доходит почти до 2 ГБ. И в какой-то момент процесс просто вырубается, не доработав до конца.
При запуске через консоль выскакивает какая-то ошибка, но не успеваю её прочитать, так как консоль тут же закрывается.
Если запустить скрипт в ISE, то появляется такая ошибка:

Сам скрипт:
Код: Выделить весь код
$url = 'http://какой-то сайт'
$file = New-TemporaryFile
$d = '#EXTM3U'
(Invoke-WebRequest -UseBasicParsing -Uri $url -TimeoutSec 20).Links.Href | Where {$_ -match "html"} | Sort-Object -Unique `
| ForEach {$_ -replace "(.*html)","http://этот сайт`$1"} | Out-File $file.FullName

Get-Content $file.FullName -Encoding utf8 | ForEach {
$l = Invoke-WebRequest -Uri $_ -TimeoutSec 20
if ($l.Content -notmatch "iframe src") {
$n = ($l.ParsedHtml.getElementsByTagName("title") | select IHTMLTitleElement_text).IHTMLTitleElement_text -replace "(.*) смотреть онлайн прямой эфир","`$1"
$ln = ($l.ParsedHtml.getElementsByTagName("iFrame") | select IHTMLFrameBase_src).IHTMLFrameBase_src
ForEach ($link in $ln) {
((Invoke-WebRequest -UseBasicParsing -URI $link -Headers @{"Referer"="$_"}).Content | Select-String -Pattern 'file:"([^"]+)"' -AllMatches).Matches `
| ForEach-Object {"$($_.Groups[1].Value)"}| ForEach {$_ -replace "(https?.*)","#EXTINF:-1,$n`n`$1"} | Out-File .\parser.txt -Append -Encoding utf8
}
}
else {
$n = ($l.ParsedHtml.getElementsByTagName("title") | select IHTMLTitleElement_text).IHTMLTitleElement_text -replace "(.*) смотреть онлайн прямой эфир","`$1"
$ln = ($l.ParsedHtml.getElementsByTagName("iFrame") | select IHTMLFrameBase_src).IHTMLFrameBase_src
ForEach ($link in $ln) {
((Invoke-WebRequest -UseBasicParsing -URI $link -Headers @{"Referer"="$_"}).Content | Select-String -Pattern 'var videoLink.*(https?[^"]+m3u8)' -AllMatches).Matches `
| ForEach-Object {"$($_.Groups[1].Value)"}| ForEach {$_ -replace "(https?.*)","#EXTINF:-1,$n`n`$1"} | Out-File .\parser.txt -Append -Encoding utf8
}
}
}
$c = Get-Content .\parser.txt -Encoding utf8
Set-Content .\parser.txt -Encoding utf8 -value $d,$c
Подскажите, пожалуйста, где ошибка в моём коде, почему такое большое потребление памяти и преждевременное закрытие процесса.
Заранее благодарен за помощь и советы.

Отправлено: 21:33, 15-12-2019

 

Старожил


Сообщения: 216
Благодарности: 15

Профиль | Отправить PM | Цитировать


Charg, забыл я как-то за Select-Object -Unique.
Сейчас код полностью переписал, работает быстро и утечки памяти больше нет.
Но возникла немного другая проблема. Сервер на некоторые ссылки возвращает 404, наверное из-за частых запросов.
Добавил в цикл Start-Sleep -s 3, но только общее время работы увеличилось, а ошибки 404 встречаются всёравно.

Отправлено: 14:33, 16-12-2019 | #11



Для отключения данного рекламного блока вам необходимо зарегистрироваться или войти с учетной записью социальной сети.

Если же вы забыли свой пароль на форуме, то воспользуйтесь данной ссылкой для восстановления пароля.


Ветеран


Сообщения: 27449
Благодарности: 8086

Профиль | Отправить PM | Цитировать


Цитата Uragan66:
Сервер на некоторые ссылки возвращает 404, наверное из-за частых запросов. »
Не может такого быть. 404 — не найден ресурс. Для «отфутболивания» — HTTP 5xx, обычно 503, 504.

Скорее, ошибки в этих «некоторых» url'ах. Попробуйте сформировать их в файл и проверить «ручками».
Это сообщение посчитали полезным следующие участники:

Отправлено: 17:29, 16-12-2019 | #12


Аватара для Charg

Ветеран


Сообщения: 2798
Благодарности: 469

Профиль | Отправить PM | Цитировать


Я бы добавил проверку на код ответа и если он не 2** (двухсотые это когда всё ок) - писал в stdout содержимое каждой переменной.
Так же не забывай про автоматическую переменную $error и Start\Stop-Transcript
Это сообщение посчитали полезным следующие участники:

Отправлено: 17:30, 16-12-2019 | #13


Старожил


Сообщения: 216
Благодарности: 15

Профиль | Отправить PM | Цитировать


Charg, спасибо!
Действительно некоторые url'ы для вторых запросов формировались неправильно, RegExr глючил... Сейчас исправил, вроде всё нормально.
Нелёгкое дело отладка скрипта

Остался один вопрос нерешенный по данному скрипту.
Подскажите, пожалуйста, есть ли возможность на PoSh указать автоматическую вертикальную прокрутку listbox по мере его заполнения ?
Пробовал добавлять AutoScrollOffset, консоль ругается.

Отправлено: 19:19, 16-12-2019 | #14


Аватара для Charg

Ветеран


Сообщения: 2798
Благодарности: 469

Профиль | Отправить PM | Цитировать


Цитата Uragan66:
Подскажите, пожалуйста, есть ли возможность на PoSh указать автоматическую вертикальную прокрутку listbox по мере его заполнения ? »
Ну, к павершелу это всё имеет отношение довольно формальное.
Быстрый гугл говорит что по-человечески это не сделать, но можно костылями, типа так (не пробовал):

Код: Выделить весь код
$listBox1.SelectedIndex = listBox1.Items.Count - 1
$listBox1.SelectedIndex = -1
Цитата Uragan66:
Действительно некоторые url'ы для вторых запросов формировались неправильно, RegExr глючил... »
Это примерно как "it's always dns" в практически любой сисадминско-виндовой проблеме - если в коде есть регулярки и что-то не работает - почти всегда виноваты регулярки.
Это сообщение посчитали полезным следующие участники:

Отправлено: 19:58, 16-12-2019 | #15


Старожил


Сообщения: 216
Благодарности: 15

Профиль | Отправить PM | Цитировать


Цитата Charg:
но можно костылями, типа так (не пробовал):
Код: Выделить весь код
$listBox1.SelectedIndex = listBox1.Items.Count - 1
$listBox1.SelectedIndex = -1
»
Не хочет так работать, ошибок нет (вернее была, пропущен знак переменной), но и прокрутка стоит на месте...

Отправлено: 20:19, 16-12-2019 | #16


Аватара для Charg

Ветеран


Сообщения: 2798
Благодарности: 469

Профиль | Отправить PM | Цитировать


Uragan66, сначала заполняешь листбокс данными, потом вот этот костыль, а уже потом рисуешь листбокс? Должно быть так, если я правильно понимаю.
Ну либо листбокс - неправильный выбор для задачи которую ты решаешь с помощью листбокса.
Это сообщение посчитали полезным следующие участники:

Отправлено: 20:43, 16-12-2019 | #17


Старожил


Сообщения: 216
Благодарности: 15

Профиль | Отправить PM | Цитировать


Цитата Charg:
листбокс - неправильный выбор для задачи которую ты решаешь с помощью листбокса »
может быть и такое... у меня в листбоксе отображаются значения одной переменной в цикле, после каждой итерации значение этой переменной выводится в листбокс.

Отправлено: 21:13, 16-12-2019 | #18


Ветеран


Сообщения: 27449
Благодарности: 8086

Профиль | Отправить PM | Цитировать


Цитата Uragan66:
Не хочет так работать, ошибок нет (вернее была, пропущен знак переменной), но и прокрутка стоит на месте... »
Uragan66, как бы нужен минимально достаточный код для воспроизведения Вашей ситуации. А «ошибок нет» — это в PoSH'е типичная ситуация сплошь и рядом, это не ЯВУ со строгой типизацией и контролем границ индексов.
Это сообщение посчитали полезным следующие участники:

Отправлено: 21:19, 16-12-2019 | #19


Старожил


Сообщения: 216
Благодарности: 15

Профиль | Отправить PM | Цитировать


Код такой:
Код: Выделить весь код
function GenerateForm {

    [reflection.assembly]::loadwithpartialname("System.Windows.Forms") | Out-Null
    [reflection.assembly]::loadwithpartialname("System.Drawing") | Out-Null

    $form1 = New-Object System.Windows.Forms.Form
    $button1 = New-Object System.Windows.Forms.Button
    $listBox1 = New-Object System.Windows.Forms.ListBox
    $RadioButton = New-Object System.Windows.Forms.RadioButton
    $InitialFormWindowState = New-Object System.Windows.Forms.FormWindowState

    $b1= $false
    $b2= $false
    $b3= $false

#----------------------------------------------
#Generated Event Script Blocks
#----------------------------------------------

    $handler_button1_Click= 
    {
        $listBox1.Items.Clear();    

        if ($RadioButton.Checked) {
            $url = 'http://какой-то сайт/'
            $file = New-TemporaryFile
            $d = '#EXTM3U'
            (Invoke-WebRequest -UseBasicParsing -Uri $url -TimeoutSec 20).Links.Href | Where {$_ -match "html"} | Sort-Object -Unique `
            | ForEach {$_ -replace "(.*html)","http://какой-то сайт`$1"} | Out-File $file.FullName
            $ls = Get-Content $file.FullName -Encoding utf8
            ForEach ($link in $ls){
                $a = Invoke-WebRequest -Uri $link -TimeoutSec 20 -Method GET
                if ($a -notmatch "iframe src") {
                    $a.Content -match '<title>(.*)</title>' | Out-Null
                    $matches[1] | ForEach-Object {[Void]$listbox1.Items.Add($_)}
                    $listBox1.SelectedIndex = $listBox1.Items.Count -1
                    $listBox1.SelectedIndex = -1
                    $n = '#EXTINF:-1,'+$matches[1]
                    $a.Content -match 'iframe.*"(https?.+php)".*' | Out-Null
                    $Global:l = $matches[1]
                    if ($l -notmatch "free") {
                        (Invoke-WebRequest -UseBasicParsing -URI $l -Headers @{"Referer"=$link}).Content -match 'file:"([^"]+)"' | Out-Null
                        $m = $matches[1]
                        Add-Content .\only-tv.m3u -Encoding utf8 -Value $n,$m
                    }
                    else {
                        continue
                    }
                }
                else {
                    $a.Content -match '<title>(.*)</title>' | Out-Null
                    $matches[1] | ForEach-Object {[Void]$listbox1.Items.Add($_)}
                    $listBox1.SelectedIndex = $listBox1.Items.Count -1
                    $listBox1.SelectedIndex = -1
                    $n = '#EXTINF:-1,'+$matches[1]
                    $a.Content -match 'iframe.*"(https?.+html)".*' | Out-Null
                    $Global:l = $matches[1]
                    (Invoke-WebRequest -UseBasicParsing -URI $l -Headers @{"Referer"=$link}).Content -match 'videoLink.*(https?[^"]+m3u8)' | Out-Null
                    $m = $matches[1]
                    Add-Content .\tv.m3u -Encoding utf8 -Value $n,$m
                }
                sleep -s 2
            }
            $c = Get-Content .\tv.m3u -Encoding utf8
            Set-Content .\tv.m3u -Encoding utf8 -value $d,$c
            Remove-Item $file.FullName -errorAction silentlycontinue
            
            $listBox1.Items.Add("Лист создан!")
        }

        if ( !$RadioButton.Checked ) {   $listBox1.Items.Add("No CheckBox selected....")} 


    }


    $OnLoadForm_StateCorrection=
    {#Correct the initial state of the form to prevent the .Net maximized form issue
        $form1.WindowState = $InitialFormWindowState
    }

#----------------------------------------------
#region Generated Form Code
    $form1.Text = "TV"
    $form1.Name = "form1"
    $form1.DataBindings.DefaultDataSourceUpdateMode = 0     
    $form1.FormBorderStyle = [System.Windows.Forms.FormBorderStyle]::Fixed3D
    $form1.StartPosition = [System.Windows.Forms.FormStartPosition]::CenterScreen
    $System_Drawing_Size = New-Object System.Drawing.Size
    $System_Drawing_Size.Width = 450
    $System_Drawing_Size.Height = 660
    $form1.BackColor = "0x7AC5E7"
    $form1.Opacity = 0.96
    $form1.ClientSize = $System_Drawing_Size

    $button1.TabIndex = 21
    $button1.Name = "button1"
    $System_Drawing_Size = New-Object System.Drawing.Size
    $System_Drawing_Size.Width = 75
    $System_Drawing_Size.Height = 23
    $button1.Size = $System_Drawing_Size
    $button1.UseVisualStyleBackColor = $True

    $button1.Text = "Run Script"

    $System_Drawing_Point = New-Object System.Drawing.Point
    $System_Drawing_Point.X = 25
    $System_Drawing_Point.Y = 585
    $button1.Location = $System_Drawing_Point
    $button1.DataBindings.DefaultDataSourceUpdateMode = 0
    $button1.add_Click($handler_button1_Click)

    $form1.Controls.Add($button1)

    $CancelButton = New-Object System.Windows.Forms.Button
    $CancelButton.Location = New-Object System.Drawing.Point(25,615)
    $CancelButton.Size = New-Object System.Drawing.Size(75,23)
    $CancelButton.Text = "Cancel"
    $CancelButton.DialogResult = [System.Windows.Forms.DialogResult]::Cancel
    $CancelButton.UseVisualStyleBackColor = $True
    $button1.TabIndex = 20
    $form1.CancelButton = $CancelButton
    $form1.Controls.Add($CancelButton)

    $listBox1.FormattingEnabled = $True
    $System_Drawing_Size = New-Object System.Drawing.Size
    $System_Drawing_Size.Width = 210
    $System_Drawing_Size.Height = 640
    $listBox1.Size = $System_Drawing_Size
    $listBox1.DataBindings.DefaultDataSourceUpdateMode = 0
    $listBox1.Name = "listBox1"
    $System_Drawing_Point = New-Object System.Drawing.Point
    $System_Drawing_Point.X = 220
    $System_Drawing_Point.Y = 13
    $listBox1.Location = $System_Drawing_Point
    $listBox1.TabIndex = 19

    $form1.Controls.Add($listBox1)

    $RadioButton.UseVisualStyleBackColor = $True
    $RadioButton.Checked = $false
    $System_Drawing_Size = New-Object System.Drawing.Size
    $System_Drawing_Size.Width = 154
    $System_Drawing_Size.Height = 30
    $RadioButton.Size = $System_Drawing_Size
    $RadioButton.TabIndex = 0
    $RadioButton.Text = "TV"
    $System_Drawing_Point = New-Object System.Drawing.Point
    $System_Drawing_Point.X = 25
    $System_Drawing_Point.Y = 40
    $RadioButton.Location = $System_Drawing_Point
    $RadioButton.DataBindings.DefaultDataSourceUpdateMode = 0
    $RadioButton.Name = "RadioButton"
    $RadioButton.add_CheckedChanged({
        if ($RadioButton.Checked){
            $listBox1.Items.Add( "TV"  )
        }
        else {
            $listBox1.Items.Clear();   
        }
    })

    $form1.Controls.Add($RadioButton)


#Save the initial state of the form
    $InitialFormWindowState = $form1.WindowState
#Init the OnLoad event to correct the initial state of the form
    $form1.add_Load($OnLoadForm_StateCorrection)
#Show the Form
    $form1.ShowDialog()| Out-Null

} #End Function

#Call the Function
GenerateForm
Правда немного подредактировал, неохота адрес сайта светить в паблике...

После последней правки, код что выше выложил, автоскроллинг заработал. Правда периодически пропадает содержимое листбокса (кроме последней строки) на несколько секунд.
Но это уже мелочи.
Большое спасибо всем за советы!

Последний раз редактировалось Uragan66, 16-12-2019 в 23:10.


Отправлено: 21:47, 16-12-2019 | #20



Компьютерный форум OSzone.net » Программирование, базы данных и автоматизация действий » Скриптовые языки администрирования Windows » PowerShell - [решено] Скрипт парсера потребляет много памяти и не отрабатывает полностью

Участник сейчас на форуме Участник сейчас на форуме Участник вне форума Участник вне форума Автор темы Автор темы Шапка темы Сообщение прикреплено

Похожие темы
Название темы Автор Информация о форуме Ответов Последнее сообщение
Статья - Почему процесс System потребляет так много памяти в Windows 10? OSZone Microsoft Windows 10 1 19-08-2015 20:05
Службы - svchost.exe потребляет слишком много памяти GIGABAIT Microsoft Windows 7 7 17-04-2015 11:02
MSFT SQL Server - MS SQL потребляет много оперативной памяти Tonny_Bennet Программирование и базы данных 22 23-10-2013 08:13
Групповая политика сопоставление дисков не полностью отрабатывает snioo Windows Server 2012/2012 R2 5 16-07-2013 11:01
Службы - HelpSvc.exe потребляет много оперативной памяти Котяра Microsoft Windows 2000/XP 5 18-07-2008 14:41




 
Переход