Авторедактирование списка url-ов на основе HTTP статус кодов
Select messages from
# through # FAQ
[/[Print]\]
Goto page 1, 2  Next  :| |:
Total Commander -> Программное обеспечение

#1: Авторедактирование списка url-ов на основе HTTP статус кодов Author: Hjkma PostPosted: Thu Jan 26, 2017 22:11
    —
Хочется иметь скрипт, который будет брать список url-ов из буфера обмена, проверять их на http статус коды, отсеивать url-ы, возвращающие статусы 404, и помещать отредактированный список url-ов обратно в буфер обмена. Нужно чтобы очистить список веб-адресов от неработающих сайтов и веб-страниц. И делать это нужно будет регулярно, поэтому требуется кнопка.
Буду очень признателен за скрипт, если кто-то из скриптописателей это сможет реализовать. Спасибо.

#2:  Author: MVVLocation: Ростов-Дон PostPosted: Thu Jan 26, 2017 23:03
    —
Батник (внутри вызывает повершелл) фильтрует урлы в буфере по валидным кодам возврата (2хх, 3хх - другие коды вызывают исключение внутри GetResponse):
Code:
@echo off
set "ARG_0=%~dpnx0"
powershell.exe -NoProfile -STA "iex (([IO.File]::ReadAllText($Env:ARG_0)) -replace '^(.*\n)*?.*<::::>.*\n', '')" & goto :EOF


Add-Type -Assembly System.Windows.Forms;


function testUrl($url, $timeout) {
   try {
      $webReq = [Net.WebRequest]::Create($url);
      $webReq.Method = 'HEAD';
      $webReq.Timeout = $timeout;
      $webRsp = $webReq.GetResponse();
      $webRsp.Close();
      Write-Host "``$url``: $([int]$webRsp.StatusCode)";
      $true;
   }
   catch {
      Write-Host "``$url``: $_";
   }
}


$urls = [Windows.Forms.Clipboard]::GetText() -split '\r?\n';
$goodUrls = @($urls | ? { $_ -match '^\w+://' -and (testUrl $_ $timeout) });
if ([Windows.Forms.MessageBox]::Show("Please click OK to copy $($goodUrls.Length) of $($urls.Length) urls to clipboard.", 'Url Filter', 1) -eq 1) {
   [Windows.Forms.Clipboard]::SetText(($goodUrls -join "`n") + "`n");
}


(добавлены установка метода HEAD и окошко сообщения в конце)


Last edited by MVV on Fri Jan 27, 2017 00:09; edited 2 times in total

#3:  Author: Hjkma PostPosted: Thu Jan 26, 2017 23:21
    —
MVV
Спасибо за скрипт. А есть ли возможность как-то оптимизировать или ускорить скрипт? Просто нужно обрабатывать тысячи ссылок, а скрипт обрабатывает их со скоростью 1 url за 1-2 секунды. За 1000 ссылок выйдет работы примерно на 16 минут, так что это долго.

#4:  Author: MVVLocation: Ростов-Дон PostPosted: Thu Jan 26, 2017 23:30
    —
Попробуй использовать метод HEAD, чтобы не грузить данные:
Code:
      $webReq = [Net.WebRequest]::Create($url);
      $webReq.Method = 'HEAD';
      ...

Также можно уменьшить значение $timeout, чтобы меньше ждать ответа от мертвых серверов, но при маленьком значении живые адреса могут тоже быть отсеяны.


Last edited by MVV on Thu Jan 26, 2017 23:42; edited 1 time in total

#5:  Author: Hjkma PostPosted: Thu Jan 26, 2017 23:35
    —
MVV
А где это в скрипте прописать?
Вставить нужно выше или ниже этого куска кода?
Code:
      $webReq = [Net.WebRequest]::Create($url);
      $webReq.Timeout = $timeout;
      $webRsp = $webReq.GetResponse();
      $webRsp.Close();
      Write-Host "``$url``: $([int]$webRsp.StatusCode)";
      $true;

#6:  Author: MVVLocation: Ростов-Дон PostPosted: Thu Jan 26, 2017 23:44
    —
Вставить нужно 1 новую строку (установка метода) после 1 уже имеющейся (создание объекта).

