Страница 1 из 2
Авторедактирование списка url-ов на основе HTTP статус кодов
Добавлено: Чт янв 26, 2017 21:11
Hjkma
Хочется иметь скрипт, который будет брать список url-ов из буфера обмена, проверять их на http статус коды, отсеивать url-ы, возвращающие статусы 404, и помещать отредактированный список url-ов обратно в буфер обмена. Нужно чтобы очистить список веб-адресов от неработающих сайтов и веб-страниц. И делать это нужно будет регулярно, поэтому требуется кнопка.
Буду очень признателен за скрипт, если кто-то из скриптописателей это сможет реализовать. Спасибо.
Добавлено: Чт янв 26, 2017 22:03
MVV
Батник (внутри вызывает повершелл) фильтрует урлы в буфере по валидным кодам возврата (2хх, 3хх - другие коды вызывают исключение внутри
GetResponse):
Код: Выделить всё
@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 и окошко сообщения в конце)
Добавлено: Чт янв 26, 2017 22:21
Hjkma
MVV
Спасибо за скрипт. А есть ли возможность как-то оптимизировать или ускорить скрипт? Просто нужно обрабатывать тысячи ссылок, а скрипт обрабатывает их со скоростью 1 url за 1-2 секунды. За 1000 ссылок выйдет работы примерно на 16 минут, так что это долго.
Добавлено: Чт янв 26, 2017 22:30
MVV
Попробуй использовать метод HEAD, чтобы не грузить данные:
Код: Выделить всё
$webReq = [Net.WebRequest]::Create($url);
$webReq.Method = 'HEAD';
...
Также можно уменьшить значение
$timeout, чтобы меньше ждать ответа от мертвых серверов, но при маленьком значении живые адреса могут тоже быть отсеяны.
Добавлено: Чт янв 26, 2017 22:35
Hjkma
MVV
А где это в скрипте прописать?
Вставить нужно выше или ниже этого куска кода?
Код: Выделить всё
$webReq = [Net.WebRequest]::Create($url);
$webReq.Timeout = $timeout;
$webRsp = $webReq.GetResponse();
$webRsp.Close();
Write-Host "``$url``: $([int]$webRsp.StatusCode)";
$true;
Добавлено: Чт янв 26, 2017 22:44
MVV
Вставить нужно 1 новую строку (установка метода) после 1 уже имеющейся (создание объекта).
Ещё можно перед последней строкой (копирование в буфер) добавить отображение окошка, чтобы забивать буфер после долгой операции только по команде (писать можно и по-русски, но тогда необходимо сохранить файл в кодировке UTF-8 без BOM):
Код: Выделить всё
$null = [Windows.Forms.MessageBox]::Show("Please click OK to copy $($goodUrls.Length) good urls to clipboard.", 'Url Filter');
В общем, отредактировал скрипт в
своём посте.
Добавлено: Чт янв 26, 2017 23:03
Hjkma
MVV
Сделал все это, скорость теперь примерно 1 url за одну секунду.
С таймаутом можно поэкспериментировать, но в принципе большая часть ссылок - и так живые, так что они отвечают в пределах 1-2 секунд, так что уменьшение таймаута не особо поможет.
А можно ли сделать так, чтобы батник обрабатывал ссылки в несколько проходов, то есть не по одной ссылке за один раз, а чтобы было 10 процессов и соединений, которые обрабатывают ссылки? Я не программист и не знаю как корректно это описать. Приведу пример. Есть downloader manager-ы, которым можно скормить тонну url-ов и можно там в настройках прописать количество соединений, например 10, тогда они скачивают по 10 файлов за один раз. Так и здесь нельзя применить тот же принцип?
Добавлено: Чт янв 26, 2017 23:16
Flasher
Hjkma
Этот способ пингования называется асинхронным.
Темповый файл стоит на дозаписи, по достижению лимита счётчика содержимое выбрасывается в буфер.
Добавлено: Пт янв 27, 2017 00:47
Hjkma
От MVV что-то нету ответа.
Может ли кто-нибудь ввести в скрипт метод асинхронного пингования с потоками от 10 раз? Чтобы скорость получилась на 10 раз быстрее.
Добавлено: Пт янв 27, 2017 00:57
MVV
Может,
MVV устал и ушел спать?
С асинхронностью будет как-то так:
Код: Выделить всё
@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");
}
Таймаут и число потоков можно поменять, но если скрипт исчерпает лимит полуоткрытых соединений, могут быть проблемы.
Добавлено: Пт янв 27, 2017 01:28
Hjkma
MVV
Новый скрипт обработал 1925 ссылок за 6 минут. То есть, скорость получилась 1 секунда = 5 ссылок. В принципе, приемлемо.
Но есть проблема: старый вариант из тех 1925 ссылок возвращал 1217 работающих ссылок. Новый вариант вернул 1160 ссылок. Я нашел ссылки, которых вернул старый скрипт и не вернул новый скрипт, они все работающие, которые возвращают статус 200 и которые открываются в браузере. Еще раз запустил скрипт, на этот раз из тех же 1925 ссылок он вернул 1124. Что-то не так в скрипте. Могу прислать в ЛС список ссылок для тестирования.
Замечу, что и во время работы старого скрипта, и во время работы нового скрипта у меня все время работает торрент, который на полную скорость качает сериал. Может это влияет?
Upd. В третий раз запустил скрипт, на этот раз поставив число потоков на 5. Вернуло 1205 ссылок. Нормальное значение должно быть - 1217 ссылок. В четвертый раз, на 3 потоков вернуло уже 1217 ссылок. В пятый раз, на 3 потоков выдало цифру в 1215 ссылок. Как-то напрягает в работе скрипта, что не до конца уверен в конечном результате, т.к. скрипт выдает разные цифры. Может есть возможность встроить в работу скрипта какой-то механизм, который бы предотвращал такие ситуации, например в конце повторно бы перепроверял те ссылки, которых скрипт отсеял?
Добавлено: Пт янв 27, 2017 10:24
MVV
Естественно, если возникает ошибка или таймаут, ссылка отсеивается. А что в консоль выдается по тем ссылкам, которые рабочие, но были отсеяны скриптом?
Если в фоне работает торрент, то это может влиять - особенно если он качает на скорости, близкой к тарифному лимиту.
Чтобы детект работал стабильнее, надо увеличивать таймаут, а также следить, чтобы лимит полуоткрытых соединений не превышался (иначе повершелл просто не сможет открывать новые соединения) - например, можно смотреть открытые соединения в Process Hacker.
Добавлено: Пт янв 27, 2017 15:24
Hjkma
MVV
Так я не могу отследить процессы в консоле, в начале долго стоит надпись "Checking 1925 url using 10 workers", а потом как время работы скрипта подходит к концу, то в консоле очень быстро скопом пролистывается список урлов и их коды состояния и затем консоль завершается.
Попробую увеличить таймаут до 100000 с числом потоков на 10.
Вот про лимит полуоткрытых соединений не понял - у меня же Windows 7, вроде там нет ограничения?
Добавлено: Пт янв 27, 2017 18:37
Avada
C учётом специфики поставленного вопроса и обсуждения тема переносится в "Программное обеспечение".
Добавлено: Пт янв 27, 2017 19:16
Hjkma
По итогам тестирования.
Второй вариант скрипта все время выдает разные результаты, то 1165 ссылок, то 1190, то 1203, сколько бы не увеличивал время таймаута и не уменьшал число потоков. Первый вариант скрипта всегда из тех 1925 ссылок выдает те же 1217 ссылок и все они рабочие. Может что-то в работе второго скрипта не так? Кстати, по консоли ошибся, это окно не исчезает, если не нажимать кнопку "ок", когда предлагают скопировать список ссылок в буфер. Но в консоли показываются не все ссылки, только 300 строк и больше ничего. Правда из тех 300 строк нашлись ссылки, которых скрипт отсеял и они рабочие. Вот их коды состояния
(ссылка): Исключение при вызове "GetResponse" с "0" арг
ументами: "Невозможно разрешить удаленное имя: '(ссылка)"
Можно ли что-нибудь прописать в работе скрипта, чтобы сделать его как можно стабильнее? К примеру сделать так, чтобы в конце работы скрипт еще раз обрабатывал ссылки, которые возвращают приведенный выше код ошибки. С одним потоком и увеличенным таймаутом.