Приложение Tkinter, использующее селен, не отвечает после нажатия кнопки «Выполнить» - PullRequest
0 голосов
/ 04 октября 2019

Я создал бота для Instagram, который использует селеновый веб-драйвер вместе с интерфейсом tkinter. Однако, когда браузер работает, приложение не отвечает, не позволяя закрыть его на полпути или что-либо еще. Приложение tkinter работает в отдельном классе с реальным кодом

import tkinter as tk
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import time
import threading
import random
import sys
import mysql.connector
from mysql.connector import errorcode
from datetime import datetime
from tkinter import *
from tkinter.ttk import * 
from time import strftime 
from tkinter import messagebox
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException



# THIS VERSION IS V 1.1.0
# THIS UPDATE INCLUDES THE NEW LAYOUT FOR THE GUI USING TTKINTER
# NEW MENUS ARE INCLUDED IN THIS UPDATE
# ADDED NUMBER OF PICTURES TO LIKE OPTION
# NEW FORMAT 
# FIXED BUGS EXCLUDING RANDOM REDIRECTION ISSUE 
# Note: This works with Chromedriver V77 and Chrome V77

class StartPage(tk.Tk):

    # Load application
    def __init__(self, root):
        root.title("Instagram Bot - Created By HudZah")

        # Creating menubar
        menubar = Menu(root)

        print("Application loading, please wait")
        print("When you install this application, you agree to the abide by the Terms And Conditions stated in the installtion folder. This software is not intended to be used for the exploitation of Instagram, rather as a means of promoting your product. Any detention or suspension that is resulted due to excessive use of this Bot is in no means the fault of the publisher, but the consequences faced by the user. It should be clear that this Bot should not be misused or overused, this might result in unknown penalties to be faced by the user." + "\n Created by HudZah") 

        Border = 3

        canvas = tk.Canvas(root, height=600, width=700)
        canvas.pack()

        MainFrame = tk.Frame(root, bg="white")
        MainFrame.place(relwidth=1, relheight=1)

        # Adding file menu and commands
        file = Menu(menubar, tearoff = 0)
        menubar.add_cascade(label = "File", menu = file)
        file.add_command(label ='New File', command = None) 
        file.add_command(label ='Run', command = lambda:GetUserInfo(Username.get(), Password.get(), List.get())) 
        file.add_command(label ='Save', command = None) 
        file.add_separator() 
        file.add_command(label ='Exit', command = root.destroy) 

        # Adding Edit Menu and commands 
        edit = Menu(menubar, tearoff = 0) 
        menubar.add_cascade(label ='Edit', menu = edit) 
        edit.add_command(label ='Cut', command = None) 
        edit.add_command(label ='Copy', command = None) 
        edit.add_command(label ='Paste', command = None) 
        edit.add_command(label ='Select All', command = None) 
        edit.add_separator() 
        edit.add_command(label ='Find...', command = None) 
        edit.add_command(label ='Find again', command = None) 

        # Adding Help Menu 
        help_ = Menu(menubar, tearoff = 0) 
        menubar.add_cascade(label ='Help', menu = help_) 
        help_.add_command(label ='Help', command = None) 
        help_.add_command(label ='Tutorials', command = None) 
        help_.add_separator() 
        help_.add_command(label ='About BOTIG', command = None) 
        UsernameFrame = tk.Frame(root, bg="lightgrey", bd=Border)
        help_.add_command(label ='Information', command = None) 


        # Relative width to the canvas
        UsernameFrame.place(relx=0.5, rely=0.135, relwidth=0.60,
                            relheight=0.1, anchor="n")

        Username = tk.Entry(UsernameFrame, font=40)
        Username.insert(0, "Username")
        Username.place(relwidth=1, relheight=1)
        Username.focus()
        PasswordFrame = tk.Frame(root, bg="lightgrey", bd=Border)
        PasswordFrame.place(relx=0.5, rely=0.26, relwidth=0.60,
                            relheight=0.1, anchor="n")

        Password = tk.Entry(PasswordFrame, show="*",  font=40)
        Password.insert(0, "Password")
        Password.place(relwidth=1, relheight=1)

        ListFrame = tk.Frame(root, bg="lightgrey", bd=Border)

        ListFrame.place(relx=0.5, rely=0.385, relwidth=0.60,
                        relheight=0.1, anchor="n")
        List = tk.Entry(ListFrame, font=40)
        List.insert(0, "Explore Hashtags, eg: food, nyc")
        List.place(relwidth=1, relheight=1)

        # Minutes
        PicsInput = Spinbox(root, from_= 1, to = 2000, font = 13)
        PicsInput.place(relx=0.5, rely=0.61, relwidth=0.14,
                     relheight=0.055, anchor = "n")

        button = tk.Button(MainFrame, text="Run",
                           command=lambda:GetUserInfo(Username.get(), Password.get(), List.get(), PicsInput.get()))

        button.place(relx=0.5, rely=0.71, relwidth=0.25,
                     relheight=0.085, anchor="n")

        button = tk.Button(MainFrame, text="Quit",
                           command= root.destroy)

        button.place(relx=0.5, rely=0.81, relwidth=0.25,
                     relheight=0.085, anchor="n")

        label = tk.Label(root, text = "Created by HudZah © 2019", font = 13, bg = "white", fg = "black")
        label.place(relx = 0.5, rely = 0.93, anchor = "n")

        PicsInputLabel = tk.Label(root, text = "Pictures Per Hashtag", font = 7, bg = "white", fg = "black")
        PicsInputLabel.place(relx = 0.5, rely = 0.55, relwidth = 0.3, anchor = "n")

        # Create label to show errors to users and Info of bot when closed
        root.config(menu = menubar) 

    #pyinstaller --add-binary="Documents/chromedriver.exe;." InstagramBotV1.1.0.py
