Участник:AJZBot/Код: различия между версиями

Материал из Википедии — свободной энциклопедии
Перейти к навигации Перейти к поиску
Содержимое удалено Содержимое добавлено
Код: print -> wikipedia.output
Код: fix: при повторной проверке не заменялся текст замечаний
Строка 451: Строка 451:
#77 = 26 + 51, где 26 - длина строки 'AJZBot/Завершающая фраза}}'
#77 = 26 + 51, где 26 - длина строки 'AJZBot/Завершающая фраза}}'
#а 51 - длина подписи бота
#а 51 - длина подписи бота
self.TalkPageText.replace(self.TalkPageText[(ReqStart):(ReqFinish+77)],\
self.TalkPageText = self.TalkPageText.replace(self.TalkPageText[(ReqStart):(ReqFinish+77)],\
self.ReqText)
self.ReqText)
else:
else:

Версия от 02:49, 28 июля 2012

Бот использует следующие служебные страницы в качестве шаблонов:

Ниже приведён снабжённый комментариями исполняемый код бота. Если у вас есть замечания, предложения по улучшению или исправлению кода, вопросы или любая другая причина вступить в контакт с ботовладельцем, обращайтесь сюда. Любый изменения этой страницы никак не повлияют на работу бота, так как здесь представлена копия кода, а не сам код. Правьте эту страницу, конструктивные улучшения будут учтены при дальнейшем развитии бота.

Код

# -*- coding: cp1251 -*-

import add_text, wikipedia, catlib

#список фраз, привязывающих статью к настоящему времени
TimeList = [u'в настоящее время',u'в наши дни',u'в прошлом году',\
            u'в следующем году', u'недавно',u'скоро',u'с тех пор',\
            u'на сегодняшний день',u'на данный момент',u'наши дни']

#список ненейтральных слов и выражений
StyleList = [u'уникальн',u'замечательн',u'превосходн',u'божественн',\
             u'великолепн',u'эксклюзивн',u'восхитительн',u'изумительн',\
             u'безупречн',u'лучш',u'ведущ',u'авторитетн',\
             u'популярн',u'престижн',u'уважаем',u'велик',\
             u'огромн',u'эффективн',u'крупнейш',u'отвратительн',\
             u'кошмарн',u'безоразн',u'успешн',u'мастерств',\
             u'феноменальн',u'знаменит',u'виртуозн',u'мастерск',\
             u'выдающ',u'самоотвержен',u'талантливейш',\
             u'жаждущ',u'гениальн',u'колоссальн',u'высококачеств',\
             u'долгожданн',u'исключительн',u'беззаветн',u'ошеломительн',\
             u'богатый опыт',u'неповторим',u'долгожданн']

#список фраз, указывающих на территориальную принадлежность читателя
OutLandList = [u'за рубежом',u'зарубежом',u'зарубежн', u'отечествен', \
               u'за бугром',u'забугорн']

#список всевозможных ссылок на действующие правила о значимости
#по-моему тут люди немного перестарались
NatabilityLinks = [u'[[ВП:ПОЛИТИКИ',u'[[ВП:СПОРТСМЕНЫ',u'[[ВП:КЗМ', \
                   u'[[ВП:МУЗЫКАНТЫ',u'[[ВП:ПИСАТЕЛИ',u'[[ВП:АКТЕРЫ', \
                   u'[[ВП:АРТИСТЫ',u'[[ВП:КЗДИ',u'[[Википедия:Значимость', \
                   u'[[Википедия:Критерии значимости персоналий', \
                   u'[[Википедия:Критерии значимости веб-сайтов', \
                   u'[[Википедия:Кавалеры высших наград государства', \
                   u'[[Википедия:Критерии значимости программ', \
                   u'[[Википедия:Критерии значимости футболистов', \
                   u'[[Википедия:Критерии значимости аниме и манги', \
                   u'[[Википедия:Списки',u'[[ВП:КЗЖ',u'[[ВП:УЧ', \
                   u'[[ВП:УЧЕНЫЕ',u'[[ВП:РД',u'[[ВП:НЯ', \
                   u'[[ВП:КЗПУ',u'[[ВП:ВОЕННЫЕ',u'[[ВП:БИЗ', \
                   u'[[ВП:ЗН',u'[[ВП:КЗ',u'[[ВП:ОКЗ',u'[[ВП:НЕНОВОСТИ', \
                   u'[[ВП:ВЕБ',u'[[ВП:КЗС',u'[[ВП:КЗВС', \
                   u'[[ВП:ЗП',u'[[ВП:СОФТ',u'[[ВП:МТЗП',u'[[ВП:ФУТ', \
                   u'[[ВП:ВНГ',u'[[ВП:С',u'[[ВП:СПИСКИ',u'[[ВП:ИНФСП', \
                   u'|anime',u'|bio',u'|okz',u'|org',u'|po', \
                   u'[[ВП:КОСП',u'|notability',u'|nb=0']

