# This is an quote and post library for a specific thread in the WarOnline forum. import requests import re from bs4 import BeautifulSoup import urllib.request as urllib import warnings warnings.filterwarnings("ignore") # Define the login URL and the thread URL login_url = 'https://waronline.org/fora/index.php?login/login' thread_url = 'https://waronline.org/fora/index.php?threads/warbot-playground.17636/' post_url = "https://waronline.org/fora/index.php?threads/warbot-playground.17636/add-reply" # Sending the message (change that!) message = "Test" # Define the login credentials username = 'WarBot' password = 'naP2tion' # Start a session to persist the login cookie across requests session = requests.Session() def compare_pages(url1, url2): #Compares 2 pages and returns True if they are the same return urllib.urlopen(url1).geturl() == urllib.urlopen(url2).geturl() def get_last_page_of_thread(thread_url=thread_url, startingPage=1): #Returns a link to the last page of the thread page = startingPage #Counter lastPage = False while not lastPage: response = requests.get(thread_url + 'page-' + str(page)) if response.status_code == 200: pass # do something (optional) if not compare_pages(thread_url + 'page-' + str(page), thread_url + 'page-' + str(page + 1)): page += 1 else: lastPage = True else: lastPage = True return (thread_url + 'page-' + str(page)) def login(username=username, password=password, thread_url=thread_url): # Log-In to the forum and redirect to thread # Retrieve the login page HTML to get the CSRF token login_page_response = session.get(login_url) soup = BeautifulSoup(login_page_response.text, 'html.parser') csrf_token = soup.find('input', {'name': '_xfToken'})['value'] # Login to the website login_data = { 'login': username, 'password': password, 'remember': '1', '_xfRedirect': thread_url, '_xfToken': csrf_token } response = session.post(login_url, data=login_data) # Check if the login was successful if 'Invalid login' in response.text: print('Login failed!') exit() def post(message=message, thread_url=thread_url, post_url=post_url, quoted_by="",quote_text="",quote_source=""): #Post a message to the forum (with or without the quote #quote_source is in format 'post-3920992' quote_source = quote_source.split('-')[-1] # Take the numbers only if quoted_by: message = f'[QUOTE="{quoted_by}, post: {quote_source}"]{quote_text}[/QUOTE]{message}' # optionally add @{quoted_by} to indent the quoter # Retrieve the thread page HTML response = session.get(thread_url) # Parse the HTML with BeautifulSoup soup = BeautifulSoup(response.text, 'html.parser') # Extract the _xfToken value from the hidden form field xf_token = soup.find('input', {'name': '_xfToken'}).get('value') # Construct the message data for the POST request message_data = { '_xfToken': xf_token, 'message': message, 'attachment_hash': '', 'last_date': '', '_xfRequestUri': post_url, '_xfWithData': '1', '_xfResponseType': 'json' } response = session.post(post_url, data=message_data) # Check if the post was successful if not response.ok: print('Post failed!') exit() print('Post submitted successfully.') def readQuote(thread_url=thread_url, username=username): # Retrieve the content of the specific thread response = session.get(thread_url) html_content = response.content # Initial values for messangerName and the message ID messengerName = "" messageID = "" # Parse the HTML content using BeautifulSoup soup = BeautifulSoup(html_content, 'html.parser') # Find all the quotes in the thread quotes = soup.find_all('div', {'class': 'bbWrapper'}) messageData = soup.find_all('div', {'class': 'message-userContent'}) # Check each quote if it contains your name and keep track of the latest one latest_quote = None for quote in quotes: if username in quote.text: latest_quote = quote if latest_quote: for data in messageData: if latest_quote.text in data.text: # Patterns to search in the last quote. namePattern = re.compile('data-lb-caption-desc="(.*?) ·') messageIDPattern = re.compile('data-lb-id="(.*?)"') # Get the messager username matchName = namePattern.search(str(data)) if matchName: messengerName = matchName.group(1) # Get the message ID matchID = messageIDPattern.search(str(data)) if matchID: messageID = matchID.group(1) reply = latest_quote.text.split("Click to expand...")[-1].replace('\n', ' ').strip() return {'reply':reply,'messengerName':messengerName,'messageID':messageID} if __name__ == '__main__': login(username=username, password=password, thread_url=thread_url) #post(message=message, thread_url=thread_url, post_url=post_url,quoted_by='Василий Пупкин',quote_text='Testing the XenForo response mechanism') quote = readQuote(thread_url=get_last_page_of_thread(thread_url,1), username=username) messangerQuote = readQuote(thread_url=get_last_page_of_thread(thread_url,1),username=quote['messengerName']) print(quote) print(messangerQuote) # The task is to fine all the unanswered quotes