사용자:Utoleetest/libre wikistat

< 사용자:Utoleetest
Utoleetest (토론 | 기여)님의 2021년 8월 13일 (금) 00:53 판 (소스 대폭 개선했음.)
(차이) ← 이전 판 | 최신판 (차이) | 다음 판 → (차이)

위키/목록에서 위키의 문서 수/총 페이지 수 통계를 갱신할 때 이용되는 파이썬 스크립트입니다. Pywikibot을 통해 돌아갈 수 있게 설게했습니다.

사용방법

  1. 우선 파이썬을 설치한 후, 시스템의 환경변수를 추가해서 커맨드 창에서 파이썬이 작동하게 설정합니다.
  2. 그 다음 PIP 설치방법 안내 페이지를 이용해서 PIP 패키지를 설치합니다.
  3. PIP를 설치했으면 커맨드 창에 PIP install selenium을 입력해 selenium 패키기를 설치합니다.
  4. 다음 링크를 이용해서 크롬 브라우저용 Chromedriver를 다운로드 받습니다. 반드시 pwb.py가 있는 곳에 chromedriver 실행 프로그램이 있어야 합니다.
  5. 다음 아래의 소스코드를 복사/붙여넣기 후에 pywikibot이 설치된 폴더에서 scripts/userscripts에 libre_wikistat.py로 저장합니다.(커스텀 스크립트를 저장할 수 있는 곳)
  6. 다 준비가 되었다면 cd C:/(Pywikibot이 설치된 카테고리) 명령어를 이용해 Pywikibot이 있는 폴더로 이동한 뒤에 커맨드 창에
> python pwb.py libre_wikistat

이라고 입력하면 작동합니다. 상당히 지저분한 코드인 검을 유감스럽게 생각합니다.

스크립트 소스

from selenium import webdriver
import re
import datetime
import time
import pywikibot


# import pickle
# import os

# 숫자 반점으로 끊어주는 함수
def digit_div(msg):
    # 우선 arg에서 온점, 띄어쓰기 등 없애기
    msg = str(msg).replace('.', '').replace(' ', '').replace(',', '').replace('٬', '')
    str_new = str(format(int(msg), ','))
    return str_new


# 문자열 한 자리면 0 강제삽입
def zeroinput(_str):
    if len(_str) == 0:
        return '00'
    elif len(_str) == 1:
        return '0' + _str
    else:
        return _str


# 미디어위키 데이터 통계
# "dc": [article_num, page_num, whole_edit, whole_user, active_user]
MW_WIKI_DATA = {}

# 다른 위키 데이터 통계
# "namu": [article_num, page_num], 없으면 None으로 처리
OTHER_WIKI_DATA = {}