#список комбинаций символов, которые однозначно указывают на проблемы
#с изображением
ImageProblemTemplate = [u'{{speedydelete',u'{{delete', \
                        u'{{template deletion request',u'{{no ', \
                        u'{{speedydelete',u'{{изображение/нет ', \
                        u'{{disputed',u'{{db-',u'{{к удалению', \
                        u'remove this line and insert a license instead']

#то, что нужно вырезать перед проверкой
ArtifactList = [u'[[Википедия:Сноски]]', \
                u'примеры использования тэгов <ref></ref>', \
                u'[[:Категория вместо [[Категория',u'[[en:название статьи]]', \
                u'[[файл:Example.jpg]]',u'[[:Категория:]]',u'[[:en:]]']


class TRequirement:
  
  def __Init__(self, page):
    #страница
    self.Page = page
    #страница обсуждения страницы Page
    self.TalkPage = page.toggleTalkPage()
    #текст замечания
    self.ReqText = ''
    #текст отчёта о проверке
    self.Report = u'== Отчёт о проведённой проверке ==\n'
    #текст страницы обсуждения статьи
    self.TalkPageText = ''
    
    #True, если в статье есть шаблон {{редактирую}}
    self.InWork = False
    #True, если найдены недочёты
    self.NeedRequirement = False
    #True, если нет категорий
    self.NoCategory = False
    #True, если нужно уточнить категории
    self.OneCategory = False
    #True, если в тексте нет ни одной внутренней ссылки
    self.NotWikifyed = False
    #Длина (размер) статьи
    self.Length = 0
    #True, если статья очень маленькая
    self.Stub = False
    #True, если есть теги <br>
    self.HasBr = False
    #True, если нет сносок
    self.Refless = False
    #True, если статья подписана
    self.Signed = False
    #True, если статья привязана к времени
    self.Temporal = False
    #количество плохих слов в статье
    self.Epithet = 0
    #True, если есть фразы, указывающие на территориальную принадлежность читателя
    self.OutLand = False
    #True, если есть пробелы в начале строки
    self.HasSpace = False
    #True, если есть пробелы с изображениями
    self.BadImage = False
    #True, если есть неправильно оформленные ссылки
    self.BadLink = False
    #True, если есть "в Украине"
    self.InUkraine = False


  #определяет, нужно ли писать замечания
  def Need(self):
    if ((self.NoCategory or self.NotWikifyed or self.Stub or self.HasBr or \
         self.Refless or self.Signed or (self.Epithet > 2) or self.Temporal \
         or self.HasSpace or self.OutLand or self.BadImage or self.BadLink or \
         self.InUkraine or self.OneCategory) 
        and not self.InWork):
      nnn = True
    else:
      nnn = False
    return nnn

  #проверяет статью
  def CheckPage(self):
    
    #проверяет статью, если она существует
    if self.Page.exists():   
      pagetext = self.Page.get()
      #вырезает артефакты шаблонной страницы, могущих исказать
      #результаты проверки
      for art in ArtifactList:
        pagetext = pagetext.replace(art,'')

      #если есть шаблон {{редактирую}}, то статья вообще не проверяется
      self.InWork = (pagetext.find(u'{{редактирую|') != -1)
      
      #проверяет размер (длину) статьи, если он меньше 1000, то Stub становится True
      self.Length=len(pagetext)+1
      if self.Length < 1000:
        self.Stub = True
        self.Report += u'* Длина статьи: '+str(self.Length)+\
          u'. Статья оценена как короткая.\n'
      else:
        self.Report += u'* Длина статьи: '+str(self.Length)+\
          u'. Размер статьи достаточен.\n' 

      #проверяет наличие ссылок вида http://ru.wikipedia.org/...
      search = pagetext.find(u'http://ru.wikipedia.org/')  
      if search != -1:
        self.BadLink = True
        self.Report += u'* Найдены неформатные ссылки. Количество:'+\
          str(pagetext.count(u'http://ru.wikipedia.org/'))+\
          u'. Первое вхождение начинается с символа '+str(search)+u'.\n'
      else:
        self.Report += u'* Неформатные ссылки не найдены.\n'

      #проверяет, есть ли в статье категории, если нет, то NoCategory 
      #становится True
      if pagetext.find(u'Категория:') == -1:
        self.NoCategory = True
        self.Report += u'* Категории не найдены.\n'
      else:
        self.Report += u'* Статья категоризована.\n'

      #Проверяет, есть ли в статье категория Персоналии по алфавиту
      #Если она есть и других категорий нет, то OneCategory становится True
      if not self.NoCategory:
        if pagetext.find(u'[[Категория:Персоналии по алфавиту]]') != -1:
          pagetext.replace(u'[[Категория:Персоналии по алфавиту]]',u'')
          if pagetext.find(u'Категория:') == -1:
            self.OneCategory = True
            self.Report += u'* Категоризация статьи недостаточна.\n'
          else:
            self.Report += u'* Предположительно, категоризация статьи достаточна.\n'
        else:
          self.Report += u'* Предположительно, категоризация статьи достаточна.\n'  

      #проверяет наличие тегов br, если они есть, то HasBr становится True
      #считаем количество тегов
      search = pagetext.count(u'<br/>') + pagetext.count(u'<br>') +\
               pagetext.count(u'<br />')
      if search != 0:
        self.HasBr = True
        self.Report += u'* Теги br присутствуют. Всего их '+str(search)+u'.\n'
      else:
        self.Report += u'* Теги br не найдены.\n'

      #проверяет наличие сносок, если их нет, то Refless становится True
      if pagetext.find(u'<ref') == -1 and pagetext.find(u'{{sfn|}}') == -1:
        self.Refless = True
        self.Report += u'* Сносок нет.\n'
      else:
        self.Report += u'* Сноски есть.\n'

      #проверяет наличие подписи в самой статье, если она есть, то Signed 
      #становится True
      search = pagetext.find(u'[[Участник:')
      if search == -1:
         search = pagetext.find(u'[[User:')
      if search != -1:
        self.Signed = True
        self.Report += u'* В статье найдена подпись. Начинается с символа '+\
          +u'номер '+str(search)+u'.\n'             
      else:
        self.Report += u'* В статье не найдена подпись.\n'

      #проверяет наличие пробелов в начале строки, если они есть, то HasSpace 
      #становится True
      #???

      #составляет список изображений в статье
      ImageList = self.Page.imagelinks()
      if ImageList != []:
        self.Report += u'* В статье есть иллюстрации.\n'
      #перебор изображений по списку
      for img in ImageList:
        if not self.BadImage:        #чтобы не проверять лишний раз
          #если изображение есть, но не существует, значит оно на Викискладе
          if not img.exists():
            #достаём изображение с Викисклада
            img = wikipedia.Page(comm, img.title().replace(u'Файл',u'File'))           
          if img.exists():
            #чтение текста страницы изображения с опусканием шрифта для
            #последующего поиска в нём шаблонов
            if not img.isRedirectPage():
              imgText = img.get().lower()
            else:
              imgText = '';
            #поиск шаблонов, сообщающих о проблемах
            for ipt in ImageProblemTemplate:
              if not self.BadImage:
                if imgText.find(ipt) != -1:
                  self.BadImage = True
                  self.Report += u'**Изображение <nowiki>'+img.title()+\
                    u'</nowiki> - проблемы.\n'
            if not self.BadImage:
              self.Report += u'**Изображение <nowiki>'+img.title()+\
                u'</nowiki> - нет проблем.\n'
          else:
            self.Report += u'**Ошибка, изображения <nowiki>'+img.title()+\
              u'</nowiki> не существует.\n'
        else:
          self.Report += u'**Изображение <nowiki>'+img.title()+\
            u'</nowiki> - не проверялось из соображений производительности.\n'

      #удаляет подпись (если она есть) перед проверкой на наличие внутренних
      #ссылок, если они есть
      if self.Signed:
        pagetext = pagetext.replace(u'[[Участник:','')
        pagetext = pagetext.replace(u'[[User:','')
      #проверяет, есть ли в статье внутренние ссылки, если нет, то NotWikifyed
      #становится True
      if (pagetext.find(u'[[') == -1) or (pagetext.find(u']]') == -1):
        self.NotWikifyed = True
        self.Report += u'* Не найдено внутренних ссылок.\n'
      else:
        self.Report += u'* Есть минимальная викификация.\n'

      #приводит текст к нижнему регистру для дальнейшей проверки по спискам
      #слов и выражений
      pagetext = pagetext.lower()

      #проверяет наличие словосочетания "в Украине"
      if pagetext.find(u'в украине') != -1:
        self.InUkraine = True
        self.Report += u'* Найдена фраза «в Украине».\n'
      else:
        self.Report += u'* Фраза «в Украине» не найдена.\n'
      
      #проверяет наличие фраз, выдающих привязку к настоящему времени, если
      #они есть, то Temporal становится True
      for substr in TimeList:
        if pagetext.find(substr) != -1:
          self.Temporal = True
          self.Report += u'* Найдено предположительно неуместное выражение «'+\
            substr+u'».\n'

      #проверяет наличие фраз, указывающих на территориальную принадлежность
      #читателя, если они есть, то OutLand становится True
      for substr in OutLandList:
        if pagetext.find(substr) != -1:
          self.OutLand = True
          self.Report += u'* Найдено предположительно неуместное выражение «'+\
            substr+u'».\n'

      #проверяет наличие ненейтральных слов, их количество записывается
      #в Epithet
      for substr in StyleList:
        self.Epithet += pagetext.count(substr)
      self.Report += u'* Количество ненейтральных слов и выражений:'+\
        str(self.Epithet)+u'.\n'
        
    #если бот нашёл ошибки, в обратном случае проверять СО не надо
    if self.Need(): 
      #проверяет страницу обсуждения, если она существует
      if self.TalkPage.exists():
        self.TalkPageText = self.TalkPage.get()

        #проверяет, нет ли тех же замечаний в составе шаблона irm,
        #расположенном на СО
        if self.TalkPageText.find(u'{{irm|') != -1:
          if self.NoCategory:
            if self.TalkPageText.find(u'|cat') != -1:
              self.NoCategory = False
          if self.OneCategory:
            if self.TalkPageText.find(u'|recat') != -1:
              self.OneCategory = False
          if self.NotWikifyed:
            if self.TalkPageText.find(u'|wikify') != -1:
              self.NotWikifyed = False
              self.HasBr = False
              self.BadLink = False
          if self.Stub:
            if self.TalkPageText.find(u'|stub') != -1:
              self.Stub = False
          if self.Refless:
            if self.TalkPageText.find(u'|ref') != -1:
              self.Refless = False
          if self.Temporal:
            if self.TalkPageText.find(u'|ethernal') != -1:
              self.Temporal = False
          if self.BadImage:
            if self.TalkPageText.find(u'|img') != -1:
              self.BadImage = False
          if self.OneCategory:
            if self.TalkPageText.find(u'|recat') != -1:
              self.OneCategory = False
          if self.Epithet > 2:
            if (self.TalkPageText.find(u'|style') != -1) or \
               (self.TalkPageText.find(u'|ntz') != -1):
              self.Epithet = 0

    #проверяет, нужно ли оставлять замечания, результат проверки
    #записывается в NeedRequirement
    #если замечания есть и нет команды не проверять статью
    if (self.Need()) and \
       (self.TalkPageText.find(u'Бот, не проверяй статью.') == -1):
      self.Report += u'В ходе проверки статьи были обнаружены недостатки. '
      self.NeedRequirement = True
      for nb in NatabilityLinks:
        if self.NeedRequirement:
          if pagetext.find(nb)!= -1:
            self.NeedRequirement = False  #то выписывается замечание
        else:
          self.Report += u'Высказаны претензии к значимости предмета статьи. \
            Согласно текущему консенсусу, в этом случае замечания бота не \
            публикуются.'
    else:
      self.Report += u'В ходе автоматической проверки статьи недостатки \
        обнаружены не были или была получена инструкция не проверять данную \
        статью.'

  #генерирует текст с замечаниями
  def CreateRequirement(self):
    
    #начало замечания
    self.ReqText=u'{{Участник:AJZBot/Вводная фраза}}\n'
    
    #если нет категорий
    if self.NoCategory:    
      self.ReqText +=u'{{Участник:AJZBot/Нет категорий}}\n'

    #если недостаточно категорий
    if self.OneCategory:    
      self.ReqText +=u'{{Участник:AJZBot/Недостаточная категоризация}}\n'
      
    #если нет внутренних ссылок
    if self.NotWikifyed:
      self.ReqText +=u'{{Участник:AJZBot/Нет внутренних ссылок}}\n'

    #неправильно оформленные внутренние ссылки
    if self.BadLink:
      self.ReqText +=u'{{Участник:AJZBot/Неправильные ссылки}}\n'

    #если нет сносок
    if self.Refless:
      self.ReqText +=u'{{Участник:AJZBot/Желательны сноски}}\n'

    #если статья слишком мальнькая
    if self.Stub:
      self.ReqText +=u'{{Участник:AJZBot/Стаб}}\n'

    #если есть теги br
    if self.HasBr:
      self.ReqText +=u'{{Участник:AJZBot/Тег br}}\n'

    #если есть подпись
    if self.Signed:
      self.ReqText +=u'{{Участник:AJZBot/Найдена подпись}}\n'

    #если есть фразы типа 'в настоящее время'
    if self.Temporal:
      self.ReqText +=u'{{Участник:AJZBot/Привязка ко времени}}\n'

    #если есть фразы типа 'за рубежом'
    if self.OutLand:
      self.ReqText +=u'{{Участник:AJZBot/Привязка к государству}}\n'

    #если есть словосочетания "в Украине"
    if self.InUkraine:
      self.ReqText +=u'{{Участник:AJZBot/Украина}}\n'

    #если есть проблемы с файлами
    if self.BadImage:
      self.ReqText +=u'{{Участник:AJZBot/Проблемы с файлами}}\n'

    #если есть существенные проблемы со стилем (больше 1 плохого слова на 3333 единиц размера)
    if self.Epithet/self.Length > 0.0003:
      self.ReqText +=u'{{Участник:AJZBot/Нейтральность}}\n'
    #если есть незначительные проблемы со стилем (больше 3 плохих слов)
    elif self.Epithet > 3:
      self.ReqText +=u'{{Участник:AJZBot/Стиль}}\n'

    #конец замечания
    self.ReqText +=u'{{Участник:AJZBot/Завершающая фраза}} --~~~~'

  #очистка страницы обсуждения от результатов предшествующей деятельности бота
  def ClearTalkPage(self):
    #ищем начало предыдущего замечания
    ReqStart=self.TalkPageText.rfind(u'{{Участник:AJZBot/Вводная фраза}}')
    #ищем конец предыдущего замечания
    ReqFinish=self.TalkPageText.rfind(u'AJZBot/Завершающая фраза}}')
    #если начало и конец найдены т.е. замечание было
    if (ReqStart != -1) and (ReqFinish != -1):
      #вставляем новое замечание на место предыдущего
      #77 = 26 + 51, где 26 - длина строки 'AJZBot/Завершающая фраза}}'
      #а 51 - длина подписи бота
      self.TalkPageText = self.TalkPageText.replace(self.TalkPageText[(ReqStart):(ReqFinish+77)],\
                                self.ReqText)
    else:
      #вставляем новое замечание в отдельный раздел в конец страницы
      self.TalkPageText += u'\n \n== Замечания по статье ==\n' + self.ReqText
      

  #помещает текст с замечаниями на СО статьи
  def PrintRequirement(self):

    if self.TalkPage.exists():
      #очистка страницы обсуждения от результатов предшествующей деятельности бота
      self.ClearTalkPage()      
      #проверяет, нужно ли публиковать отчёт о проверке
      if self.TalkPageText.rfind(u'Бот, отчёт о проверке.') > \
         self.TalkPageText.rfind(u'<s>Бот, отчёт о проверке.</s>'):
        self.TalkPageText.replace(u'<s>Бот, отчёт о проверке.</s>',u'Бот, отчёт о проверке.')
        self.TalkPageText.replace(u'Бот, отчёт о проверке.',u'<s>Бот, отчёт о проверке.</s>')
        self.ReqText += u'\n\n'+self.Report+u'\n--~~~~'
      self.TalkPage.put(self.TalkPageText,comment=u'Замечания по статье',\
                        minorEdit=False)
    else:
      #помещает результат на СО статьи, не создавая раздела, так как страница
      #пустая
      self.TalkPage.put(self.ReqText,comment=u'Замечания по статье',\
                        minorEdit=False)
    
    #помещает информирующий шаблон вверху самой статьи
    add_text.add_text(self.Page,u'{{Инкубатор, автопроверка}}',\
                      summary=u'Уведомление о проверке',up=True,\
                      always = True)

