Tag Archives: вікіпедія

Як написати бота до Telegram?

Легко. 🙂 Давайте напишемо бота який перекладатиме нам всяке з німецької:

Приклад діалогу

Для цього нам треба поговорити з botFather-ом:

А зараз трохи не по темі цієї статті. Ось код який перетворює вікідані на словник, шукаючи всі сутності які мають мітки однією мовою, а потім показучи їх мітки іншою мовою, використовуючи хитрий запит SPARQL:

import json
import requests

def translate(from_lang, to_lang, word):
    '''
        Переклдає мітки елементів вікіданих з мови на мову. Повертає список варіантів перекладу
    '''
    res = sparql('''
        SELECT  ?ukLabel WHERE {
          ?item ?label "%s"@%s.
          ?item rdfs:label ?ukLabel filter(lang(?ukLabel) = "%s")
        } LIMIT 10
    ''' % (word, from_lang, to_lang))
    return list(map(
        lambda e: e['ukLabel']['value'],
        res['results']['bindings']
    ))

def sparql(query):
    ''' Отримує JSON дані запиту SPARQL до вікіданих '''
    res = requests.get(
        'https://query.wikidata.org/sparql',
        params={
            'query': query,
            'format': 'json'
        }
    )
    return json.loads(res.text)

А тепер повертаємось до теми телеграмного бота. Аби його написати треба поставити бібліотеку:

pip install pyTelegramBotAPI

Ось її Github: https://github.com/eternnoir/pyTelegramBotAPI

А далі – елементарно як писати консольну програму:

import telebot

TOKEN = '' # тут вставити те що BotFather сказав

bot = telebot.TeleBot(TOKEN)

@bot.message_handler(content_types=["text"]) # Якщо прийдуть нові повідомлення
def respond_to_message(message):
    translations = translate('de', 'uk', message.text) # Отримати переклади тексту повідомленя
    resp = '\n'.join(translations) if translations else 'На жаль, перекладу слова %s не знайдено' % message.text
    bot.send_message( # відправити назад
        message.chat.id, # в той самий чат з якого прийшло (можна напевне й в інший)
        resp
    )

if __name__ == '__main__':
     bot.polling(none_stop=True) # Запустити бота аби той сидів на лінії і слухав повідомлення.

Поки що все, бо й висипатись іноді треба. Пізніше нагадайте мені не забути написати більше про SPARQL, як поставити собі локальну mediawiki і розширення до неї, як логінити сторонні застосунки через OAuth, і як переписати інтерфейс вікіпедії на Vue.js. 🙂


Filed under: Кодерство, Павутина Tagged: вікіпедія, Python

Як написати свій букмарклет?

Букмарклет (bookmark) – це слово створене поєднанням слів bookmark (закладка) і applet (application (застосунок) + зменшувальний суфікс -let). Таким чином правильним перекладом bookmarklet було б “закластуночок” (чи “застокладочка”), але ви цього краще не кажіть Юрку Зеленому. Але я відхиляюсь. Отож, букмарклет, це маленька програма що міститься в закладці.

Як її туди помістили? Ну, виявляється браузери крім протоколів http, ftp, ітп, розуміють такий протокол як javascript. І коли отримують посилання з цим протоколом, при кліку по ньому не змінюють сторінку, а виконують його href як код JavaScript. Щоб побачити приклад простого букмарклету, створіть документ bookmarklet.htm, і помістіть в нього такий код:

<html>
<head><meta charset="utf-8" /></head>
<body>
<a href="javascript:
    alert('Привіт!')
">Мій букмарклет</a>
</body>
</html>

Якщо відкрити його в браузері, ви побачите чисту сторінку з єдиним посиланням Мій букмарклет, яке при кліку буде показувати повідомлення “Привіт!”. Якщо перетягнути це посилання на панель закладок в браузері, то тепер ви зможете в будь-який момент отримати привітання на будь-якій сторінці яку дивитесь, досить лише натиснути букмарклет.

Але це не дуже корисний букмарклет. Щоб він робив щось корисніше, досить замінити код в рядку 5, на якийсь корисніший.

