Wiki - KEONHACAI COPA

Thành viên:AlphamaBot/Code đa chức năng (pywikibot)

Đây là phiên bản mới nhất của AlphamaBot chạy dựa theo mã nguồn Pywikibot và ngôn ngữ lập trình Python.

Lưu ý, bạn phải tự chịu trách nhiệm về con bot của mình khi thực thi bằng đoạn mã. Tôi chỉ đảm bảo đoạn mã sẽ có ít lỗi nhất có thể.

HƯỚNG DẪN SỬ DỤNG
  • Lưu đoạn mã sau vào 1 tập tin, ví dụ run_bot.py (hoặc bất cứ tên gì), sau đó cùng cú pháp python run_bot.py (hoặc tên file bạn chọn) để chạy trong cmd (command line).
  • Đối với khi chạy hàm menu() trên console thì sử dụng cú pháp
    • đa chức năng xử lý trang: run_bot.py -f multi
    • chức năng chào mừng: run_bot.py -f welcome
    • chạy tất cả: run_bot.py -f all
  • Nếu không sử dụng thì có thể che dòng code này bằng dấu # và sử dụng hàm tùy biến độc lập. Khi đó không cần truyền tham số như khi sử dụng hàm menu(). Việc này giúp lập trình viên flexible với lựa chọn của mình.
TÍNH NĂNG TƯƠNG LAI
  • Thêm thể loại từ en
  • Tự xếp thể loại (BERT)
  • Tự wiki hóa
  • Phân loại văn bản (BERT)
import sys, getopt
import pywikibot

from pywikibot.pagegenerators import * # pagegenerators: tìm kiếm danh sách trang
from pywikibot.config import * # config: cấu hình bot (user, password,...)
#from pywikibot.login import *

import re # gói regex dành cho các biểu thức chính quy
import time


# -- helpers -------------------------------------------------- #
# ------------------------------------------------------------- #

def replace_all(text, dict):
    """
        thay thế toàn bộ văn bản theo từ điển
            text: văn bản gốc - string
            dict: từ điển - object
            return: văn bản đã được thay thế - string
    """

    for i, j in dict.iteritems():
        text = text.replace(i, j)
    return text

def strip_all(text, list):
    """
        tỉa văn bản đầu cuối theo danh sách
            text: văn bản gốc - string
            list: danh sách cần tỉa - list
            return: văn bản đã được thay thế - string
    """

    loop = 0
    while True:
        loop += 1
        if (loop > 50): break

        for i in list:
            text = text.strip(i)

        count = 0
        for i in list:
            if (len(text) >= len(i)):
                if (i in text[0:len(i) + 1] or i in text[-len(i):]):
                    count = count + 1
                    break
        if (count == 0): break
      
    return text


def hide_by_string1(text, start, end):
    """
        ẩn văn bản theo cặp thẻ chỉ định
            text: văn bản gốc - string
            start: chuỗi bắt đầu - string
            end: chuỗi kết thúc - string
            return: trả về văn bản đã được thay đổi - string
    """

    hide_text = ''
    flag = False

    for i, c in enumerate(text):
        try:
            if (text[i] == start):
                hide_text += start
                flag = True
        except: pass

        try:
            if (text[i] == end):
                flag = False
        except: pass

        if (flag == True): hide_text += '#'
        else: hide_text += c

    return hide_text
              

def hide_by_string2(text, start1, start2, end1, end2):

    """
        ẩn văn bản theo cặp thẻ chỉ định
            text: văn bản gốc - string
            start1, start2: chuỗi bắt đầu - string
            end1, end2: chuỗi kết thúc - string
            return: trả về văn bản đã được thay đổi - string
    """

    hide_text = ''
    flag = False
     
    for i, c in enumerate(text):
        try:
            if (text[i] == start1 and text[i+1] == start2):
                hide_text += start1 + start2
                flag = True
        except: pass

        try: 
            if (text[i] == end1 and text[i+1] == end2):
                flag = False
        except: pass

        if (flag == True): hide_text += '#'
        else: hide_text += c

    return hide_text
              