Ещё можно перед последней строкой (копирование в буфер) добавить отображение окошка, чтобы забивать буфер после долгой операции только по команде (писать можно и по-русски, но тогда необходимо сохранить файл в кодировке UTF-8 без BOM):
Code:
$null = [Windows.Forms.MessageBox]::Show("Please click OK to copy $($goodUrls.Length) good urls to clipboard.", 'Url Filter');


В общем, отредактировал скрипт в своём посте.

#7:  Author: Hjkma PostPosted: Fri Jan 27, 2017 00:03
    —
MVV
Сделал все это, скорость теперь примерно 1 url за одну секунду.
С таймаутом можно поэкспериментировать, но в принципе большая часть ссылок - и так живые, так что они отвечают в пределах 1-2 секунд, так что уменьшение таймаута не особо поможет.
А можно ли сделать так, чтобы батник обрабатывал ссылки в несколько проходов, то есть не по одной ссылке за один раз, а чтобы было 10 процессов и соединений, которые обрабатывают ссылки? Я не программист и не знаю как корректно это описать. Приведу пример. Есть downloader manager-ы, которым можно скормить тонну url-ов и можно там в настройках прописать количество соединений, например 10, тогда они скачивают по 10 файлов за один раз. Так и здесь нельзя применить тот же принцип?

#8:  Author: FlasherLocation: Москва PostPosted: Fri Jan 27, 2017 00:16
    —
Hjkma
Этот способ пингования называется асинхронным.
Темповый файл стоит на дозаписи, по достижению лимита счётчика содержимое выбрасывается в буфер.

#9:  Author: Hjkma PostPosted: Fri Jan 27, 2017 01:47
    —
От MVV что-то нету ответа.
Может ли кто-нибудь ввести в скрипт метод асинхронного пингования с потоками от 10 раз? Чтобы скорость получилась на 10 раз быстрее.

#10:  Author: MVVLocation: Ростов-Дон PostPosted: Fri Jan 27, 2017 01:57
    —
Может, MVV устал и ушел спать? Rolling Eyes

С асинхронностью будет как-то так:
Code:
@echo off
set "ARG_0=%~dpnx0"
powershell.exe -NoProfile -STA "iex (([IO.File]::ReadAllText($Env:ARG_0)) -replace '^(.*\n)*?.*<::::>.*\n', '')" & goto :EOF


Add-Type -Assembly System.Windows.Forms;


function testUrls($urls, $timeout, $workerCount = 2) {
   $job = @{
      queue = [Collections.Queue]::Synchronized((New-Object Collections.Queue (, $urls)));
      list = [Collections.ArrayList]::Synchronized((New-Object Collections.ArrayList));
      timeout = $timeout;
   };
   Write-Host "Checking $($urls.Length) urls using $workerCount workers...";
   $workerScript = {
      $job = $args[0];
      try {
         while (1) {
            $url = $job.queue.Dequeue();
            try {
               $webReq = [Net.WebRequest]::Create($url);
               $webReq.Method = 'HEAD';
               $webReq.Timeout = $job.timeout;
               $webRsp = $webReq.GetResponse();
               $webRsp.Close();
               $null = $job.list.Add($url);
               "$url`: $($webRsp.StatusCode)";
            }
            catch {
               "$url`: $_";
            }
         }
      }
      catch {}
   };
   $workers = @((1 .. $workerCount) | % { $w = [PowerShell]::Create().AddScript($workerScript).AddArgument($job); @{ w = $w; r = $w.BeginInvoke() } });
   $workers | % { Write-Host ($_.w.EndInvoke($_.r) -join "`n") };
   $job.list;
}

$timeout = 10000;
$workerCount = 10;
$urls = @([Windows.Forms.Clipboard]::GetText() -split '\r?\n' | ? { $_ -match '^\w+://' });
$startTime = [DateTime]::Now;
$goodUrls = @(testUrls $urls $timeout $workerCount);
$workTime = [int]([DateTime]::Now - $startTime).TotalSeconds;
if ([Windows.Forms.MessageBox]::Show("Approved $($goodUrls.Length) of $($urls.Length) urls in $workTime seconds.`nPlease click OK to copy urls to clipboard.", 'Url Filter', 1) -eq 1) {
   [Windows.Forms.Clipboard]::SetText(($goodUrls -join "`n") + "`n");
}


Таймаут и число потоков можно поменять, но если скрипт исчерпает лимит полуоткрытых соединений, могут быть проблемы.

#11:  Author: Hjkma PostPosted: Fri Jan 27, 2017 02:28
    —