# 미디어위키 통계 - 위키 기호- url 입력
MW_WIKI = {
    # 한국어 사이트
    'nuri': 'https://nuriwiki.net/wiki/',  # 누리위키
    'dc': 'https://wiki.dcinside.com/wiki/',  # 디시위키
    "ligame": 'https://libertygame.miraheze.org/wiki/',  # 리버티게임
    'unam': 'https://www.unamwiki.org/w/',  # 우남위키
    'wikis': 'https://wikis.krosocsi.org/index.php?title=',  # 위키스
    'licentium': 'https://www.licentium.net/wiki/',  # 자유인사전
    'jwiki': 'http://jwiki.kr/wiki/index.php/',  # 제이위키
    'zeta': 'https://zetawiki.com/wiki/',  # 제타위키
    'jinbo': 'https://jinbowiki.org/wiki/index.php/',  # 진보위키
    'truth': 'https://truth.miraheze.org/wiki/',  # 진실위키
    'coin': 'http://wiki.hash.kr/index.php/',  # 코인위키
    'bigfo': 'https://bigforest.miraheze.org/wiki/',  # 큰숲백과
    'footk': 'http://footballk.net/mediawiki/',  # 풋케위키
    'femi': 'https://femiwiki.com/w/',  # 페미위키
    'kowiks': 'https://ko.wikisource.org/wiki/',  # 위키문헌
    'kowikq': 'https://ko.wikiquote.org/wiki/',  # 위키인용집
    'kowikb': 'https://ko.wikibooks.org/wiki/',  # 위키책
    'air': 'https://airtravelinfo.kr/wiki/index.php?title=',  # 항공위키
    'bujok': 'https://bujok.fandom.com/ko/wiki/',  # 부족전쟁위키
    'poke': 'https://pokemon.fandom.com/ko/wiki/',  # 포켓몬 위키
    'kofandom': 'https://community.fandom.com/ko/wiki/',  # 팬덤 중앙 커뮤니티
    'kouncyclo': 'https://uncyclopedia.kr/wiki/',  # 백괴사전
    # 영어 사이트
    'enwikb': 'https://en.wikibooks.org/wiki/',  # wikibooks
    'enwikn': 'https://en.wikinews.org/wiki/',  # wikinews
    'enwikq': 'https://en.wikiquote.org/wiki/',  # wikiquote,
    'enwiks': 'https://en.wikisource.org/wiki/',  # wikisource
    'mw': 'https://mediawiki.org/wiki/',  # medeawiki
    'wimeta': 'https://meta.wikimedia.org/wiki/',  # wikimedia meta
    'common': 'https://commons.wikimedia.org/wiki/',  # wikimedia commons
    'widata': 'https://www.wikidata.org/wiki/',  # wikidata
    'fandom': 'https://community.fandom.com/wiki/',  # fandom central community
    'att': 'https://allthetropes.org/wiki/',  # All The Tropes
    'bulba': 'http://bulbapedia.bulbagarden.net/wiki/',  # Bulbapedia
    'conserv': 'https://conservapedia.com/',  # Conservapedia
    'dcdata': 'https://dc.fandom.com/wiki/',  # DC Database
    'family': 'https://familypedia.wikia.org/wiki/',  # Familypedia
    'mariowiki': 'https://mariowiki.com/',  # Mariowiki
    'minecraft': 'https://minecraft.fandom.com/wiki/',  # Minecraft Wiki
    'rational': 'https://rationalwiki.org/wiki/',  # Rational Wiki
    'uncyclo': 'http://en.uncyclopedia.co/wiki/',  # Uncyclopedia
    'starwars': 'https://starwars.fandom.com/wiki/',  # Wookiepedia
    'wowpedia': 'https://wowpedia.fandom.com/wiki/',  # WowPedia
}

# 각 언어별 위키백과 목록
WIKIPEDIA_LANG = [
    'arwiki',
    'dewiki',
    'enwiki',
    'eswiki',
    'frwiki',
    'idwiki',
    'itwiki',
    'jawiki',
    'kowiki',
    'nlwiki',
    'plwiki',
    'ptwiki',
    'ruwiki',
    'srwiki',
    'svwiki',
    'ukwiki',
    'viwiki',
    'zhwiki'
]

# 각 언어별 위키낱말사전 목록
WIKTIONARY_LANG = [
    'dewikt',
    'enwikt',
    'frwikt',
    'kowikt',
    'ruwikt'
]


# 미디어위키 계열 위키 반복 프로세스