def hide_code(text):

    hide_text = hide_by_string2(text, '{', '{', '}', '}') # hide templates
    hide_text = hide_by_string1(hide_text, '<', '>') # hide code chunks

    # split text + remove special characters
    chunks = [strip_all(t, ['\n', '<', '>', '{{', '}}', '*']).strip() for t in hide_text.split('#') if strip_all(t, ['\n', '<', '>', '{{', '}}', '*']).strip() != '']

    # remove some prefixes
    prefixes = ['Tập tin:', 'File:', 'Thể loại:', 'Category:']
    chunks = [c for c in chunks if len([p for p in prefixes if p in c]) == 0]
    chunks = [c for c in chunks if len(c.split()) > 10] # not use too short chunks
     
    #print('text_chunk: ', chunks)
    return chunks

# --- wiki ---------------------------------------------------- #
# ------------------------------------------------------------- #

def check_redirect(text):
    """
        kiểm tra redirect trong nội dung văn bản (thường có cú pháp #redirect hoặc #đổi)
        bot không chạy ở các trang redirect
            text: văn bản - string
            return: boolean
    """

    texts = text.split('\n')
    if (len(texts) < 1): return False

    check1 = re.search(r'#\s*[Đđ][ổỔ][iI]\s*', texts[0])
    check2 = re.search(r'#\s*[Rr][Ee][Dd][Ii][Rr][Ee][Cc][Tt][Ss]\s*', texts[0])

    if check1: return True
    if check2: return True

    return False
    
def punctuation_fixes(title, text, summary):
    """
        ***HÀM ĐANG BỊ LỖI
        sửa khoảng trắng dư trước dấu câu
            title: tên trang - string
            text: nội dung trang - string
            summary: nội dung tóm tắt - string
            return: trả về các biến trên
    """

    new_text = text
    chunks = hide_code(text)
    new_chunks = []

    for chunk in chunks:
        errors = re.findall(r'\w{1}\s{1,2}[.,;:)]\s{1,2}\w{1}', chunk)
        for e in errors:
            temp_e = ''
            flag = False
            for c in ' '.join(e.split()):
                if (c in ['.',',',';',':',')']): flag = True
                if (flag == True): temp_e += c
                if (flag == False and c != ' '): temp_e += c

            new_chunks.append(chunk.replace(e, temp_e))

    for c, n in zip(chunks, new_chunks): new_text = new_text.replace(c, n)
    if (new_text != text): summary += '[sửa dấu câu]'

    return title, new_text, summary
    
def page_handling(page):

    title = str(page._link)
    title = title.strip('[[').strip(']]')
    summary = ''

    # hàm sửa lỗi chung, thay thế 1 số cụm từ
    if (check_redirect(page.text) == True): return title, page.text, summary
    
    title, new_text, summary = general_fixes(title, page.text, summary)
    #title, new_text, summary = punctuation_fixes(title, new_text, summary)

    return title, new_text, summary
    

