利用者:Mizusumashi/Bot/version history table.py

# -*- coding: utf-8 -*-
"""
This script is under public domain, and comes with ABSOLUTELY NO WARRANTY.
You can use/modify/redistribute without any permission.

このスクリプトの著作権は放棄され、このスクリプトはパブリックドメインにあります。
このスクリプトは完全に無保証です。このスクリプトの動作については全く何も保証されておらず、このスクリプトを使用したいかなる結果についても責任は負われません。

このスクリプトは、ウィキペディアの履歴ページから変更履歴を取得し、wikiマークアップによる表の形式に変換して、ローカルファイルに保存します。

-page             変更履歴を取得するページを指定します。
                  デフォルト値は設定されていませんが、コマンドラインパラメータ
                  で指定されていなければ、対話インターフェースで指定できます。

-file             変更履歴を保存するローカルファイルの名前を指定します。
                  デフォルト値は、「履歴.txt」になっています。

-encoding         ローカルファイルに保存するエンコーディングを指定します。
                  お使いの環境で、Pythonのcodecsモジュールが認識できるエンコー
                  ディングを指定してください。デフォルト値は、「utf-8」が指定さ
                  れています。
"""

import codecs, re
import wikipedia

def _getVersionHistory(page, start):
    path = ('/w/api.php'
            '?action=query'
            '&prop=revisions'
            '&rvprop=ids|flags|timestamp|user|comment|size'
            '&rvlimit=500'
            '&format=xml')
    path += '&titles=' + page.urlname()
    if start:
        path += '&rvstartid=' + str(start)

    data = page.site().getUrl(path)
    
    result = []
    end = None
    for tm in re.finditer(r'<rev ([^>]+)/>', data):
        rev = {}
        for pm in re.finditer(r'(\S+)\s*=\s*"([^"]*)"', tm.group(1)):
                key = wikipedia.html2unicode(pm.group(1))
                value = wikipedia.html2unicode(pm.group(2))
                rev[key] = value
                if key == 'revid':
                    end = int(value)
        result += [rev]
    print data

    return result, end

def getVersionHistory(page):
    result = []
    history, end = _getVersionHistory(page, None)
    result += history
    
    while end:
        history, end = _getVersionHistory(page, end - 1)
        result += history

    return result

def parse(s):
    r = ''
    while s:
        m = re.match('\[\[:?(?P<link>[^\|\]]*)\]\](?P<rest>(.|\n)*)', s)
        if m:
            r += u'[[:%s|%s]]' % (m.group('link'), m.group('link'))
            s = m.group('rest')
            continue

        m = re.match(r'\[\[:?(?P<link>[^\|\]]*)\|(?P<name>[^\]]*)\]\](?P<rest>(.|\n)*)',
                     s)
        if m:
            r += u'[[:%s|%s]]' % (m.group('link'), m.group('name'))
            s = m.group('rest')
            continue
        ec = {'|': '&#x6C;',
              '{': '&#x7B;',
              '}': '&#x7D;',
              '[': '&#x5B;',
              ']': '&#x5D;',
              '<': '&lt;',
              '>': '&gt;',
              '\n': ' '}
        r += ec.get(s[0], s[0])
        s = s[1:]
    return r