def mw_process(_str):
    global driver, MW_WIKI
    # 홈페이지 불러오기.
    if 'wiki' in _str:
        url = 'https://{}.wikipedia.org/wiki/special:statistics/'.format(_str[0:2])
    elif 'wikt' in _str:
        url = 'https://{}.wiktionary.org/wiki/special:statistics/'.format(_str[0:2])
    else:
        url = MW_WIKI[_str]+"special:statistics/"
    driver.get(url)
    time.sleep(1)
    MW_WIKI_DATA[_str] = []
    d1 = driver.find_element_by_xpath('//*[@id="mw-content-text"]/table/tbody/tr[2]/td[2]').text
    d2 = driver.find_element_by_xpath('//*[@id="mw-content-text"]/table/tbody/tr[3]/td[2]').text
    # 미디어 파일 통계가 잡히지 않는 스페인어 위키백과/스웨덴어 위키백과/bulbapedia는 데이터 수집 보정을 해야 한다.
    if _str in ['eswiki', 'svwiki', 'bulba', 'widata', 'enwikq']:
        d3 = driver.find_element_by_xpath('//*[@id="mw-content-text"]/table/tbody/tr[5]/td[2]').text
        d4 = driver.find_element_by_xpath('//*[@id="mw-content-text"]/table/tbody/tr[8]/td[2]').text
        d5 = driver.find_element_by_xpath('//*[@id="mw-content-text"]/table/tbody/tr[9]/td[2]').text
    # 나머지 위키들
    else:
        d3 = driver.find_element_by_xpath('//*[@id="mw-content-text"]/table/tbody/tr[6]/td[2]').text
        d4 = driver.find_element_by_xpath('//*[@id="mw-content-text"]/table/tbody/tr[9]/td[2]').text
        d5 = driver.find_element_by_xpath('//*[@id="mw-content-text"]/table/tbody/tr[10]/td[2]').text

    MW_WIKI_DATA[_str] = [digit_div(d1), digit_div(d2), digit_div(d3), digit_div(d4), digit_div(d5)]
    print(MW_WIKI_DATA[_str])


# 나머지 위키 패턴
# '위키명': ['stat_url', 'article_stat_value_xpath', 'page_stat_value_xpath']
WIKI_ARTICLE = {
    'nosm': ['http://no-smok.net/nsmk/SystemInfo', None, '//*[@id="macro-1"]'],  # 노스모크
    # 'scpko' - 단순 매크로로 긁어오기 어려운 구조
    'namu': [
        'https://namu.wiki/w/%EB%82%98%EB%AC%B4%EC%9C%84%ED%82%A4:%ED%86%B5%EA%B3%84',
        '//*[@id="app"]/div/div[2]/article/div[3]/div[2]/div/div/div[5]/table/tbody/tr[2]/td[2]/div',
        '//*[@id="app"]/div/div[2]/article/div[3]/div[2]/div/div/div[5]/table/tbody/tr[1]/td[2]/div'
    ],  # 나무위키
    'alpha': [
        'https://awiki.theseed.io/w/%EC%95%8C%ED%8C%8C%EC%9C%84%ED%82%A4:%ED%86%B5%EA%B3%84/i',
        '//*[@id="app"]/div/section[2]/div/div/div/div[2]/div/div/div[2]/table/tbody/tr[3]/td[2]/div',
        '//*[@id="app"]/div/section[2]/div/div/div/div[2]/div/div/div[2]/table/tbody/tr[2]/td[3]/div'
    ],  # 알파위키
    'veda': [
        'http://rigvedawiki.net/w/%EC%8B%9C%EC%8A%A4%ED%85%9C%EC%A0%95%EB%B3%B4',
        '//*[@id="macro-3"]',
        '//*[@id="macro-1"]'
    ],  # 리그베다 위키
    # open- 조작이 필요- 별도처리
    # 더위키 - 조작이 필요
    # 바다위키 - 조작이 필요 - 별도처리
    # 시드위키 - 조작 필요
    'zero': [
        'https://wiki.zeropage.org/wiki.php/TitleIndex',
        '//*[@id="macro-3"]',
        '//*[@id= "macro-1"]'
    ]  # 제로위키
}


def patterned_process(_str):
    global driver, WIKI_ARTICLE, OTHER_WIKI_DATA

    url = WIKI_ARTICLE[_str][0]
    driver.get(url)
    time.sleep(1)

    if WIKI_ARTICLE[_str][1] is not None:
        v1 = driver.find_element_by_xpath(WIKI_ARTICLE[_str][1]).text
        v1 = digit_div(v1)
    else:
        v1 = None
    if WIKI_ARTICLE[_str][2] != None:
        v2 = driver.find_element_by_xpath(WIKI_ARTICLE[_str][2]).text
        v2 = digit_div(v2)
    else:
        v2 = None

    OTHER_WIKI_DATA[_str] = [v1, v2]
    print(OTHER_WIKI_DATA[_str])


driver = webdriver.Chrome()