def general_fixes(title, text, summary):
    """
        sửa lỗi chung
            title: tên trang - string
            text: nội dung - string
            summary: tóm tắt nội dung sửa đổi - string
            return: trả về các biến trên
    """

    new_text = text
    
    # chú thích
    new_text = re.sub(r'\{\{[Cc]ite\s*book', '{{chú thích sách', new_text)
    new_text = re.sub(r'\{\{[Cc]ite\s*web', '{{chú thích web', new_text)
    new_text = re.sub(r'\{\{[Cc]ite\s*news', '{{chú thích báo', new_text)
    new_text = re.sub(r'\{\{[Cc]ite\s*web', '{{chú thích web', new_text)
    new_text = re.sub(r'\{\{[Cc]ite\s*journal', '{{chú thích tạp chí', new_text)
    new_text = re.sub(r'\{\{[Cc]ite\s*iucn', '{{chú thích IUCN', new_text)
    new_text = re.sub(r'\{\{[Cc]ite\s*doi', '{{chú thích DOI', new_text)
    new_text = re.sub(r'\{\{[Cc]ite tweet', '{{chú thích tweet', new_text)

    # tham khảo
    new_text = re.sub(r'\{\{[Rr]eflist', '{{tham khảo', new_text)
    new_text = re.sub(r'\{\{\s*[Tt]ham(\s*\_*)[Kk]hảo\s*', '{{tham khảo', new_text)
    new_text = re.sub(r'\<[Rr]eferences\s*\/\>', '{{tham khảo}}', new_text)

    # thể loại
    new_text = re.sub(r'\[\[\s*[Cc]ategory\s*:', '[[Thể loại:', new_text)
    new_text = re.sub(r'\[\[\s*[Tt]hể(\s*\_*)loại\s*:', '[[Thể loại:', new_text)

    new_text = re.sub(r'\[\[\s*[Tt]hể\s*loại\s*:\s*[Cc]ategory\s*:', '[[Thể loại:', new_text)
    new_text = re.sub(r'\[\[\s*[Tt]hể\s*loại\s*:\s*[Tt]hể\s*loại\s*:', '[[Thể loại:', new_text)

    # tập tin    
    new_text = re.sub(r'\[\[[Ff]ile\s*:', '[[Tập tin:', new_text)
    new_text = re.sub(r'\[\[[Ii]mage\s*:', '[[Hình:', new_text)

    # bản mẫu
    new_text = re.sub(r'\{\{[Tt]axobox', '{{Bảng phân loại', new_text)
    new_text = re.sub(r'\{\{[Cc]ommonscat-inline', '{{Thể loại Commons nội dòng', new_text)
    new_text = re.sub(r'\{\{[Cc]ommons category-inline', '{{Thể loại Commons nội dòng', new_text)
    new_text = re.sub(r'\{\{[Ww]ikispecies-inline', '{{Wikispecies nội dòng', new_text)
    new_text = re.sub(r'\{\{[Cc]ommons category', '{{Thể loại Commons', new_text)
    new_text = re.sub(r'\{\{[Cc]ommons\s*cat', '{{Thể loại Commons', new_text)

    # đề mục
    new_text = re.sub(r'==\s*References\s*==', '== Tham khảo ==', new_text)
    new_text = re.sub(r'==\s*External\s*links\s*==', '== Liên kết ngoài ==', new_text)
    new_text = re.sub(r'==\s*[Ll]iên\s*[Kk]ết\s*[Bb]ên\s*[Nn]goài\s*==', '== Liên kết ngoài ==', new_text)
    new_text = re.sub(r'==\s*[Ss]ee\s*[Aa]lso\s*==', '== Xem thêm ==', new_text)
    new_text = re.sub(r'==\s*[Nn]otes\s*==', '== Ghi chú ==', new_text)

    if (new_text != text): summary += '[sửa đổi chung]'

    return title, new_text, summary


def check_status(site, bot_name):
    """
        kiểm tra trạng thái bot là tắt hay mở
            site: biến đối tượng trang - object
            bot_name: tên bot - string
            return: boolean
    """

    # Kiểm tra trạng thái bot ở không gian [[Thành viên:Tên bot/Status]]
    # Xem ví dụ cách lưu ở [[Thành viên:AlphamaBot/Status]]

    page_name = 'Thành viên:' + bot_name + '/Status'
    page = pywikibot.Page(site, page_name)

    texts = page.text.split('\n')

    try:
        pair = [p.strip() for p in texts[1].split('=')]
        if (pair[0] == 'active' and pair[1] == '1'):
            return True
    except: pass

    return False