class TBotController:

  def __Init__(self,page):
    #страница, на которой находятся инструкции для управления
    self.Page = page
    #Удалось ли получить инструкции со страницы Page
    self.Instructed = False
    #Работает ли бот
    self.Working = True
    #Список проверяемых каждый раз статей
    self.Always = []
    #Список не проверяемых статей
    self.Never = []
    #Начало списка проверяемых каждый раз статей
    self.beginAlways = -1
    #Конец списка проверяемых каждый раз статей
    self.endAlways = -1
    #Начало списка не проверяемых статей
    self.beginNever = -1
    #Конец списка не проверяемых статей
    self.endNever = -1

  #читает инструкции
  def ReadInstructions(self):
    if self.Page.exists():
      wikipedia.output(u'Центр управления существует')
      pagetext = self.Page.get()
      self.beginAlways = pagetext.find(u'== Каждый раз проверять статьи ==')
      self.endAlways = pagetext.find(u'== Не проверять статьи ==')
      self.beginNever = self.endAlways
      self.endNever = len(pagetext)
      if (self.beginAlways>-1) and (self.endAlways>-1) and\
         (self.beginNever>-1) and (self.endNever>-1):
        self.Instructed = True
        if (pagetext.find(u'Бот работает? <!-- (Да или Нет) --> Да') != -1):
          self.Working = True
          wikipedia.output(u'Получено разрешение на проверку')
        elif (pagetext.find(u'Бот работает? <!-- (Да или Нет) --> Нет') != -1):
          self.Working = False
          wikipedia.output(u'Разрешение на проверку не получено')
        else:
          self.Instructed = False
          wikipedia.output(u'Инструкции не получены')

  def InstructionRead(self):
    answer = (self.Instructed and self.Working)
    if answer:
      wikipedia.output(u'Начата проверка')
    else:
      wikipedia.output(u'Проверка отменена')
    return answer