#  위키백과+위키낱말사전 통합 통계
for pattern in WIKIPEDIA_LANG + WIKTIONARY_LANG:
    try:
        mw_process(pattern)
    except:
        pass

# 나머지 미디어위키 통합 통계
for pattern in MW_WIKI.keys():
    try:
        mw_process(pattern)
    except:
        pass

# 나머지 위키 중 패턴 있는 위키들 통합 통계
for pattern in WIKI_ARTICLE.keys():
    try:
        patterned_process(pattern)
    except:
        pass

# scp 한국어위 통계 - 단독통계
try:
    driver.get('http://ko.scp-wiki.net/system:list-all-pages')
    time.sleep(1)
    txt = driver.find_element_by_xpath('//*[@id="page-content"]/div[1]/p').text
    txt = txt.replace('전체 페이지 수: ', '')
    OTHER_WIKI_DATA['scpko'] = [None, digit_div(txt)]
    print(OTHER_WIKI_DATA['scpko'])
except:
    pass

# 오픈위키 통계

try:
    driver.get('http://openwiki.kr/about/')
    time.sleep(1)
    open_1 = driver.find_element_by_xpath('//*[@id="dokuwiki__content"]/div/div[2]/div[19]/ul/li[2]/ul/li[1]/div/em').text
    open_2 = driver.find_element_by_xpath('//*[@id="dokuwiki__content"]/div/div[2]/div[19]/ul/li[2]/ul/li[2]/div/em').text
    OTHER_WIKI_DATA['open'] = [format(int(open_1), ','), format(int(open_1) + int(open_2), ',')]
    print(OTHER_WIKI_DATA['open'])
except:
    pass

# 더위키 통계
try:
    driver.get('https://thewiki.kr/w/TheWiki:%ED%86%B5%EA%B3%84')
    time.sleep(1)
    thewiki_data = driver.find_element_by_xpath('/html/body/div[2]/article/div[3]/div/ul[1]/li').text
    thewiki_stat = thewiki_data[24:29]
    OTHER_WIKI_DATA['thewiki'] = [thewiki_stat, None]
    print(OTHER_WIKI_DATA['thewiki'])
except:
    pass

# 바다위키 통계
try:
    driver.get('https://bada.wiki/w/%EB%B0%94%EB%8B%A4%EC%9C%84%ED%82%A4%3A%ED%86%B5%EA%B3%84')
    time.sleep(1)
    bada_data = driver.find_element_by_xpath('//*[@id="in_data_0"]')
    bada_stat = digit_div(bada_data.text[-8:-2])
    OTHER_WIKI_DATA['bada'] = [None, bada_stat]
    print(OTHER_WIKI_DATA['bada'])
except:
    pass

# 시드위키 통계
try:
    driver.get('https://seedwiki.xyz/title_index')
    time.sleep(1)
    seed_pages = driver.find_element_by_xpath('/html/body/div[3]/div[2]/div[2]/ul[2]/li').text.replace('전체 : ', '')
    seed_articles = driver.find_element_by_xpath('/html/body/div[3]/div[2]/div[2]/ul[3]/li[4]').text.replace('기타 : ','')
    OTHER_WIKI_DATA['seed'] = [format(int(seed_articles), ','), format(int(seed_pages), ',')]
    print(OTHER_WIKI_DATA['seed'])
except:
    pass

# TV Tropes 통계
try:
    driver.get('https://tvtropes.org/pmwiki/articlecount.php')
    time.sleep(1)
    trope_1 = driver.find_elements_by_xpath('//*[@id="wikimiddle"]/p[4]')
    trope_1 = trope_1[0].text.split('\n')
    for stats in trope_1:
        if 'Main' in stats:
            article_trope = stats.replace(': Main', '')
            break
    trope_2 = driver.find_element_by_xpath('//*[@id="wikimiddle"]/p[2]')
    page_trope = trope_2.text.replace('Total: ', '')
    OTHER_WIKI_DATA['trope'] = [format(int(article_trope), ','), format(int(page_trope), ',')]
    print(OTHER_WIKI_DATA['trope'])
except:
    pass