def welcome(site, welcome_template, total = 50):
    """
        chào mừng thành viên
            site: đối tượng dự án - object (site = pywikibot.Site('vi', 'wikipedia'))
            total: số lượng thành viên mới - int
            return: chào mừng thành viên có trên 1 sửa đổi     
    """

    # lấy danh sách nhật trình các tài khoản đã đăng ký mới
    log_newusers = site.logevents('newusers', total = total)

    # dựa theo nhật trình lấy danh sách tên thành viên mới
    users = (pywikibot.User(site, u.user()) for u in log_newusers)

    # kiểm tra bản mẫu có hợp lệ
    templates = ['{{thế:hoan nghênh2}}', '{{thế:hoan nghênh3}}', '{{thế:hoan nghênh4}}', '{{thế:hoan nghênh5}}',
                             '{{thế:hoan nghênh6}}', '{{thế:hoan nghênh7}}', '{{thế:hoan nghênh8}}',
                             '{{thế:hoan nghênh12}}', '{{thế:hoan nghênh của Băng Tỏa}}',
                             '{{thế:chào mừng thành viên mới}}']
    
    welcome_template = welcome_template.lower()
    if (welcome_template not in templates):
        print('Bản mẫu chào mừng không hợp lệ! Kiểm tra danh sách: ', templates)
        return

    # bắt đầu duyệt danh sách thành viên mới
    for u in users:
        try:
            # lấy tên thành viên
            username = str(u._link)
            username = username.strip('[[').strip(']]')
            username = username.replace('Thành viên:', '')
     
            # kiểm tra hợp lệ
            if u.isBlocked():  continue # không chào mừng nếu thành viên bị cấm
            if 'bot' in u.groups() or 'bot' in username.lower(): continue  # không chào mừng nếu thành viên là bot
            if u.editCount() < 1: continue # không chào mừng nếu thành viên không có sửa đổi nào

            # không chào mừng nếu thành viên có tên vi phạm,...
              
            print('Đang chào mừng thành viên: ', username)
            user_talk = 'Thảo luận Thành viên:' + username
            page = pywikibot.Page(site, user_talk)

            # xử lý trang
            if (len(page.text) == 0):
                page.text += welcome_template + '\n~~~~'
                page.save(summary = '[[:mw:Manual:Pywikibot/vi|Pywikibot]]: Chào mừng thành viên mới (bản mẫu ' + welcome_template + ').')
                print('--- Đã thêm bản mẫu.')
            else: print('--- Trang thảo luận đã tồn tại.')
        except:
            print('--- Tên thành viên chứa ký tự nằm ngoài BMP.')
            pass
            
        print('....................................')
            

def multifunction(site):
    """
        hàm đa năng
            site: đối tượng dự án (object)
    """
    
    # các hàm tạo danh sách
    # total: tổng số trang cần tìm
    # namespaces: không gian tên
    # pages = site.search('toán học', total=50, namespaces=[0]) # tìm trang theo cụm từ
    # pages = site.search('insource: 'toán học'', total=50, namespaces=[0]) # tìm trang bằng mã wiki
    # pages = RecentChangesPageGenerator(site, total = 50, namespaces=[0]) # tìm trang thay đổi gần đây
    # pages = RandomPageGenerator(site, total = 50, namespaces=[0]) # lỗi thời
    # pages = NewpagesPageGenerator(site, total=1000, namespaces=[0]) # tìm danh sách các trang gần đây ở không gian Chính (bài viết)

    #pages = site.randompages(total=500, namespaces=[0], redirects=True) # lấy danh sách bài ngẫu nhiên

    pages = NewpagesPageGenerator(site, total=1000, namespaces=[0])
    
    step = 5
    count = 1

    for p in pages:
        count += 1

        try:
            print('....................................')

            # mỗi 5 trang thì mới kiểm tra trạng thái bot tắt hay mở
            if (count%step == 0):
                if (check_status(site, bot_name) == False):
                    print('Bot không được kích hoạt! Xem ở [[' + bot_status_page + ']].')
                    break
                    
                start = time.time()
                temp_title = str(p._link)
                temp_title = temp_title.strip('[[').strip(']]')
                print('Đang xử lý trang: ', temp_title)
                    
                page = pywikibot.Page(site, temp_title)

                # xử lý trang
                title, new_text, summary = page_handling(page)
    
                if (new_text !=  page.text):
                    page.text = new_text
                    end = time.time()

                    time_label = str(end - start)[0:6] + 's'
                    page.save(summary = '[[:mw:Manual:Pywikibot/vi|Pywikibot]] + [[Thành viên:AlphamaBot/Code đa chức năng (pywikibot)|AlphamaModule]]: ' + summary + ', ' + time_label) # lưu trang
                                                              
                    print('--- Đã lưu!')
                else:
                    print('--- Không có gì thay đổi!')
                    
        except Exception as e:
            print('Lỗi: ', e, p)

        