site = wikipedia.getSite()                      #Википедия
comm = wikipedia.getSite('commons','commons')   #Викисклад

Controller=TBotController()

#перебор статей, входящих в GoodCategory и не входящих в BadCategory
#одновременно
Controller.__Init__(wikipedia.Page(site,u'ru:Участник:AJZBot/Центр управления'))
Controller.ReadInstructions()
if Controller.InstructionRead():
  GoodCategory = set(catlib.Category(site, u"Категория:Википедия:Прошу \
проверить мою статью на соответствие правилам").articles())
  BadCategory = set(catlib.Category(site, u"Категория:Википедия:Статьи \
инкубатора, проверенные ботом").articles())
  Requirement=TRequirement()
  for page in GoodCategory.difference(BadCategory):      
    try:                                        #на всякий случай
      #если страница существует и не является редиректом
      if page.exists() and not page.isRedirectPage():
        Requirement.__Init__(page)
        if Requirement.Page.namespace()==102 and  \
          Requirement.TalkPage.namespace()==103 and \
          Requirement.Page.exists():
          Requirement.CheckPage()                #проверка статьи
          if Requirement.NeedRequirement:        #если нужны замечания
            Requirement.CreateRequirement()      #создать текст замечания
            #поместить текст замечания на СО и шаблон в статью
            Requirement.PrintRequirement()       
            wikipedia.output(u'Есть замечания по статье ')
          else:
            wikipedia.output(u'Нет замечаний по статье')
          print(page)
    except:
      wikipedia.output(u'Не получилось со статьёй ')
      print(page)
  wikipedia.output(u'Проверка завершена')