
Если у Вас во Вконтакте есть не маленькие сообщества, то постоянный и рутинный процесс поддержки стен в чистоте от спама может надоедать. Чем больше сообществ и подписчиков в этих сообществах - тем сложней уследить за порядком в комментариях.
Избавиться от этого надоедливого дела можно при помощи простенького Powershell скрипта "Антиспам Вконтакте".
Скрипт добавляет в черный список сообщества (на 11 месяцев, то есть возможность чтения сообщества остается, блокируется только возможность оставлять комментарии):
- комментаторов стены, которые не являются подписчиками этого сообщества
- тех, кто оставляет идентичные комментарии
- тех, кто добавляет в указанный фотоальбом фотографии и при этом не является подписчиком сообщества.
- тех, комментаторов, у которых страница создана явно для рекламных целей (анализирует статус, стену, количество подписок, пытается определить дату создания страницы)
Повторюсь, так как блокировка временная, а не навсегда, то комментатор и дальше может просматривать сообщество, но при этом возможность оставлять комментарии у него блокируется.
Преимущество антиспам скрипта для Вконтакте над платными сервисами:
- бесплатен
- можно проанализировать код и убедится что ничего злонамеренного не совершается
- есть возможность переделать скрипт под свои нужды и предпочтения
Скрипт время от времени дорабатывается и обновляется в этой записи.
Powershell скрипт "Антиспам Вконтакте":
# Скрипт добавляет в черный список сообщества (на 11 месяцев) комментаторов которые не являются подписчиками этого сообщества либо тех, кто оставляет идентичные комментарии и имеет явно спамные страницы # Автор elims.org.ua function http_request { #функция отсылки http-запросов и получения ответа param([string]$uri = $null) #входящий параметр $uri = "https://api.vk.com/method/"+$uri $i = 1 #счетчик попыток получения ответа от сервера while ($request -eq $null) { #пока не получим ответ от сервера $request = Invoke-WebRequest -Uri $uri #посылаем запрос Start-Sleep -m 340 #задержка в 340 милисекунд if($i -gt 1) { #если пытались получить ответ от сервера более 1 раза, то выводим это на экран write-host 'Попытка' $i ':' $uri } $i++ #увеличиваем счетчик попыток } $response_array = $request.content | ConvertFrom-Json #Конвертируем полученные данные из формата JSON в массив return $response_array #возврат результата функции } function ban-user { param($owner_id = $null,[string]$user_id = $null,$ban_comment = $null,$comment_id = $null,$message_string = $null) #входящий параметр $response_array = http_request("groups.banUser?group_id="+$group_id+"&user_id="+$user_id+"&end_date="+$end_date+"&comment="+$ban_comment+"&access_token="+$token+"&v=5.27") #банним комментатора $response_array = http_request("wall.reportComment?owner_id="+$owner_id+"&comment_id="+$comment_id+"&access_token="+$token+"&v=5.27") #удаляем комментарий $message_string | Out-File -Append $file_export -Encoding UTF8 } function check_for_spam_in_string { #функция проверяющая есть ли спам в входящей строке param([string]$function_string = $null) #входящий параметр $spam_string = $False #пока считаем что спама нет $function_string = $function_string.ToLower() #переводим текст строки в нижний регистр $function_string = $function_string -replace '(\\)|(\/)|(\*)|(:)|(\?)|(")|(<)|(>)|(\|)|(\[)|(\])|(\n)|(_)|( )', "" #убираем всякие разделители foreach($spam_text in $spam_texts_array) { #пробегаемся по всем указанным спамным паттернам $spam_text = $spam_text -replace '(\\)|(\/)|(\*)|(:)|(\?)|(")|(<)|(>)|(\|)|(\[)|(\])|(\n)|(_)|( )', "" #убираем всякие разделители $spam_text = $spam_text.ToLower() #переводим текст строки в нижний регистр if ($function_string.contains($spam_text)) { #если строка содержит спам $spam_string = $True #комментарий считается спамной } } return $spam_string #возвращаем результат } function vk-antispam-function { #функция антиспама $group_id = $owner_id * -1 $response_array = http_request("wall.get?owner_id="+ $owner_id + "&count=100&v=5.27") #получаем список постов $posts_array = $response_array.response.items $i = 0 $comments_from_id_text = @() #массив состоящий из текстов сообщений и отравителей $comments_comment_id = @() #массив состоящий из id комментариев $end_date = [int][double]::Parse($(Get-Date -date (get-date).ToUniversalTime()-uformat %s)) + 28857600 #юникс дата разбана while ( $i -lt 100 ) { #обходим полученные 100 постов if ($posts_array.comments[$i].count -gt 0) { #если пост содержит комментарии $response_array = http_request("wall.getComments?owner_id="+ $owner_id + "&post_id=" + $posts_array.id[$i] + "&count=100&v=5.27")#получаем комментарии к посту $comments_array = $response_array.response.items $comment_i = 0 foreach($comment in $comments_array.id) { #обходим полученные коментарии $time_now = Get-Date -date (get-date) #текущее время if(check_for_spam_in_string($comments_array[$comment_i].text)) { #если текст комментария содержит спам $message_string = "" + $time_now + " Комментарий содержит спам! post: "+$owner_id+"_"+$posts_array.id[$i]+" from_id: "+$comments_array.from_id[$comment_i]+" text: "+$comments_array[$comment_i].text ban-user $owner_id $comments_array.from_id[$comment_i] "antispam:spamincomment" $comments_array.id[$comment_i] $message_string #баним и удаляем текущий комментарий } else { #если текст комментария НЕ содержит спам $response_array = http_request("groups.get?user_id=" + $comments_array.from_id[$comment_i] + "&count=1000&access_token="+$token+"&v=5.29") #проверяем являеться ли комментатор подписчиком $groups = $response_array.response.items $groups_count = $response_array.response.count $member = 1 if ($groups.contains($group_id)) { #если комментатор состоит в группе $member = 2 } elseif ($groups_count -gt 0) { $response_array = http_request("groups.isMember?group_id=" + $group_id + "&user_id=" + $comments_array.from_id[$comment_i] + "&v=5.27") #проверяем являеться ли комментатор подписчиком, перепроверяем через другой запрос if ($response_array.response -eq 0) { $member = 0 } } if ($member -eq 0) { #если комментатор не является подписчиком $message_string = "" + $time_now + " Не подписчик! post: vk.com/wall" +$owner_id+"_"+$posts_array.id[$i]+" from_id: vk.com/id"+$comments_array.from_id[$comment_i]+" text: "+$comments_array[$comment_i].text ban-user $owner_id $comments_array.from_id[$comment_i] "antispam:notsubscriber" $comments_array.id[$comment_i] $message_string #баним и удаляем текущий комментарий } else { #если комментатор является подписчиком $string = "from_id: " + $comments_array.from_id[$comment_i] + " text: " + $comments_array[$comment_i].text #строка содержащая id комментатора и текст комментария if ($comments_from_id_text -contains $string ) { #если комментатор уже оставлял такое сообщение $message_string = ""+$time_now+" Дубликат! id исходного комментария: " + $comments_comment_id[$comments_from_id_text.indexOf($string)] + "id текущего комментария: " + $comments_array.id[$comment_i] + " автор и текст: " + $string ban-user $owner_id $comments_array.from_id[$comment_i] "antispam:identicalcomment" $comments_array.id[$comment_i] $message_string #баним и удаляем текущий комментарий #удаляем исходный комментарий: $response_array = http_request("wall.reportComment?owner_id="+$owner_id+"&comment_id="+$comments_comment_id[$comments_from_id_text.indexOf($string)]+"&access_token="+$token+"&v=5.27") } else { #если комментатор еще не оставлял такое сообщение $time_now_unix = [int][double]::Parse($(Get-Date -date (get-date).ToUniversalTime()-uformat %s)) #берем текущее время в юникс-формате и переводит в целое число $comments_from_id_text = $comments_from_id_text + $string #записываем в массив строку содержащую id комментатора и текст комментария $comments_comment_id = $comments_comment_id + $comments_array.id[$comment_i] #записываем в массив id коментария $response_array = http_request("wall.get?owner_id=" + $comments_array.from_id[$comment_i] + "&count=1&access_token="+$token+"&v=5.28") #получаем самую новую запись на стене $post_text = $response_array.response.items.text + $response_array.response.items.copy_history.text $posts_count = $response_array.response.count #количество постов на стене комментатора $response_array = http_request("users.get?user_ids=" + $comments_array.from_id[$comment_i] + "&fields=status&access_token="+$token+"&v=5.27") #получаем статус комментатора $status = $response_array.response.status #статус if ($status -eq $null) { $status = "" } #если неудалось получить статус, то делаем его пустым if ($post_text -eq $null) { $post_text = "" } #если неудалось получить первый пост, то делаем его пустым if((check_for_spam_in_string($status))-or(check_for_spam_in_string($post_text))) { #если текст статуса или первый пост содержит спам $message_string = ""+$time_now+" Страница комментатора спамная! post: "+$owner_id+"_"+$posts_array.id[$i]+" from_id: "+$comments_array.from_id[$comment_i]+" text: "+$comments_array[$comment_i].text+" Status: "+$status+ " First Post: "+$post_text ban-user $owner_id $comments_array.from_id[$comment_i] "antispam:spampage:text-status-last-post" $comments_array.id[$comment_i] $message_string } else { $response_array = http_request("wall.get?owner_id="+$comments_array.from_id[$comment_i]+"&offset="+($posts_count-1)+"&count=1&access_token="+$token+"&v=5.28") #получаем самую старую запись на стене $post_first_date = $response_array.response.items.date #дата первого поста на стене комментатора if ((($time_now_unix-$post_first_date) -lt 2*2592000)-or($posts_count -eq 0)) { #если самый старый пост был менее 2 месяцев назад или постов вообще нет $response_array = http_request("photos.getAll?owner_id="+$comments_array.from_id[$comment_i]+"&count=1&access_token="+$token+"&v=5.28") #получаем самую новую фотографию на странице $photos_count = $response_array.response.count #количество фотографий на странице комментатора $response_array = http_request("photos.getAll?owner_id="+$comments_array.from_id[$comment_i]+"&offset="+($photos_count-1)+"&count=1&access_token="+$token+"&v=5.28") #получаем самую старую фотографию на странице комментатора $photo_first_date = $response_array.response.items.date #дата первой фотографии на странице комментатора if (($time_now_unix-$photo_first_date) -lt 2*2592000) { #если самая старая фотография была добавлена менее 2 месяцев назад $response_array = http_request("users.getSubscriptions?user_id=" + $comments_array.from_id[$comment_i] +"&count=1&extended=1&access_token="+$token+"&v=5.28") #получаем подписки комментатора $subscriptions_count = $response_array.response.count #количество подписок if ($subscriptions_count -ge 50) { #если комментатор имеет более 50 подписок $message_string = ""+$time_now+" Страница vk.com/id"+$comments_array.from_id[$comment_i]+" была недавно создана! Фотография:"+([TimeZone]::CurrentTimeZone.ToLocalTime(([datetime]'1/1/1970').AddSeconds($photo_first_date)))+" Пост:"+([TimeZone]::CurrentTimeZone.ToLocalTime(([datetime]'1/1/1970').AddSeconds($post_first_date)))+" Подписок:"+$subscriptions_count+" Пост:vk.com/wall"+$owner_id+"_"+$posts_array.id[$i] ban-user $owner_id $comments_array.from_id[$comment_i] "antispam:spampage:date-of-photo-wall-subscritions" $comments_array.id[$comment_i] $message_string } } } } } } } $comment_i++ #счетчик комментариев } } "" + $i + " of 100 post: "+$owner_id+"_"+$posts_array.id[$i] $i++ #счетчик постов } } function vk-antispam-photo-function { #функция антиспама в фотоальбоме "Удаляем фотографии от не подписчиков в альбоме " + $album_id + " сообщества " + $owner_id $group_id = $owner_id * -1 $response_array = http_request("photos.get?owner_id="+ $owner_id + "&album_id=" + $album_id + "&rev=1&count=100&v=5.27") #получаем 100 фотографий $photo_array = $response_array.response.items $i = 0 $photo_date = [int][double]::Parse($(Get-Date -date (get-date).ToUniversalTime()-uformat %s)) - 2*86400 #текущее время минус количество секунд за 2*сутки $end_date = [int][double]::Parse($(Get-Date -date (get-date).ToUniversalTime()-uformat %s)) + 28857600 #юникс дата разбана while ( $i -lt 100 ) { #обходим полученные 100 фотографий if($photo_array.date[$i] -gt $photo_date) { #если фотография добавлялась за последние 2 сутки $response_array = http_request("groups.isMember?group_id=" + $group_id + "&user_id=" + $photo_array.user_id[$i] + "&v=5.27") #проверяем являеться ли человек подписчиком $member = 2 $member = $response_array.response if ($member -eq 0) { #убеждаемся еще раз что он не подписчик, так как контакт глючит и не всегда отдает верный результат $response_array = http_request("groups.isMember?group_id=" + $group_id + "&user_id=" + $photo_array.user_id[$i] + "&v=5.27") #проверяем являеться ли человек подписчиком $member = 2 $member = $response_array.response } if ($member -eq 0) { #если автор фотографии не является подписчиком $response_array = http_request("groups.banUser?group_id="+$group_id+"&user_id="+$photo_array.user_id[$i]+"&end_date="+$end_date+"&comment=antispamphoto:notsubscriber&access_token="+$token+"&v=5.27") #банним человека $response_array = http_request("photos.report?owner_id="+$owner_id+"&photo_id="+$photo_array.id[$i]+"&access_token="+$token+"&v=5.27") #удаляем фотографию $string_message = "" + (Get-Date -date (get-date)) + " Не подписчик! Обнаружена фотография: " + $owner_id+"_"+$photo_array.id[$i] + " от user_id: " + $photo_array.user_id[$i] $string_message $string_message | Out-File -Append $file_export -Encoding UTF8 } elseif($photo_array.text[$i].lenght -gt 0 ) { $string_message = "" + (Get-Date -date (get-date)) + "Обнаружена фотография с описанием!" + $owner_id+"_"+$photo_array.id[$i] + " от user_id: " + $photo_array.user_id[$i] + " описание: " + $photo_array.text[$i] $string_message $string_message | Out-File -Append $file_export -Encoding UTF8 } } $i++ #счетчик фотографий } } $token = "ioaudysaiuofasidufsdaifudsiofuyviuyzcviouxvysioudfgyaiufy" $file_export = "C:\temp\antispam-report.txt" #файл экспорта $spam_texts_array = "добавляйтесь в друзья","возбуждающая жвачка","ВОЗБУЖДАЮЩИЕ ЖВАЧКИ" $owner_id = -5994278 $album_id = 15765487 #id-альбома в который пользователи добавляют свои фотографии vk-antispam-function vk-antispam-photo-function $owner_id = -13665595 vk-antispam-function
В самом конце скрипта указываются следующие входящие параметры:
$token - что такое токен и как его сгенерировать я уже писал вот тут, если кратко - то это Ваш уникальный код, благодаря которому Вконтакте будет понимать что скрипт выполняется от Вашего имени (поэтому свой токен не рекомендуется сообщать сторонним лицам). Для работы этого скрипта нужно иметь право на удаления комментариев, фотографий в сообществе и добавление пользователей в черный список сообщества. Пример ссылки для получения такого токена:
https://oauth.vk.com/authorize?client_id=тут_id_вашего_приложения&scope=groups,wall,photos,offline&redirect_uri=https://oauth.vk.com/blank.html&display=page&v=5.24&response_type=token
$file_export - адрес текстового файла, куда будет записываться информация о выполнении срипта
$album_id - id-альбома в который пользователи добавляют свои фотографии
$owner_id - id-сообщества в котором нужно чистить стену от спама. Если у Вас таких сообществ несколько, то присваиваете эту переменную несколько раз чередуя с вызовом функции vk-antispam-function, у меня в скрипте указано два сообщества.
$spam_texts_array - список спамных словосочетаний, на которые реагирует скрипт, перечисляются в кавычках, через запятую, в моем примере указано три спамных словосочетания: "добавляйтесь в друзья", "возбуждающая жвачка", "ВОЗБУЖДАЮЩИЕ ЖВАЧКИ".
Для большей наглядности предположим я хочу чистить стену от спама в 5 сообществах и у них следующие id:
- -12345
- -453254
- -52452
- -4525
- -464576
Тогда я должен в скрипте заменить код:
$owner_id = -5994278 vk-antispam-function $owner_id = -13665595 vk-antispam-function
На код:
$owner_id = -12345 vk-antispam-function $owner_id = -453254 vk-antispam-function $owner_id = -52452 vk-antispam-function $owner_id = -4525 vk-antispam-function $owner_id = -464576 vk-antispam-function
Осталось этот скрипт сохранить в файл с расширением ps1 и прописать в планировщике заданий его периодический запуск, после чего стена у Вас будет в чиста от спама =)
UPD: для работы скрипта нужен Powershell не ниже 4-й версии
Здравствуйте. Понравилась Ваша статься, задумка актуальна, но у меня не получается запустить этот скрипт или руки у меня кривые.
Сделал все как было описано. Помогите пожалуйста.
Скрин.
s35-temporary-files.radikal.ru/3b892c1e10104b5eb248735a61e733ac/-88693455.jpg
Антон, здравствуйте. Скрин не отображается — «404 — File or directory not found.». Попробуйте еще куда-то выложить. Возможно у Вас старая версия Powershell.
Перезалил. Установил Powershell на XP по вашей ссылке в статье. Может это быть из за того, что у меня посты от имени группы?
uploads.ru/JEhtb.jpg
Мои посты также от имени группы. Судя по ошибке массив с постами пустой, нужно смотреть первые ошибки, а не последние. Лучше просто их скопируйте текстом и вставьте куда-либо, например вот сюда: pastebin.com/
Я бы это сделал, но консоль после быстрого прогона красного текста закрывается. Как это можно решить?
Я сначала запускаю консоль: cmd
Потом в ней запускаю повершел: Powershell
А потом уже в ней запускаю скрипт: antispam.ps1
И у меня ничего не закрывается.
pastebin.com/WxG2ukGm Вот, вроде бы скопировал все.
Ошибка та же: массив с комментариями пуст. owner_id какой указан?
мой
$owner_id = -2286932
Указан корректно. А версия powershell какая? команда «$host.version» в консоли говорит какая версия.
консоль: cmd
Потом повершел: Powershell
А потом: $host.version
Интересует столбик Major
Major
——
2
Думаю именно в этом проблема, так как сам специально ставил более новую версию — там был набор необходимых мне команд. У меня 4-я версия.
Возможно под XP нет 4-й версии.
Да. Действительно, дело было в старой версии. Сейчас запустил на w7 с обновленной 4й версией шелла и все работает. Спасибо за помощь и пардон за потраченное время). Но Если реализуете это творение под 2ю версию шелла, то буду очень благодарен.
На здоровье =) Под 2-ю версию, увы, переписывать не планирую.
В скрипт добавлена функция, которая также следит за указанным фотоальбомом: если пользователь добавил в фотоальбом фотографию и не является подписчиком сообщества, то он добавляется в черный список на 11 месяцев, фотография удаляется.
Здравствуйте Владимир. Старался Вас не беспокоить, но все таки очень нужен скрипт под XP, хоть криком кричи). Можно ли с Вами как-нибудь договориться?
Антон, здравствуйте. Как говорится «любой каприз за Ваши деньги», все таки на переписывание скрипта придется уделять время, которое у меня распланировано, + ОС на виртуальной машине поднимать, но с необходимой мотивацией могу за это взяться. Пишите по этому поводу на мою почту, она указана на странице About, в конце текста =)
Скрипт существенно доработан. Исправлены ошибки с ложным срабатыванием, добавлены новые проверки на выявление спама и спамных страниц.
Здравствуйте!
Его нужно всегда вручную запускать? Нельзя сделать, чтобы 24 часа работало?
Привет!
Пытаюсь использовать скрипт. Во-первых из-за русского текста он запускаться не хочет. Во-вторых после выполнения скрипта (русский язык я из скрипта удалил) спам не удаляется. В лог вываливается:
10/09/2015 17:13:20 Comment with SPAM! post: -104125447_1 from_id: 262525396 text: test
Можно, если немного изменить скрипт. Но я предпочел прописать запуск в планировщике задач. То есть скрипт не запускается вручную, он запускается автоматически через планировщик задач.
Еще актуально ?
Спасибо большое Владимиру , очень помог — все установил и сделал за минимальную сумму денег)
Сергей, пожалуйста =)
У меня удаляет комменты вроде, а в ЧС не заносит. Вот скрин: https://vk.com/albums105089913?z=photo105089913_434620781%2Falbum105089913_00
Помогите мне пожалуйста!
Спасибо!
и по пути вопрос, как уменьшить или убрать время бана?
Спасибо!
Скорее всего комментатор не состоит ни в одной группе, либо скрывает их список.
Новая версия скрипта такие ошибки обрабатывает, если я не ошибаюсь, но у меня пока нет времени заниматься его публикацией.
#юникс дата разбана — строка которое задает время разбана.28857600 — время в секундах которое плюсуется к текущему времени
Владимир, извините, ещё вопрос:
Есть дубли комментариев, авторов от заносит в ЧС, а вот комменты их не удаляет. Не подскажите где копать?
Рядышком с кодом, где есть что-то вроде дубли или dublicates
Привет! Что-то я не так делаю походу.
Выставил в Notepad++ кодировку utf-8. Скопировал скрипт. Сохранил в ps1.
Залил на хост Jino. Выставил в файле: utf-8, windows, powershell.
Запускаю — просто вижу в браузере весь текст файла и ничего не срабатывает…
Привет. Да, не то. Скрипт никакого отношения к браузеру не имеет. Ничего в браузере запускать не нужно. И хостинг обычный для него не подойдет.