# 영어 SCP 통계
try:
    driver.get('http://www.scpwiki.com/system:list-all-pages/p/500')
    time.sleep(1)
    cnt1 = len(driver.find_elements_by_xpath('//*[@id="page-content"]/div/div')) - 1
    cnt2_item = driver.find_elements_by_class_name('current')[0]
    cnt2 = int(cnt2_item.text)
    OTHER_WIKI_DATA['scp'] = [None, format(50 * (cnt2 - 1) + cnt1, ',')]
    print(OTHER_WIKI_DATA['scp'])
except:
    pass

# WIKITREE 통계
try:
    driver.get('https://www.wikitree.com/')
    time.sleep(1)
    cnt_txt = driver.find_element_by_xpath('//*[@id="content"]/div/div[2]/div').text
    cnt = cnt_txt[18:28].strip()
    print(OTHER_WIKI_DATA['wikitree'])
except:
    pass

# 니코니코 대백과 통계 - 단독통계
try:
    driver.get('https://dic.nicovideo.jp/')
    time.sleep(1)
    text = driver.find_element_by_id("count-all-articles").text
    OTHER_WIKI_DATA['nico'] = [None, digit_div(text)]
except:
    pass

# 바이두 백과 통계
try:
    driver.get('https://baike.baidu.com')
    time.sleep(5)
    baidu_1 = driver.find_element_by_xpath('//*[@id="lemmaNum"]')
    OTHER_WIKI_DATA['baidu'] = [None, baidu_1.text]
except:
    pass

# pkl = open('wikistat.pkl', 'wb')
# pickle.dump(article_num, pkl)
# pickle.dump(page_num, pkl)
# pkl.close()

# 통계 작성 시점
x = datetime.datetime.now()
msg_date = '<!--date-->' + str(x.year) + '-' + str(x.month) + '-' + str(x.day)
msg_time = '<!--time-->' + zeroinput(str(x.hour)) + ':' + zeroinput(str(x.minute)) + '(KST)'

print('날짜:', msg_date)
print('시간:', msg_time)

driver.close()

# 위키/목록 텍스트 추출
site = pywikibot.Site('ko', 'libre')
page = pywikibot.Page(site, "위키/통계")
txt = page.text

# 통계 수정

# 미디어위키 기반 위키
for pat, dat in MW_WIKI_DATA.items():
    pat_1 = "<!--{}-->".format(pat)
    pat_2 = "<!--{}_2-->".format(pat)
    pat_3 = "<!--{}_3-->".format(pat)
    pat_4 = "<!--{}_4-->".format(pat)
    pat_5 = "<!--{}_5-->".format(pat)

    if len(dat) == 5:
        txt = re.sub(pat_1 + r"[0-9,]*", pat_1 + dat[0], txt)
        txt = re.sub(pat_2 + r"[0-9,]*", pat_2 + dat[1], txt)
        txt = re.sub(pat_3 + r"[0-9,]*", pat_3 + dat[2], txt)
        txt = re.sub(pat_4 + r"[0-9,]*", pat_4 + dat[3], txt)
        txt = re.sub(pat_5 + r"[0-9,]*", pat_5 + dat[4], txt)

# 나머지 위키들
for pat, dat in OTHER_WIKI_DATA.items():
    pat_1 = "<!--{}-->".format(pat)
    pat_2 = "<!--{}_2-->".format(pat)

    if len(dat) == 2 and dat[0] != None:
        txt = re.sub(pat_1 + r"[0-9,]*", pat_1 + dat[0], txt)
    if len(dat) == 2 and dat[1] != None:
        txt = re.sub(pat_2 + r"[0-9,]*", pat_2 + dat[1], txt)

# 시간 수정
msg_date_old = '<!--date-->' + r'[0-9]{4,}\-[0-9]{1,2}\-[0-9]{1,2}'
msg_time_old = '<!--time-->' + r'[0-9]{1,2}:[0-9]{1,2}\(KST\)'
txt = re.sub(msg_date_old, msg_date, txt)
txt = re.sub(msg_time_old, msg_time, txt)

# 위키/목록 페이지 수정
page.text = txt
page.save('봇:통계 갱신')