Наприклад є такий сайт – lib.rus.ec. Вони хоч мають домен еквадору – але москалі, і коли відкрити їх сайт, то вискакує повідомлення, яке блокує доступ до сторінки, і просить грошей за чужі книжки. Я переконаний що в цьому випадку дозволяється використати принцип “грабуй награбоване”, і додати в букмарклет такий код:

 document.getElementsByClassName('lsp-overlay')[0].remove()

І тоді при кліку по букмарклету це вікно пропадатиме. Клас, правда? (Не забудьте забрати виклик alert() який ми написали там раніше)

Але давайте зробимо ще щось складніше і корисніше. Давайте зробимо букмарклет, який оформлює посилання на веб-сторінку в форматі вікіпедії cite web, і дає її нам в якомусь вікні. Це такий шаблон, який гарно оформлює посилання, але заповнювати його руками – ще та морока.

Для букмарклетів є кілька правил. Їх код все таки міститься всередині атрибуту елемента HTML, і повинен відповідати стандартам цієї мови. Наприклад всі подвійні лапки """ (ну ви зрозуміли), повинні бути заміненими HTML-кодом ". Крім того, перехід на новий рядок вважається еквівалентним пробілу, тому однорядкові коментарі можливі лише в кінці скрипта:

alert('Це вискочить');
// alert('Це не вискочить бо закоментовано');
alert('Це теж не вискочить бо коментар продовжується');

Ну і тому що ввесь скрипт здається браузеру написаним на одному рядку – бажано шанувати крапки з комою.

Якщо ми хочемо написати великий букмарклет, який можливо використовуватиме jQuery, та інші бібліотеки, нам захочеться їх якось підвантажувати. Але, віднедавна в адміністраторів серверів з’явилась нова можливість збільшувати безпеку вводячи обмеження на джерела з яких на сайт завантажуються ресурси – Content Security Policy, тому такі букмарклети можуть працювати не всюди. Можливо доведеться все переписати, мініфікувати і запакувати, але на всяк випадок, ось вам код підвантаження скрипта:

(function () {
    var script = document.createElement('script');
    script.src='https://gist.githubusercontent.com/bunyk/6ae97e5c3de490cfb4a1/raw/b7fcfde5c40314262893761418a6a25dd6ed0ce8/cite_web.js';
    document.body.appendChild(script);
}());

Подібним чином вже з того скрипта ми можемо підвантажити jQuery та наприклад CSS.

Я тут наковбасив трохи JavaScript, який можливо не на всіх сайтах працює, і не всі дані статті витягує, але на моєму блозі він дає щось подібне до цього:

cite_web

Щоб поставити собі такий, перенесіть оце посилання в закладки: “{{cite web|…“, а тоді в контекстному меню закладки натисніть “Властивості”, чи “Редагувати”, і замініть текст на

(function () {
    var script = document.createElement('script');
    script.src='https://gist.githubusercontent.com/bunyk/6ae97e5c3de490cfb4a1/raw/3102c3e285c6e24a9aed98d1bc7f0b7abeda20fc/cite_web.js';
    document.body.appendChild(script);
}());

Ось код:


Filed under: Кодерство, Павутина Tagged: Лайфхаки, вікіпедія, JavaScript

Генштаб для грамнацистів

Щойно з’явилась ідея супер-пупер сервісу для всіх хто пише і вичитує.

Сценарії використання

  1. Користувач бачить помилку на якомусь сайті. (Ідея націлена на вікіпедію, але має працювати на будь-яких інших сайтах, наприклад тут.) Нехай він зареєстрований на нашому порталі грамнацистів, і встановив букмарклет. Користувач виділяє ту помилку, натискає на букмарклет, той букмарклет показує попап з формою, де вписаний рядок з помилкою, полем куди можна ввести правильний варіант, пояснення помилки і посилання на словники та правопис.
  2. Користувач пише статтю. Він хоче написати її грамотно. Він вводить її текст, натискає інший букмарклет, і той використовуючи алгоритм Ахо-Корасік чи щось легше, підкреслює всі помилки і в попапах показує коментарі користувачів що їх виправили, та варіанти виправлень.
  3. Користувач вважає що помилка – не помилка, і попередній користувач помилився додавши її до словника. В попапі він клацає кнопочку “обговорення” і переходить на наш портал, де може обговорити.
  4. Адміністратори/редактори (вікіпедії) вирішують хто правий, а хто ні. Помилка яка насправді такою не була, позначається, і при наступних спробах її ввести, йому будуть повідомляти що це не помилка, і якщо він не згоден – посилати в обговорення.
  5. Найпопулярніші помилки, які вже точно помилки експортуються в файл що читається роботом який лазить по вікіпедії і виправляє всі статті та перевіряє всі нові правки. Якщо користувач вніс правку з помилкою – йому приходить повідомлення з поясненням суті помилки, проханням так не робити і порадою поставити букмарклет. :) На зразок такого:

  6. Треба врахувати те, що помилок існує більше ніж правильних слів (наприклад в слові “пиво” можна помилитися 32^4 = 2^{20} \approx 10^6 мільйоном різних способів, і то якщо не враховувати що також існують пропуск, дефіс, апостроф та інші символи. Тому варто намагатись вводити лише часті помилки, а решту залишати на hunspell. Словник для hunspell теж дозволити редагувати спільно, через букмарклети.

P.S. Я ще можу змиритись з тим що Firefox мені підкреслює hunspell, latex, букмарклет, попап і подібне. Але “блозі”, “кнопочку” “P.S.” і т.п. міг би вже вивчити.


Filed under: Кодерство, Павутина Tagged: вікіпедія, освіта, цілі

Генштаб для грамнацистів

Щойно з’явилась ідея супер-пупер сервісу для всіх хто пише і вичитує.

Сценарії використання

  1. Користувач бачить помилку на якомусь сайті. (Ідея націлена на вікіпедію, але має працювати на будь-яких інших сайтах, наприклад тут.) Нехай він зареєстрований на нашому порталі грамнацистів, і встановив букмарклет. Користувач виділяє ту помилку, натискає на букмарклет, той букмарклет показує попап з формою, де вписаний рядок з помилкою, полем куди можна ввести правильний варіант, пояснення помилки і посилання на словники та правопис.
  2. Користувач пише статтю. Він хоче написати її грамотно. Він вводить її текст, натискає інший букмарклет, і той використовуючи алгоритм Ахо-Корасік чи щось легше, підкреслює всі помилки і в попапах показує коментарі користувачів що їх виправили, та варіанти виправлень.
  3. Користувач вважає що помилка – не помилка, і попередній користувач помилився додавши її до словника. В попапі він клацає кнопочку “обговорення” і переходить на наш портал, де може обговорити.
  4. Адміністратори/редактори (вікіпедії) вирішують хто правий, а хто ні. Помилка яка насправді такою не була, позначається, і при наступних спробах її ввести, йому будуть повідомляти що це не помилка, і якщо він не згоден – посилати в обговорення.
  5. Найпопулярніші помилки, які вже точно помилки експортуються в файл що читається роботом який лазить по вікіпедії і виправляє всі статті та перевіряє всі нові правки. Якщо користувач вніс правку з помилкою – йому приходить повідомлення з поясненням суті помилки, проханням так не робити і порадою поставити букмарклет. :) На зразок такого:

  6. Треба врахувати те, що помилок існує більше ніж правильних слів (наприклад в слові “пиво” можна помилитися 32^4 = 2^{20} \approx 10^6 мільйоном різних способів, і то якщо не враховувати що також існують пропуск, дефіс, апостроф та інші символи. Тому варто намагатись вводити лише часті помилки, а решту залишати на hunspell. Словник для hunspell теж дозволити редагувати спільно, через букмарклети.

P.S. Я ще можу змиритись з тим що Firefox мені підкреслює hunspell, latex, букмарклет, попап і подібне. Але “блозі”, “кнопочку” “P.S.” і т.п. міг би вже вивчити.


Filed under: Кодерство, Павутина Tagged: вікіпедія, освіта, цілі

bwikibot 0.4.2, відтепер з автовиправленням правопису!

Автовиправлення правопису, як пізніше виявилось – передчасна ідея, але суть публікації в тому що bwikibot активно розвивається і на сьогодні вже має версію 0.4.13. Очікуйте 0.5.0!
Правда не всього правопису, а лише деяких іменників чоловічого роду в родовому відмінку, але й це вже краще ніж нічого.

bwikibot встановлюється просто як:

sudo pip install bwikibot

Або, якщо цією програмою ще хтось крім мене користується (дякую вам) і вже встановив, то оновлюємо:

sudo pip install --upgrade bwikibot

Нагадаю що pip повинен бути для третього Python, підтримка другого можлива лише теоретично, якщо хтось допоможе мені з тестами.

Після чого виправлення правопису запускається командою:

python3 main.py spell "Пориньте у Python 3/Модульне тестування"

correction_diff

І якщо вказана сторінка існує на вікі, на яку він залогінений, то текст цієї сторінки буде прочитано, будуть здійснені всі можливі автозаміни, вам буде показаний диф між новою і старою версіями (треба буде подумати над тим, як зробити так аби цей диф виглядав коротшим) і після отримання від вас згоди на запис, виправлена версія записана назад у вікі.

Що він може? Небагато, поки-що. В нього є словник genitive_a_u.txt, в якому містяться слова чоловічого роду в родовому відмінку з закінченнями “а”, “у”. Словник поки що невеликий, містить сім слів: аргументу, графа, менеджменту, методу, об’єкта, параметра, файла.

Проте це слова які я не вмію правильно писати, хоча пишу часто. :) Словник буде доповнюватись. Потім може ще додам словник автовиправлень частих помилок загального виду, і якісь n-грами.

Ну і щойно виявив помилку. Мій коректор хоче замінювати слово “аргументами” на “аргументуми”. :) Треба згадати що там в кінці шаблону треба поставити… Здається "аргумент\b"?

А ще, коли проект виросте до справді корисного, напевне варто буде його відокремити і додати можливість перевірки і автовиправлення блоґу через xml-rpc.

Ах, і якщо хтось знає як не винаходити велосипед, а інтегрувати aspell чи щось подібне – поділіться досвідом.

Доповнення на 16:15 : Помилку з “аргументуми”, занадто довгі дифи, виправлено в версії 0.4.3, також для цієї версії тести проходяться як в Python3 так і в Python2, але вручну я тестував тільки 3.


Filed under: Інструменти, Кодерство, Павутина Tagged: вікіпедія, мова, Python

Кібернетична вікі. Епізод II. Атака ботів

Не так давно
на одному
сервері кібцентру…

В Кібернетичній вікі
неспокійно. Більше сотні
користувачів демонструють
наміри закидати її спамом.

Рух спамерів очолюваний
загадковим невідомо ким
(чи взагалі ніким не очолюваний),
перешкоджає малочисельним кіберджедаям
зберігати чистоту й порядок на сайті.

Адміністрато bunyk повертається в КібВікі
щоб зайнятись принциповим питанням: створенням
бота для допомоги джедаям в малоуспішній боротьбі…

Пафосні титри подивились – переходим до банального сюжету про те як добро перемогло зло. :) Зі мною була нова сила (Python 3), і розуміння того що об’єктно-орієнтоване програмування призначене для зменшення кількості подібних параметрів в різних методах. І знання PEP8 яке дозволяє писати код на 8 та більше балів за Пайлінтом.

До того дії всіх ботів я відкидав вручну, слідкуючи за вікі через RSS. Коли їх було 1-2 на день це ще можна було терпіти. Але коли вони повалили десятками я на деякий час забив.

Я вирішив не морочити собі голову з PywikipediaБотом, для роботи якого на cybwiki ще треба створювати окремий файл конфігурації, а змайструвати свого. Свого писати набагато приємніше ніж лазити по сотнях файлів чужого. Крім того, мені дуже соромно за старий bunykwikibot, бо той код – блювотний. Зрозуміло що рік тому я цього не міг бачити. Тому маючи ще один день відпустки який залишився з проходження практики вирішив використати цей шанс щоб виправити ситуацію.

Знайомтесь – bunykwikibot2. Поки що різноманітних запитів до вікі в нього менше. Але зате він вміє логінитись і писати. І з ним приємно працювати.

Покажу на прикладі сьогоднішнього бою проти спамерів (ввесь код):

#!/usr/bin/python3

Ага. Рухаємось вперед. Бо якщо не ми, то хто?

from api import Wiki

Простіше простого. І не треба завантажувати штук п’ять функцій!

def hunt_bots():
    wiki = Wiki('http://cybportal.univ.kiev.ua/w/api.php')
    wiki.session_file('bunyk_on_cybwiki.session')

Це в нашого скрипта головна функція. При запуску створює новий клієнт wiki, для API за заданою адресою. Другий рядочок каже що дані сесії (куки і ще дещо) будуть завантажуватись з вказаного файлу. А якщо їх там нема – попросити в користувача залогінитись і записати туди дані сесії.

    def marked_bot(user):
        userpage = user.userpage().read() or ''
        return '{{Spambot}}' in userpage

Як розрізнити спам і не спам? Пол Грем написав статтю про Баєсівський класифікатор, а я як останній неуч її все ще не читав. Тому вирішив просто позначити всіх ботів вручну, шаблончиком {{Spambot}}. Функція вище отримує текст сторінки користувача, і дивиться чи там не написано що користувач – бот.

Зрозуміло бота ще треба позначити. Цим займається наступна функція:

    def shoot_bot(bot):
        bot.userpage().write('{{Spambot}}', 'Попався!')

Перший її рядок замінює текст сторінки бота позначкою про те що він бот, супроводжуючи цю дію бойовим криком “Попався!”.

        for contrib in bot.contributions():
            spam_page = wiki.page(contrib['title'])
            only_bots = True
            for user in spam_page.contributors():
                if not marked_bot(user):
                    only_bots = False
                    break
            if only_bots:
                spam_page.delete('Спам.')

Далі по черзі розглядаються всі сторінки які бот редагував. І якщо єдиними редакторами цих сторінок були вже позначені боти – сторінки теж видаляються.

        bot.block('Die spammers, die!')

Після цього бот блокується з іншим грізним криком.

Але основна частина скрипта – визначення хто бот, а хто ні:

    for user in wiki.all_users:
        userpage = user.userpage()
        page_text = userpage.read()
        if page_text:
            if '{{Spambot}}' in page_text:
                print(user.name, '- ботяра')
                continue
            if '{{Approved}}' in page_text:
                print(user.name, '- чесний')
                continue
            print(page_text)
        else:
            print('Сторінка користувача порожня')
        edits = user.edit_count()
        print(userpage.title, 'Редагувань: %d' % edits)

Я розглядав кожного користувача. Якщо він вже позначений – виводив повідомлення і брав наступного. Якщо ж ні – виводив текст його сторінки користувача, логін і кількість редагувань.

        if edits < 3:
            verdict = True
        else:
            verdict = ask_y_n('Це бот, як думаєте?'
                '(y/n або порожній рядок якщо не знаєте)'
            )

Спочатку кожну справу я розглядав вручну. Потім до мене якось дійшло що кожен бот залогінювався і робив не більше двох редагувань. Видно вони на більше не розраховані бо їх банять і доводиться реєструвати нові аккаунти. Правда через це мало не “постраждав” Номіровський тому що статтю про себе він редагував переважно анонімно, але я все виправив руками.

        if verdict == '':
            continue
        elif verdict:
            shoot_bot(user)
        else:
            userpage.append(
                '{{Approved}}',
                'Підтвердження того що власник сторінки - не бот.'
            )

Ну і коли сторону користувача визначено, він або розстрілювався, або позначався як наш. Якщо не визначено – пропускався.

Ну після довгої підготовки бій був коротким:
Робота бота

Результати: заблоковано 114 ботів. 40 нормальних користувачів підтверджено.

Тепер напевне пора думати що робити з наступними навалами? Банити всіх хто не поставить на свою сторінку відповідний шаблон, а анонімів за географічною ознакою? Чи таки вчити баєсівський класифікатор розрізняти дифи? Побачимо.


Filed under: Кодерство, Павутина Tagged: CybWiki, вікіпедія, Python