def createVersionHistoryTable(history,
                              page,
                              forceReload=False,
                              reverseOrder=False,
                              getAll=False,
                              revCount=500,
                              title = None,
                              oldid = 'oldid',
                              date = 'date/time',
                              username = 'username',
                              summary = 'edit summary',
                              talk = 'Talk',
                              log = 'contribs',
                              style = 'class = "wikitable plainlinks"'):

    hostname = page.site().hostname()
    path = hostname + page.site().path()

    result = u'{| %s\n' % style
    if title:
        result += u'|+ %s\n' % title
    result += u'! %s || %s || %s || %s\n' \
              % (oldid, date, username, summary)

    count = len(history)
    for rev in history:
        revid = '[http://%s?oldid=%s %s]' \
                % (path, rev['revid'], rev['revid'])
        revid += '<!--' + rev['revid'] + '-->'

        timestamp = re.sub(r'(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})Z',
                           r'\g<1>-\g<2>-\g<3> \g<4>:\g<5>:\g<6>',
                           rev['timestamp'])
        timestamp += '<!--' + rev['timestamp'] + '-->'

        if 'anon' not in rev:
            user = (u'<span style="white-space: nowrap">' \
                    + u'[[User:%(u)s|%(u)s]]</span> ' +\
                    u'<span style="white-space: nowrap">' \
                    + u'([[User talk:%(u)s|%(t)s]] | ' \
                    + u'[[Special:Contributions/%(u)s|%(l)s]])</span>') \
                   % {'u': rev['user'], 't': talk, 'l': log}
        else:
            user = (u'<span style="white-space: nowrap">' \
                    + u'[[Special:Contributions/%(u)s|%(u)s]]</span> ' +\
                    u'<span style="white-space: nowrap">' \
                    + u'([[User talk:%(u)s|%(t)s]])</span>') \
                   % {'u': rev['user'], 't': talk}
        user +=  '<!--' + rev['user'] + '-->'

        if 'comment' not in rev:
            comment = ''
        else:
            m = re.match(r'(?P<pre>(.|\n)*)'
                         r'/\*\s*(?P<section>([^\*]|(\*(?!/)))*([^\s\*]|(\*(?!/))))\s*\*/'
                         r'(?P<post>(.|\n)*)',
                         rev['comment'])
            if not m:
                comment = parse(rev['comment'])
            else:
                comment = parse(m.group('pre'))
                comment += u'<span class="autocomment">'
                if m.group('pre'):
                    comment += u'- '
                comment += u'[[%s#%s|→]]<span />%s' % (page.title(), m.group('section'), m.group('section'))
                if m.group('post'):
                    comment += u': '
                comment += u'</span>'
                comment += parse(m.group('post'))
            comment2 = re.sub(r'&', r'&amp;', rev['comment'])
            comment2 = re.sub(r'<!--', r'&lt;--', comment2)
            comment2 = re.sub(r'-->', r'--&gt;', comment2)
            comment += '<!--' + comment2 + '-->'

        result += u'|-<!--%d-->\n' % count+\
                u'| style="vertical-align: top; white-space: nowrap" | %s\n' % revid  +\
                u'| style="vertical-align: top; white-space: nowrap" | %s\n' % timestamp  +\
                u'| style="vertical-align: top" | %s\n' % user  +\
                u'| style="vertical-align: top" | %s\n' % comment
        count -= 1

    result += '|}'

    return result

def main():
    title = None
    page = None
    output = 'version_history.txt'
    encoding = 'utf-8'

    for arg in wikipedia.handleArgs():
        if arg[:6] == '-page:':
            title = unicode(arg[6:])
        elif arg[:6] == '-file:':
            output = unicode(arg[6:])
        elif arg[:9] == '-encoding':
            encoding = unicode(arg[9:])
        else:
            wikipedia.output('ERROR: wrong parameter: ' + arg)

    site = wikipedia.getSite()
    if title:
        page = wikipedia.Page(site, title)
        if not page.exists():
            wikipedia.output('ERROR: page does not exist: ' + title)
            return

    while not page:
        title = wikipedia.input('Please input page name:')
        try:
            p = wikipedia.Page(site, title)
        except:
            p = None

        if p and p.exists():
            page = p
        else:
            wikipedia.output('ERROR: page does not exist: ' + title)

    history = getVersionHistory(page)
    text = createVersionHistoryTable(history,
                                     page,
                                     title = None,
                                     oldid = 'oldid',
                                     date = u'投稿日時(UTC)',
                                     username = u'投稿者',
                                     summary = u'編集内容の要約',
                                     talk = u'会話',
                                     log = u'投稿履歴')

    text = \
u"""= 履歴 (History) =
""" + text + u"""
* この表は、[[Help:履歴|履歴ページ]]における[[Help:要約欄|要約欄]]での指定によって、<span class="plainlinks">[http://www.gnu.org/licenses/fdl.html GNU Free Documentation License]</span> 上の履歴 (History)に含まれます([[Wikipedia:著作権#総則]]をご参照ください)。
* 技術的理由などにより、この表の「編集内容の要約」は投稿時のものと異なっている場合があります。
* この表と変更履歴ページの内容に重複がある場合は、変更履歴ページの内容を優先することとします。
"""

    f = codecs.open(output, 'w', encoding)
    f.write(text)
    f.close

    wikipedia.output('History Table(%d) are saved in \'%s\'' \
                     % (len(history), output))
    
if __name__ == '__main__':
    try:
        main()
    finally:
        wikipedia.stopme()