class InstagramBot(tk.Tk):
    # Run page
    def __init__(self, username, password):
        self.username = username
        self.password = password
        self.driver = webdriver.Chrome()

    def login(self):
        driver = self.driver
        driver.get("https://www.instagram.com/")
        time.sleep(2)
        LoginButton = driver.find_element_by_xpath(
            "//a[@href='/accounts/login/?source=auth_switcher']")
        LoginButton.click()
        time.sleep(5)
        UsernameElem = driver.find_element_by_xpath(
            "//input[@name='username']")
        UsernameElem.clear()
        UsernameElem.send_keys(self.username)
        PasswordElem = driver.find_element_by_xpath(
            "//input[@name='password']")
        PasswordElem.clear()
        PasswordElem.send_keys(self.password)
        PasswordElem.send_keys(Keys.RETURN)
        time.sleep(6)

    def LikePhoto(self, hashtag, NumOfPics, pages):

        driver = self.driver 
        driver.get("https://www.instagram.com/explore/tags/" + hashtag + "/")
        time.sleep(3)
        # gathering photos
        PicLinks = []

        print("Check : Number of pages are", pages)
        for i in range(0,pages):
            try:
                driver.execute_script(
                    "window.scrollTo(0, document.body.scrollHeight);")
                time.sleep(2)
                # get tags
                Links = driver.find_elements_by_tag_name('a')
                # finding relevant hrefs

                Links = [elem.get_attribute('href') for elem in Links
                        if ".com/p/" in elem.get_attribute("href")]
                for i in range (0,len(Links)):
                    if Links[i] not in PicLinks:
                        PicLinks.append(Links[i])

                print(
                    "Check: Total N.of pic hrefs stored after array : " + str(len(PicLinks)) + " , in " + hashtag)
                # print(Links)
            except Exception:
                continue

        LikedPhotos = 0
        for i in range(0, len(PicLinks)):
            print("Num" , i , " : " ,  PicLinks[i])
        # Liking photos
        UniquePhotos = int(NumOfPics)
        #for PicLinks in Links:
        for i in range(0,int(NumOfPics)):
            driver.get(PicLinks[i])
            time.sleep(4)
            driver.execute_script(
                "window.scrollTo(0, document.body.scrollHeight);")
            try:
                time.sleep(random.randint(5, 9))

                #driver.find_element_by_xpath("//class[@glyphsSpriteHeart__outline__24__grey_9 u-__7]").click()
                driver.find_element_by_xpath('//span[@aria-label="Like"]').click()  # Anonymous function

                time.sleep(1)
                UniquePhotos = UniquePhotos - 1
                LikedPhotos = LikedPhotos + 1
                print("Picture liked : ",LikedPhotos , " Pictures left : ", UniquePhotos)

            except Exception:
                time.sleep(2)

    def closeBrowser(self):
        self.driver.close()
        print("Browser quit")
