Описание
Мотивация
Бот с аналогичной функциональностью есть здесь: Участник:KrBot/Задания
Реализация
Согласно плану задач, категоризатор периодически сканирует настройки планировщика и запускает обработку согласно найденным задачам. Планировщик определяет предел числа обработанных статей за раз и период сканирования.
Реализовано с помощью модуля pywikibot textlib, и поэтому категоризатор автоматически правит формат перед категориями (одна пустая строка).
Конфигурация описана на следующей странице:
Пример конфигурации:
{
"переименовать": {
"Винтик": "Шпунтик"
},
"удалить": [
"Ёжики в тумане"
]
}
То есть, категоризатор будет искать все страницы категорий «Винтик» и «Ёжики в тумане», первые из которых переименовываются в «Шпунтик», а вторые удаляются.
После выполнения задачи не забываем убрать из конфигурации установленные параметры.
Исходный код
import json
import mwparserfromhell
import pywikibot
from bot_logging.log import log_warning_json
from wiki_category_processing.category_collector import rename_category, delete_category
from wiki_requests.site import ru_site
from wiki_template_processing.endings_format import detect_format_endings, set_format_ending
TASK_CATEGORIZATOR = u"категоризатор"
categorizator_cfg_cached = None
def get_catogorizator_cfg():
global categorizator_cfg_cached
if categorizator_cfg_cached is not None:
return categorizator_cfg_cached
pagename = "Участник:BsivkoBot/Категоризатор/Конфигурация"
site = pywikibot.Site()
page = pywikibot.Page(site, pagename)
text = str(page.text)
categorizator_cfg_cached = json.loads(text)
return categorizator_cfg_cached
def get_single_or_list_as_list(value):
if isinstance(value, list):
return value
if value is None:
return value
return [value]
def categorizator_for_article(text, cfg, title="unknown"):
if cfg.get("переименовать") is not None:
to_rename = cfg["переименовать"]
for key, value in to_rename.items():
text = rename_category(ru_site(), text, "Категория:" + key, "Категория:" + value)
if cfg.get("удалить") is not None:
to_delete = cfg["удалить"]
for name in to_delete:
text = delete_category(ru_site(), text, "Категория:" + name)
return text
category_collector.py:
import mwparserfromhell
import pywikibot
from pywikibot import textlib
from wiki_requests.redirects import get_redirects_to_template
def collect_categories(text):
result = set()
parsed = mwparserfromhell.parse(text)
for wikilink in parsed.filter_wikilinks():
if wikilink.title is not None:
title = str(wikilink.title)
cat_prefix = "Категория:"
if len(title) > len(cat_prefix):
if title[:len(cat_prefix)] == "Категория:":
result.add(title[len(cat_prefix):])
return result
def one_of_categories_is_present(text, names):
parsed = mwparserfromhell.parse(text)
categories_set = collect_categories(text)
categories_set = [element.lower() for element in categories_set]
for name in names:
if name.lower() in categories_set:
return True
return False
def delete_category(site, text, name_to_delete):
categories = textlib.getCategoryLinks(text, site=site)
for cat in categories:
if cat.title() == name_to_delete:
categories.remove(cat)
text = textlib.replaceCategoryLinks(text, categories, site)
return text
def rename_category(site, text, name_to_rename, new_name):
categories = textlib.getCategoryLinks(text, site=site)
catpl = pywikibot.Category(site, new_name)
for cat in categories:
if cat.title() == name_to_rename:
categories.remove(cat)
categories.append(catpl)
text = textlib.replaceCategoryLinks(text, categories, site)
return text
Тестирование
from wiki_category_processing.category_collector import collect_categories, one_of_categories_is_present, \
delete_category, rename_category
from wiki_requests.site import ru_site
def test_collect_categories():
text = "{{компьютерная игра}} [[Категория:Q]]\n[[Категория:QWERT]]"
value = collect_categories(text)
assert value.intersection({'Q'}) == {'Q'}
assert value.intersection({'QWERT'}) == {'QWERT'}
assert value.intersection({'видеоигра'}) == set()
return
def test_category_is_present():
text = "{{компьютерная игра}} [[Категория:Q]]\n[[Категория:QWERT]]"
assert one_of_categories_is_present(text, ["компьютерная игра"]) == False
assert one_of_categories_is_present(text, ["Q"]) == True
assert one_of_categories_is_present(text, ["Q", "QWERT"]) == True
assert one_of_categories_is_present(text, ["A", "B", "Q"]) == True
assert one_of_categories_is_present(text, ["A", "B", "C"]) == False
return
def test_delete_category():
text = "{{компьютерная игра}} [[Категория:Q]]\n[[Категория:QWERT]]"
value = delete_category(ru_site(), text, "Категория:Q")
assert "Q]]" not in value
value = delete_category(ru_site(), text, "Категория:QWERT")
assert "QWERT" not in value
return
def test_rename_category():
text = "{{компьютерная игра}} [[Категория:Q]]\n[[Категория:QWERT]]"
value = rename_category(ru_site(), text, "Категория:Q", "Категория:A")
assert "Q]]" not in value
assert "A]]" in value
return
Состояние и развитие
- Тестирование. Bsivko (обс.) 06:14, 1 ноября 2019 (UTC)
Обсуждение