def menu(argv, site):
    """
        lấy tham số truyền theo dòng lệnh
            argv: đối số - object
            site: dự án - object
    """

    try:
        opts, args = getopt.getopt(argv, "h:f:")
    except getopt.GetoptError:
        print('run_bot.py -f <welcome|multi|all>')
        sys.exit(2)

    for opt, arg in opts:
        if opt == '-h':
            print('run_bot.py -f <welcome|multi|all>')
            sys.exit()
        elif(opt in ('-f')):
            if (arg == 'multi'):
                multifunction(site)
            elif (arg == 'welcome'):
                welcome(site, '{{thế:hoan nghênh12}}', total = 500)
            elif (arg == 'all'):
                multifunction(site)
                welcome(site, '{{thế:hoan nghênh12}}', total = 500)
            else:
                print('run_bot.py -f <welcome|multi|all>')

#.......................................................................................
if __name__ == '__main__':


    site = pywikibot.Site('vi', 'wikipedia') # khai báo ngôn ngữ + dự án

    # ghi đè tham số trong config.py
    bot_name = 'AlphamaBot'
    usernames['wikipedia']['vi'] = bot_name # tên bot
    console_encoding = 'utf-8'
    use_api_login = True 

    put_throttle = 0 # bỏ thời gian chờ giữa các action
    maxthrottle = 0 # bỏ thời gian chờ tối đa giữa các action
    noisysleep = 30

    # Tạo thao tác lưu ảo để đăng nhập và kiểm tra chức năng bot
    bot_status_page = 'Thành viên:' + bot_name + '/Status'
    page = pywikibot.Page(site, bot_status_page)
    page.save('')

    if (check_status(site, bot_name) == False):
        print('Bot không được kích hoạt! Xem ở [[' + bot_status_page + ']].')
        sys.exit() # hàm thoát trong main


    # sử dụng menu console
    menu(sys.argv[1:], site)

    # hàm chào mừng
    #welcome(site, '{{thế:hoan nghênh12}}', total = 500)

    # hàm chào mừng chạy liên tục
    '''i = 0
    while True:
        if (i%5 == 0):
            if (check_status(site, bot_name) == False):
                print('Bot không được kích hoạt! Xem ở [[' + bot_status_page + ']].')
                break
        i = i + 1
        welcome(site, '{{thế:hoan nghênh12}}', total = 500)'''

    # hàm đa năng xử lý trang
    #multifunction(site)

    # hàm đa năng xử lý trang chạy liên tục
    '''i = 0
    while True:
        if (i%5 == 0):
            if (check_status(site, bot_name) == False):
                print('Bot không được kích hoạt! Xem ở [[' + bot_status_page + ']].')
                break
        i = i + 1
        multifunction(site)'''
Wiki - Keonhacai copa chuyên cung cấp kiến thức thể thao, keonhacai tỷ lệ kèo, bóng đá, khoa học, kiến thức hằng ngày được chúng tôi cập nhật mỗi ngày mà bạn có thể tìm kiếm tại đây có nguồn bài viết: https://vi.wikipedia.org/wiki/Th%C3%A0nh_vi%C3%AAn:AlphamaBot/Code_%C4%91a_ch%E1%BB%A9c_n%C4%83ng_(pywikibot)