# Pass info to main class


def GetUserInfo(username, password, hashtagReceived, nOfPics):
    if password and username and hashtagReceived:
        if username != "Username" and password != "Password" and hashtagReceived != "Explore Hashtags, eg: food, nyc":
            try:
                if int(nOfPics) != 0:
                    if messagebox.askokcancel('Application','Application is running, press OK to continue') == True:
                        hashtags = []
                        username = username
                        password = password
                        pages = int(nOfPics)/10
                        pages = int(pages)
                        if pages < 1:
                            pages = 1
                        else:
                            pages = pages
                        #print("username is ", username, "ands password is", password)
                        # Split hashtags into an array
                        hashtags = hashtagReceived.split(",")
                        try:
                            print(hashtags)
                            IG = InstagramBot(username, password)
                            IG.login()
                            i = 0

                        except:
                            messagebox.showerror("Could not execute task. Please try again.")

                        try:
                            while i <= len(hashtags):
                            # Choose a random tag from the list of tags
                                tag = hashtags[i]
                                tag = tag.replace(" ", "")
                                IG.LikePhoto(tag, nOfPics, pages)
                                i = i + 1
                        except ValueError:
                            print("Value could not be converted to an integer.")

                        except Exception:
                            if i != len(hashtags):
                                IG.closeBrowser()
                                print("Browser crashed")
                                time.sleep(3)
                                IG = InstagramBot(username, password)
                                IG.login()
                                i = 0
                            elif i == len(hashtags):
                                print("Hashtags are out")

                        finally:
                            print("Program finished")
                            IG.closeBrowser()




                    else:
                        SystemExit()
                else:
                    messagebox.showwarning("Error", "Please enter a valid number of posts to like")
                    print("Please enter a valid number of posts to like")
            except Exception:
                messagebox.showwarning("Error", "Please enter a valid number of posts to like")
                print("Please enter a valid number of posts to like")                

        else:
            messagebox.showwarning("Error", "Please enter suitable data")
            print("Please enter suitable data")
    else:
        messagebox.showwarning('Error', 'Please enter a username or password')  #shows warning message
        print("Please enter a username and password")


if __name__ == "__main__":
    print("Run from main")
    root = tk.Tk()
    Start = StartPage(root)
    root.mainloop()
else:
    print("Run from import")

Браузер работает отлично и код работает. Однако, если вы попытаетесь нажать на любую кнопку в приложении, оно не ответит. Предполагается запустить браузер и одновременно запустить приложение

1 Ответ

1 голос
/ 04 октября 2019

Проблема, с которой вы сталкиваетесь, заключается в том, что селен и tkinter работают в одном потоке / процессе, вам нужно либо использовать модуль потоков, либо модуль подпроцесса, чтобы выполнить это, ваше приложение tkinter больше не будет зависать.

Документацию по потокам можно найти здесь

Документация по подпроцессам здесь

Вы можете найти некоторые реализации потоков по этой ссылке

...