Участник:BsivkoBot/КатегоризаторОписаниеМотивацияБот с аналогичной функциональностью есть здесь: Участник: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 Состояние и развитиеОбсуждение |