MVV
Новый скрипт обработал 1925 ссылок за 6 минут. То есть, скорость получилась 1 секунда = 5 ссылок. В принципе, приемлемо.
Но есть проблема: старый вариант из тех 1925 ссылок возвращал 1217 работающих ссылок. Новый вариант вернул 1160 ссылок. Я нашел ссылки, которых вернул старый скрипт и не вернул новый скрипт, они все работающие, которые возвращают статус 200 и которые открываются в браузере. Еще раз запустил скрипт, на этот раз из тех же 1925 ссылок он вернул 1124. Что-то не так в скрипте. Могу прислать в ЛС список ссылок для тестирования.
Замечу, что и во время работы старого скрипта, и во время работы нового скрипта у меня все время работает торрент, который на полную скорость качает сериал. Может это влияет?
Upd. В третий раз запустил скрипт, на этот раз поставив число потоков на 5. Вернуло 1205 ссылок. Нормальное значение должно быть - 1217 ссылок. В четвертый раз, на 3 потоков вернуло уже 1217 ссылок. В пятый раз, на 3 потоков выдало цифру в 1215 ссылок. Как-то напрягает в работе скрипта, что не до конца уверен в конечном результате, т.к. скрипт выдает разные цифры. Может есть возможность встроить в работу скрипта какой-то механизм, который бы предотвращал такие ситуации, например в конце повторно бы перепроверял те ссылки, которых скрипт отсеял?

#12:  Author: MVVLocation: Ростов-Дон PostPosted: Fri Jan 27, 2017 11:24
    —
Естественно, если возникает ошибка или таймаут, ссылка отсеивается. А что в консоль выдается по тем ссылкам, которые рабочие, но были отсеяны скриптом?

Если в фоне работает торрент, то это может влиять - особенно если он качает на скорости, близкой к тарифному лимиту.

Чтобы детект работал стабильнее, надо увеличивать таймаут, а также следить, чтобы лимит полуоткрытых соединений не превышался (иначе повершелл просто не сможет открывать новые соединения) - например, можно смотреть открытые соединения в Process Hacker.

#13:  Author: Hjkma PostPosted: Fri Jan 27, 2017 16:24
    —
MVV
Так я не могу отследить процессы в консоле, в начале долго стоит надпись "Checking 1925 url using 10 workers", а потом как время работы скрипта подходит к концу, то в консоле очень быстро скопом пролистывается список урлов и их коды состояния и затем консоль завершается.
Попробую увеличить таймаут до 100000 с числом потоков на 10.
Вот про лимит полуоткрытых соединений не понял - у меня же Windows 7, вроде там нет ограничения?

#14:  Author: AvadaLocation: Россия, Саратов PostPosted: Fri Jan 27, 2017 19:37
    —
C учётом специфики поставленного вопроса и обсуждения тема переносится в "Программное обеспечение".

#15:  Author: Hjkma PostPosted: Fri Jan 27, 2017 20:16
    —
По итогам тестирования.
Второй вариант скрипта все время выдает разные результаты, то 1165 ссылок, то 1190, то 1203, сколько бы не увеличивал время таймаута и не уменьшал число потоков. Первый вариант скрипта всегда из тех 1925 ссылок выдает те же 1217 ссылок и все они рабочие. Может что-то в работе второго скрипта не так? Кстати, по консоли ошибся, это окно не исчезает, если не нажимать кнопку "ок", когда предлагают скопировать список ссылок в буфер. Но в консоли показываются не все ссылки, только 300 строк и больше ничего. Правда из тех 300 строк нашлись ссылки, которых скрипт отсеял и они рабочие. Вот их коды состояния
Quote:
(ссылка): Исключение при вызове "GetResponse" с "0" арг
ументами: "Невозможно разрешить удаленное имя: '(ссылка)"


Можно ли что-нибудь прописать в работе скрипта, чтобы сделать его как можно стабильнее? К примеру сделать так, чтобы в конце работы скрипт еще раз обрабатывал ссылки, которые возвращают приведенный выше код ошибки. С одним потоком и увеличенным таймаутом.



Total Commander -> Программное обеспечение


output generated using printer-friendly topic mod. All times are GMT + 4 Hours

Goto page 1, 2  Next  :| |:
Page 1 of 2

Powered by phpBB © 2001, 2005 phpBB Group