Просмотр исходного кода

CoTan自动化网页基本完成,待封装

Huan 5 лет назад
Родитель
Сommit
19c853acc3
3 измененных файлов с 405 добавлено и 47 удалено
  1. 190 14
      Crawler_controller.py
  2. 14 1
      Information_storage.py
  3. 201 32
      Web_Crawler.py

+ 190 - 14
Crawler_controller.py

@@ -9,17 +9,27 @@ import bs4
 import re as regular
 import Information_storage
 import requests
+from selenium.webdriver.common.action_chains import ActionChains
+from selenium.webdriver.common.keys import Keys
+keys_name_dict = {'ctrl':Keys.CONTROL,'shift':Keys.SHIFT,'tab':Keys.TAB,'left_ctrl':Keys.LEFT_CONTROL,'left_shift':Keys.LEFT_SHIFT,
+                      'left_alt':Keys.LEFT_ALT,'ALT':Keys.ALT,'enter':Keys.ENTER,'return':Keys.RETURN,'backspace':Keys.BACKSPACE,
+                      'del':Keys.DELETE,'pgup':Keys.PAGE_UP,'pgdn':Keys.PAGE_DOWN,'home':Keys.HOME,'end':Keys.END,'esc':Keys.CANCEL,
+                      'insert':Keys.INSERT,'meta':Keys.META,'up':Keys.UP,'down':Keys.DOWN,'right':Keys.RIGHT,'left':Keys.LEFT
+                     }#键-值映射
+for i in range(1,13):#F1 - F12按键
+    keys_name_dict[f'f{i}'] = eval(f'Keys.F{i}')
 
 data_base = Information_storage.DataBase_Home()
 
 class PAGE:
-    def __init__(self):
+    def __init__(self,time_out):
         self.url=''
         self.UA=''
         self.func = 'PAGE'
+        self.time_out = time_out
 
     def __str__(self):
-        return f'{self.func}-{self.url}:UA>{self.UA}'
+        return f'[{self.time_out}s]{self.func}-{self.url}:UA>{self.UA}'
 
 class REQUESTS_Base(PAGE):
     def init(self,UA,url,cookies):
@@ -32,14 +42,13 @@ class REQUESTS_Base(PAGE):
                    'Accept-Language': 'zh-Hans-CN, zh-Hans; q=0.5',
                    'Connection': 'Keep-Alive',
                    'User-Agent': UA}
-        self.requests = lambda *args:None
         self.url = url
         self.cookies = cookies
         self.new = True
 
 class URL_POST(REQUESTS_Base):#通过requests的post请求
-    def __init__(self, url, data,UA='',cookies=None, **kwargs):
-        super(URL_POST, self).__init__()
+    def __init__(self, url, data, time_out,UA='',cookies=None, **kwargs):
+        super(URL_POST, self).__init__(time_out)
         self.func = 'post'
         self.data = data
         self.requests = requests.post
@@ -49,16 +58,16 @@ class URL_POST(REQUESTS_Base):#通过requests的post请求
         return super(URL_POST, self).__str__() + f';data>{self.data}'
 
 class URL_GET(REQUESTS_Base):#通过requests的post请求
-    def __init__(self, url,UA='',cookies=None, **kwargs):
-        super(URL_GET, self).__init__()
+    def __init__(self, url, time_out,UA='',cookies=None, **kwargs):
+        super(URL_GET, self).__init__(time_out)
         self.func = 'simplify_get'
         self.requests = requests.get
         self.init(UA,url,cookies)
 
 class URL_PAGE(PAGE):
-    def __init__(self,url,first_run=False,head=False,no_plugins=True,no_js=False,no_java=False,
+    def __init__(self,url, time_out,first_run=False,head=False,no_plugins=True,no_js=False,no_java=False,
                  no_img=False,UA='',cookies=None,new=False,down_load_dir='',**kwargs):
-        super(URL_PAGE, self).__init__()
+        super(URL_PAGE, self).__init__(time_out)
         self.url = url
         self.func = 'get'
         self.options = webdriver.ChromeOptions()
@@ -109,6 +118,10 @@ class url:#url管理器
         self.url_history = []#url历史
         self.filter = {}#过滤函数
 
+    def close(self):
+        self.file.close()
+        self.file_run.close()
+
     def filter_func(self,url,**kwargs):#url过滤系统
         for i in self.filter:
             if not self.filter[i](url): return False
@@ -124,7 +137,7 @@ class url:#url管理器
         return list(self.filter.keys())
 
     def add_url(self,url,func,data=None,**kwargs):#添加url
-        if func == '':func = 'simplify_get'
+        if func == '':func = 'get'
         if func == 'get':url_ = url
         else:
             url_ = url + str(data)
@@ -159,6 +172,9 @@ class url:#url管理器
         self.file_run.write(f'{url}\n')
         self.file_run.flush()
 
+    def finish(self):
+        return len(self.url_list) == 0
+
     def return_url(self):
         return self.url_list.copy()
 
@@ -170,6 +186,7 @@ class Page_Downloader:
     def __init__(self,url:url,dic=''):
         self.url = url
         self.dir = dic
+        self.log = Information_storage.log(dic)
         Page_Downloader.num += 1
         self.page_source_dict = {}#页面保存信息
         self.cookie_Thread = None#子进程
@@ -178,6 +195,17 @@ class Page_Downloader:
         self.cookie_dict_list = {}#sele的cookies
         self.lase_func = ''
 
+    def close(self):
+        self.log.close()
+
+    def stop(self):
+        try:
+            self.break_ = False
+            self.browser.quit()
+            self.lase_func = ''
+        except:
+            pass
+
     def strat_urlGet(self,*args,func_cookie):#用get请求url ->得到一个页面信息
         self.break_ = False
         self.page_source_dict = {}
@@ -188,9 +216,13 @@ class Page_Downloader:
                 self.browser.quit()
                 self.browser = webdriver.Chrome(chrome_options=self.nowurl.options)
             try:
+                self.browser.set_page_load_timeout(self.nowurl.time_out)  # 设置页面加载超时
+                self.browser.set_script_timeout(self.nowurl.time_out)  # 设置页面异步js执行超时
                 self.browser.get(url)
             except:
                 self.browser = webdriver.Chrome(chrome_options=self.nowurl.options)
+                self.browser.set_page_load_timeout(self.nowurl.time_out)  # 设置页面加载超时
+                self.browser.set_script_timeout(self.nowurl.time_out)  # 设置页面异步js执行超时
                 self.browser.get(url)
             try:
                 if self.nowurl.new != True:raise Exception
@@ -204,6 +236,9 @@ class Page_Downloader:
                 pass
             self.start_cookies(func_cookie,url)
         else:#requests模式
+            if self.lase_func == 'get':
+                try:self.browser.quit()
+                except:pass
             try:
                 args = {'cookies':self.cookie_dict[self.nowurl.cookies]}
                 func_cookie([args['cookies']])
@@ -211,7 +246,7 @@ class Page_Downloader:
                 args = {}
                 func_cookie([])
             if self.nowurl.func == 'post':args['data'] = self.nowurl.data
-            self.browser = self.nowurl.requests(url,headers=self.nowurl.headers,**args)
+            self.browser = self.nowurl.requests(url,headers=self.nowurl.headers,**args,timeout=self.nowurl.time_out)
             self.cookie_dict[url] = requests.utils.dict_from_cookiejar(self.browser.cookies)#保存cookies
             func_cookie([self.cookie_dict[url]])
         self.lase_func = self.nowurl.func
@@ -263,6 +298,7 @@ class Page_Downloader:
         self.Parser.browser = self.browser
         self.Parser.url = self.url
         self.Parser.dir = self.dir
+        self.Parser.log = self.log
 
 class Page_Parser:
     def __init__(self,Downloader:Page_Downloader):
@@ -270,6 +306,7 @@ class Page_Parser:
         self.Downloader.set_Page_Parser(self)
         self.func_list = []
         self.func_dict = {}
+        self.n = 0
         self.init()
 
     def init(self,url=''):
@@ -286,9 +323,20 @@ class Page_Parser:
         return wrap
 
     def add_func(self,name,func):
-        n = len(self.func_list)
-        self.func_list.append(f'{name}[{n}]')
-        self.func_dict[f'{name}[{n}]'] = func
+        self.func_list.append(f'{name}[{self.n}]')
+        self.func_dict[f'{name}[{self.n}]'] = func
+        self.n += 1
+
+    def tra_func(self):
+        self.func_list = []
+        self.func_dict = {}
+        self.n = 0
+
+    def del_func(self,index,end=False):
+        if end:index = len(self.func_list) - index - 1
+        del self.func_dict[self.func_list[index]]
+        self.func_list[index] = 'Func_have_been_del'
+        self.func_dict['Func_have_been_del'] = lambda *args,**kwargs:None
 
     def return_func(self,only=True):
         if only:
@@ -793,9 +841,136 @@ class Page_Parser:
             self.element_dict[f'{name}[{num}]'] = [self.browser.json()]#request 解析为 json
         self.add_func(f'to_json', action)  # 添加func
 
+    def make_ActionChains(self,**kwargs):#创建动作链
+        @self.add_base
+        def action(num,name,*args, **kwargs):
+            nonlocal self
+            self.element_dict[f'{name}[{num}]'] = [ActionChains(self.browser)]
+        self.add_func(f'make_ActionChains', action)  # 添加func
+
+    def ActionChains_click(self,Chains,element_value,index,**kwargs):#单击左
+        @self.add_base
+        def action(*args, **kwargs):
+            nonlocal self
+            self.element_dict[Chains][0].click(self.element_dict[element_value][index])
+        self.add_func(f'[{Chains}]click>[{element_value}][{index}]', action)  # 添加func
+
+    def ActionChains_double_click(self,Chains,element_value,index,**kwargs):#双击左
+        @self.add_base
+        def action(*args, **kwargs):
+            nonlocal self
+            self.element_dict[Chains][0].double_click(self.element_dict[element_value][index])
+        self.add_func(f'[{Chains}]double_click>[{element_value}][{index}]', action)  # 添加func
+
+    def ActionChains_click_right(self,Chains,element_value,index,**kwargs):#点击右
+        @self.add_base
+        def action(*args, **kwargs):
+            nonlocal self
+            self.element_dict[Chains][0].context_click(self.element_dict[element_value][index])
+        self.add_func(f'[{Chains}]right_click>[{element_value}][{index}]', action)  # 添加func
+
+    def ActionChains_click_and_hold(self,Chains,element_value,index,**kwargs):#按住左
+        @self.add_base
+        def action(*args, **kwargs):
+            nonlocal self
+            self.element_dict[Chains][0].click_and_hold(self.element_dict[element_value][index])
+        self.add_func(f'[{Chains}]click_and_hold>[{element_value}][{index}]', action)  # 添加func
+
+    def ActionChains_release(self,Chains,element_value,index,**kwargs):#松开左键
+        @self.add_base
+        def action(*args, **kwargs):
+            nonlocal self
+            self.element_dict[Chains][0].release(self.element_dict[element_value][index])
+        self.add_func(f'[{Chains}]release>[{element_value}][{index}]', action)  # 添加func
+
+    def ActionChains_drag_and_drop(self,Chains,element_value,index,element_value2,index2,**kwargs):#拽托、松开
+        @self.add_base
+        def action(*args, **kwargs):
+            nonlocal self
+            self.element_dict[Chains][0].drag_and_drop(self.element_dict[element_value][index],
+                                                       self.element_dict[element_value2][index2])
+        self.add_func(f'[{Chains}]drag_and_drop>[{element_value}][{index}]', action)  # 添加func
+
+    def ActionChains_move(self,Chains,element_value,index,**kwargs):#移动鼠标
+        @self.add_base
+        def action(*args, **kwargs):
+            nonlocal self
+            self.element_dict[Chains][0].move_to_element(self.element_dict[element_value][index])
+        self.add_func(f'[{Chains}]drag_and_drop>[{element_value}][{index}]', action)  # 添加func
+
+    def Special_keys(self,key:str,is_special_keys):  # 装饰器
+        if is_special_keys:
+            return keys_name_dict.get(key.lower(), key),f'[{key.upper()}]'
+        else:
+            return key,key
+
+    def ActionChains_key_down(self,Chains,key,element_value,index,is_special_keys,**kwargs):#down
+        new_key,key = self.Special_keys(key,is_special_keys)
+        @self.add_base
+        def action(*args, **kwargs):
+            nonlocal self
+            self.element_dict[Chains][0].key_down(new_key,self.element_dict[element_value][index])
+        self.add_func(f'[{Chains}]key_down>{key}:[{element_value}][{index}]', action)  # 添加func
+
+    def ActionChains_key_up(self,Chains,key,element_value,index,is_special_keys,**kwargs):#down
+        new_key, key = self.Special_keys(key, is_special_keys)
+        @self.add_base
+        def action(*args, **kwargs):
+            nonlocal self
+            self.element_dict[Chains][0].key_up(new_key,self.element_dict[element_value][index])
+        self.add_func(f'[{Chains}]key_up>{key}:[{element_value}][{index}]', action)  # 添加func
+
+    def ActionChains_send_keys_to_element(self,Chains,key,element_value,index,is_special_keys,**kwargs):#发送到指定元素
+        new_key, key = self.Special_keys(key, is_special_keys)
+        @self.add_base
+        def action(*args, **kwargs):
+            nonlocal self
+            self.element_dict[Chains][0].send_keys_to_element(self.element_dict[element_value][index],new_key)
+        self.add_func(f'[{Chains}]sent>{key}:[{element_value}][{index}]', action)  # 添加func
+
+    def ActionChains_send_keys(self,Chains,key,is_special_keys,**kwargs):#发送到焦点元素
+        new_key, key = self.Special_keys(key, is_special_keys)
+        @self.add_base
+        def action(*args, **kwargs):
+            nonlocal self
+            self.element_dict[Chains][0].send_keys(new_key)
+        self.add_func(f'[{Chains}].sent>{key}', action)  # 添加func
+
+    def ActionChains_run(self,Chains,run_time=1,**kwargs):#执行
+        @self.add_base
+        def action(*args, **kwargs):
+            nonlocal self
+            self.element_dict[Chains][0].perform()
+            sleep(run_time)
+        self.add_func(f'[{Chains}].run<{run_time}s', action)  # 添加func
+
+    def get_all_windows(self,*args,**kwargs):#获取所有句柄
+        @self.add_base
+        def find(browser, num, name, *args, **kwargs):
+            nonlocal self
+            if browser == None:browser = self.browser
+            self.element_dict[f'{name}[{num}]'] = browser.window_handles#获得窗口句柄
+        self.add_func(f'get_all_windows',find)#添加func
+
+    def get_now_windows(self,*args,**kwargs):#获取当前窗口句柄
+        @self.add_base
+        def find(browser, num, name, *args, **kwargs):
+            nonlocal self
+            if browser == None:browser = self.browser
+            self.element_dict[f'{name}[{num}]'] = [browser.current_window_handle]#获得当前窗口句柄
+        self.add_func(f'get_now_window',find)#添加func
+
+    def switch_to_windwos(self,element_value,index=0,**kwargs):#切换窗口
+        @self.add_base
+        def action(*args, **kwargs):
+            nonlocal self
+            self.browser.switch_to.window(self.element_dict[element_value][index])
+        self.add_func(f'switch_to_window>{element_value}[{index}]', action)  # 添加func
+
     def Element_interaction(self,update_func=lambda *args:None):#元素交互
         func_list = self.func_list
         status = None
+        self.log.write(f'{"*"*5}url:{self.now_url}{"*"*5}')
         def update(func_name):
             nonlocal status,self
             if status:
@@ -804,6 +979,7 @@ class Page_Parser:
                 success_code = 'No status'
             else:
                 success_code = 'Wrong to run'
+            self.log.write(f'last:[{success_code}];now:[{func_name}];url:{self.now_url} [END]')
             value_box = []
             for i in self.element_dict:
                 try:

+ 14 - 1
Information_storage.py

@@ -1,4 +1,5 @@
 import os
+import time
 
 class Database:
     def __init__(self,name):
@@ -70,4 +71,16 @@ class DataBase_Home:# data base控制器
         self.database[name].out_file(dir)
 
     def return_database(self):
-        return list(self.database.keys())
+        return list(self.database.keys())
+
+class log:
+    def __init__(self,log_dir):
+        self.log_dir = log_dir
+        self.log_file = open(log_dir + '/log.coTanLog','r+' if os.path.exists(log_dir + 'log.coTanLog') else 'w+')
+
+    def write(self,data):
+        self.log_file.write(f"[{time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time()))}] " + data + '\n')
+        self.log_file.flush()
+
+    def close(self):
+        self.log_file.close()

+ 201 - 32
Web_Crawler.py

@@ -40,7 +40,7 @@ def Main():
     URL_Input = tkinter.Entry(top, width=width_B * 2)
     URL_Input.grid(column=a_x + 1, row=a_y, columnspan=2, sticky=tkinter.E + tkinter.W)
 
-    global URL_ARGS,UA_Input,use_Cookies_Input,FUNC_Input,DATA_Input
+    global URL_ARGS,UA_Input,use_Cookies_Input,FUNC_Input,DATA_Input,TimeOut_Input
     a_y += 1
     URL_ARGS = []
     lable = ['不加载js','不加载java','不加载插件']#复选框
@@ -71,6 +71,11 @@ def Main():
     FUNC_Input = tkinter.Entry(top, width=width_B * 2)
     FUNC_Input.grid(column=a_x + 1, row=a_y, columnspan=2, sticky=tkinter.E + tkinter.W)
 
+    a_y += 1
+    tkinter.Label(top, text='请求超时:', bg=bg, fg=fg, font=FONT, width=width_B, height=height_B).grid(column=a_x,row=a_y)
+    TimeOut_Input = tkinter.Entry(top, width=width_B * 2)
+    TimeOut_Input.grid(column=a_x + 1, row=a_y, columnspan=2, sticky=tkinter.E + tkinter.W)
+
     a_y += 1
     tkinter.Label(top, text='Cookies:', bg=bg, fg=fg, font=FONT, width=width_B, height=height_B).grid(column=a_x,row=a_y)
     use_Cookies_Input = tkinter.Entry(top, width=width_B)
@@ -106,9 +111,9 @@ def Main():
     a_y += 3
     tkinter.Button(top, bg=bbg, fg=fg, text='单点爬虫运行',command=startDownloader, font=FONT, width=width_B,height=height_B).grid(
         column=a_x, row=a_y, sticky=tkinter.E + tkinter.W)
-    tkinter.Button(top, bg=bbg, fg=fg, text='爬虫运行',command=startDownloader, font=FONT, width=width_B,height=height_B).grid(
+    tkinter.Button(top, bg=bbg, fg=fg, text='爬虫运行',command=Crawler_Run, font=FONT, width=width_B,height=height_B).grid(
         column=a_x+1, row=a_y, sticky=tkinter.E + tkinter.W)
-    tkinter.Button(top, bg=bbg, fg=fg, text='单点爬虫停止',command=startDownloader, font=FONT, width=width_B,height=height_B).grid(
+    tkinter.Button(top, bg=bbg, fg=fg, text='单点爬虫停止',command=Crawler_Stop, font=FONT, width=width_B,height=height_B).grid(
         column=a_x+2, row=a_y, sticky=tkinter.E + tkinter.W)
 
     a_y += 1
@@ -120,10 +125,10 @@ def Main():
     cookies_fixed.set('0')
 
     a_y += 1
-    cookies_BOX = tkinter.Listbox(top, width=width_B * 3, height=height_B * 4)
-    cookies_BOX.grid(column=a_x, row=a_y, columnspan=3, rowspan=4, sticky=tkinter.E + tkinter.W + tkinter.S + tkinter.N)
+    cookies_BOX = tkinter.Listbox(top, width=width_B * 3, height=height_B * 3)
+    cookies_BOX.grid(column=a_x, row=a_y, columnspan=3, rowspan=3, sticky=tkinter.E + tkinter.W + tkinter.S + tkinter.N)
 
-    a_y += 4
+    a_y += 3
     tkinter.Button(top, bg=bbg, fg=fg, text='清空曲奇',command=Tra_cookies, font=FONT, width=width_B,height=height_B).grid(
         column=a_x, row=a_y, sticky=tkinter.E + tkinter.W)
     tkinter.Button(top, bg=bbg, fg=fg, text='更新曲奇',command=Update_cookies, font=FONT, width=width_B,height=height_B).grid(
@@ -175,11 +180,17 @@ def Main():
     search_Input.grid(column=a_x + 1, row=a_y, columnspan=2, sticky=tkinter.E + tkinter.W)
 
     a_y += 1
-    Parser_Func_BOX = tkinter.Listbox(top, width=width_B * 3, height=height_B * 4)
-    Parser_Func_BOX.grid(column=a_x, row=a_y, columnspan=3, rowspan=4, sticky=tkinter.E + tkinter.W + tkinter.S + tkinter.N)
+    tkinter.Button(top, bg=bbg, fg=fg, text='删除方法',command=Del_Parser_Func, font=FONT, width=width_B,height=height_B).grid(
+        column=a_x, row=a_y,columnspan=2 , sticky=tkinter.E + tkinter.W)
+    tkinter.Button(top, bg=bbg, fg=fg, text='清空方法',command=Tra_Parser_Func, font=FONT, width=width_B,height=height_B).grid(
+        column=a_x+2, row=a_y, sticky=tkinter.E + tkinter.W)
+
+    a_y += 1
+    Parser_Func_BOX = tkinter.Listbox(top, width=width_B * 3, height=height_B * 5)
+    Parser_Func_BOX.grid(column=a_x, row=a_y, columnspan=3, rowspan=5, sticky=tkinter.E + tkinter.W + tkinter.S + tkinter.N)
 
     global Var_Input,VarIndex_Input,Send_Input,UserPW_Input,SELE_Input,JS_Input,Time_Input
-    a_y += 4
+    a_y += 5
     tkinter.Label(top, text='操作元素:', bg=bg, fg=fg, font=FONT, width=width_B, height=height_B).grid(column=a_x,row=a_y)
     Var_Input = tkinter.Entry(top, width=width_B * 2)
     Var_Input.grid(column=a_x + 1, row=a_y, columnspan=2, sticky=tkinter.E + tkinter.W)
@@ -275,22 +286,6 @@ def Main():
     tkinter.Button(top, bg=bbg, fg=fg, text='选择value',command=lambda :Page_Parser_addActionFunc('select_by_value'), font=FONT, width=width_B,height=height_B).grid(
         column=a_x+2, row=a_y, sticky=tkinter.E + tkinter.W)
 
-    a_y += 1
-    tkinter.Button(top, bg=bbg, fg=fg, text='页面后退',command=lambda :Page_Parser_addActionFunc('back'), font=FONT, width=width_B,height=height_B).grid(
-        column=a_x, row=a_y, sticky=tkinter.E + tkinter.W)
-    tkinter.Button(top, bg=bbg, fg=fg, text='页面刷新',command=lambda :Page_Parser_addActionFunc('refresh'), font=FONT, width=width_B,height=height_B).grid(
-        column=a_x+1, row=a_y, sticky=tkinter.E + tkinter.W)
-    tkinter.Button(top, bg=bbg, fg=fg, text='页面前进',command=lambda :Page_Parser_addActionFunc('forward'), font=FONT, width=width_B,height=height_B).grid(
-        column=a_x+2, row=a_y, sticky=tkinter.E + tkinter.W)
-
-    a_y += 1
-    tkinter.Button(top, bg=bbg, fg=fg, text='暴力等待',command=lambda :Page_Parser_addActionFunc('wait_sleep'), font=FONT, width=width_B,height=height_B).grid(
-        column=a_x, row=a_y, sticky=tkinter.E + tkinter.W)
-    tkinter.Button(top, bg=bbg, fg=fg, text='元素检查等待',command=lambda :Page_Parser_addActionFunc('set_wait'), font=FONT, width=width_B,height=height_B).grid(
-        column=a_x+1, row=a_y, sticky=tkinter.E + tkinter.W)
-    tkinter.Button(top, bg=bbg, fg=fg, text='运行js',command=lambda :Page_Parser_addActionFunc('run_JS'), font=FONT, width=width_B,height=height_B).grid(
-        column=a_x+2, row=a_y, sticky=tkinter.E + tkinter.W)
-
     a_x += 3
     tkinter.Label(top, text='', bg=bg, fg=fg, font=FONT, width=1).grid(column=a_x, row=a_y)  # 设置说明
     a_x += 1
@@ -462,10 +457,10 @@ def Main():
     DataName_Input.grid(column=a_x + 1, row=a_y, columnspan=2, sticky=tkinter.E + tkinter.W)
 
     a_y += 1
-    DataBase_BOX = tkinter.Listbox(top, width=width_B * 3, height=height_B * 3)
-    DataBase_BOX.grid(column=a_x, row=a_y, columnspan=3, rowspan=3, sticky=tkinter.E + tkinter.W + tkinter.S + tkinter.N)
+    DataBase_BOX = tkinter.Listbox(top, width=width_B * 3, height=height_B * 5)
+    DataBase_BOX.grid(column=a_x, row=a_y, columnspan=3, rowspan=5, sticky=tkinter.E + tkinter.W + tkinter.S + tkinter.N)
 
-    a_y += 3
+    a_y += 5
     tkinter.Label(top, text='URL标签:', bg=bg, fg=fg, font=FONT, width=width_B, height=height_B).grid(column=a_x,row=a_y)
     URLTAG_Input = tkinter.Entry(top, width=width_B * 2)
     URLTAG_Input.grid(column=a_x + 1, row=a_y, columnspan=2, sticky=tkinter.E + tkinter.W)
@@ -478,6 +473,97 @@ def Main():
     tkinter.Button(top, bg=bbg, fg=fg, text='解析为json', command=lambda :Page_Parser_addActionFunc2('to_json'), font=FONT,
                    width=width_B, height=height_B).grid(column=a_x + 2, row=a_y, sticky=tkinter.E + tkinter.W)
 
+    global Special_keys,Chains_Input,element_value2_Input,index2_Input,run_time,key_Input
+
+    a_y += 1
+    tkinter.Label(top, text='操作动作链:', bg=bg, fg=fg, font=FONT, width=width_B, height=height_B).grid(column=a_x,row=a_y)
+    Chains_Input = tkinter.Entry(top, width=width_B * 2)
+    Chains_Input.grid(column=a_x + 1, row=a_y, columnspan=2, sticky=tkinter.E + tkinter.W)
+
+    a_y += 1
+    tkinter.Label(top, text='拽拖至元素:', bg=bg, fg=fg, font=FONT, width=width_B, height=height_B).grid(column=a_x,row=a_y)
+    element_value2_Input = tkinter.Entry(top, width=width_B * 2)
+    element_value2_Input.grid(column=a_x + 1, row=a_y, columnspan=2, sticky=tkinter.E + tkinter.W)
+
+    a_y += 1
+    tkinter.Label(top, text='拽拖索引:', bg=bg, fg=fg, font=FONT, width=width_B, height=height_B).grid(column=a_x,row=a_y)
+    index2_Input = tkinter.Entry(top, width=width_B * 2)
+    index2_Input.grid(column=a_x + 1, row=a_y, columnspan=2, sticky=tkinter.E + tkinter.W)
+
+    a_y += 1
+    tkinter.Label(top, text='键入值:', bg=bg, fg=fg, font=FONT, width=width_B, height=height_B).grid(column=a_x,row=a_y)
+    key_Input = tkinter.Entry(top, width=width_B * 2)
+    key_Input.grid(column=a_x + 1, row=a_y, columnspan=2, sticky=tkinter.E + tkinter.W)
+
+    a_y += 1
+    tkinter.Label(top, text='运行时长:', bg=bg, fg=fg, font=FONT, width=width_B, height=height_B).grid(column=a_x,row=a_y)
+    run_time = tkinter.Entry(top, width=width_B * 2)
+    run_time.grid(column=a_x + 1, row=a_y, columnspan=2, sticky=tkinter.E + tkinter.W)
+
+    a_y += 1
+    tkinter.Button(top, bg=bbg, fg=fg, text='点击左键',command=lambda :Page_Parser_addActionFunc3('click'), font=FONT, width=width_B,height=height_B).grid(
+        column=a_x, row=a_y, sticky=tkinter.E + tkinter.W)
+    tkinter.Button(top, bg=bbg, fg=fg, text='双击左键',command=lambda :Page_Parser_addActionFunc3('double_click'), font=FONT, width=width_B,height=height_B).grid(
+        column=a_x+1, row=a_y, sticky=tkinter.E + tkinter.W)
+    tkinter.Button(top, bg=bbg, fg=fg, text='点击右键', command=lambda :Page_Parser_addActionFunc3('click_right'), font=FONT,
+                   width=width_B, height=height_B).grid(column=a_x + 2, row=a_y, sticky=tkinter.E + tkinter.W)
+
+    a_y += 1
+    tkinter.Button(top, bg=bbg, fg=fg, text='按住左键',command=lambda :Page_Parser_addActionFunc3('click_and_hold'), font=FONT, width=width_B,height=height_B).grid(
+        column=a_x, row=a_y, sticky=tkinter.E + tkinter.W)
+    tkinter.Button(top, bg=bbg, fg=fg, text='松开左键',command=lambda :Page_Parser_addActionFunc3('release'), font=FONT, width=width_B,height=height_B).grid(
+        column=a_x+1, row=a_y, sticky=tkinter.E + tkinter.W)
+    tkinter.Button(top, bg=bbg, fg=fg, text='拽托元素', command=lambda :Page_Parser_addActionFunc2('drag_and_drop'), font=FONT,
+                   width=width_B, height=height_B).grid(column=a_x + 2, row=a_y, sticky=tkinter.E + tkinter.W)
+
+    a_y += 1
+    tkinter.Button(top, bg=bbg, fg=fg, text='移动鼠标',command=lambda :Page_Parser_addActionFunc3('move'), font=FONT, width=width_B,height=height_B).grid(
+        column=a_x, row=a_y, sticky=tkinter.E + tkinter.W)
+    tkinter.Button(top, bg=bbg, fg=fg, text='按下按键',command=lambda :Page_Parser_addActionFunc3('key_down'), font=FONT, width=width_B,height=height_B).grid(
+        column=a_x+1, row=a_y, sticky=tkinter.E + tkinter.W)
+    tkinter.Button(top, bg=bbg, fg=fg, text='抬起按键', command=lambda :Page_Parser_addActionFunc3('key_up'), font=FONT,
+                   width=width_B, height=height_B).grid(column=a_x + 2, row=a_y, sticky=tkinter.E + tkinter.W)
+
+    Special_keys = tkinter.IntVar()
+    a_y += 1
+    tkinter.Button(top, bg=bbg, fg=fg, text='发送文本到焦点',command=lambda :Page_Parser_addActionFunc3('send_keys'), font=FONT, width=width_B,height=height_B).grid(
+        column=a_x, row=a_y, sticky=tkinter.E + tkinter.W)
+    tkinter.Button(top, bg=bbg, fg=fg, text='发送文本',command=lambda :Page_Parser_addActionFunc3('send_keys_to_element'), font=FONT, width=width_B,height=height_B).grid(
+        column=a_x+1, row=a_y, sticky=tkinter.E + tkinter.W)
+    tkinter.Checkbutton(top, bg=bg, fg=fg, activebackground=bg, activeforeground=fg, selectcolor=bg, text='转换为特殊按钮',
+                        variable=Special_keys).grid(column=a_x + 2, row=a_y, sticky=tkinter.W)
+
+    a_y += 1
+    tkinter.Button(top, bg=bbg, fg=fg, text='生成动作链',command=lambda :Page_Parser_addActionFunc3('make_ActionChains'), font=FONT, width=width_B,height=height_B).grid(
+        column=a_x, row=a_y, sticky=tkinter.E + tkinter.W)
+    tkinter.Button(top, bg=bbg, fg=fg, text='运行动作链',command=lambda :Page_Parser_addActionFunc3('ActionChains_run'), font=FONT, width=width_B,height=height_B).grid(
+        column=a_x+1,columnspan=2, row=a_y, sticky=tkinter.E + tkinter.W)
+
+    a_y += 1
+    tkinter.Button(top, bg=bbg, fg=fg, text='获取当前窗口',command=lambda :Page_Parser_addActionFunc('get_now_windows'), font=FONT, width=width_B,height=height_B).grid(
+        column=a_x, row=a_y, sticky=tkinter.E + tkinter.W)
+    tkinter.Button(top, bg=bbg, fg=fg, text='获取所有窗口',command=lambda :Page_Parser_addActionFunc('get_all_windows'), font=FONT, width=width_B,height=height_B).grid(
+        column=a_x+1, row=a_y, sticky=tkinter.E + tkinter.W)
+    tkinter.Button(top, bg=bbg, fg=fg, text='切换窗口', command=lambda :Page_Parser_addActionFunc('switch_to_windwos'), font=FONT,
+                   width=width_B, height=height_B).grid(column=a_x + 2, row=a_y, sticky=tkinter.E + tkinter.W)
+
+    a_y += 1
+    tkinter.Button(top, bg=bbg, fg=fg, text='暴力等待',command=lambda :Page_Parser_addActionFunc('wait_sleep'), font=FONT, width=width_B,height=height_B).grid(
+        column=a_x, row=a_y, sticky=tkinter.E + tkinter.W)
+    tkinter.Button(top, bg=bbg, fg=fg, text='元素检查等待',command=lambda :Page_Parser_addActionFunc('set_wait'), font=FONT, width=width_B,height=height_B).grid(
+        column=a_x+1, row=a_y, sticky=tkinter.E + tkinter.W)
+    tkinter.Button(top, bg=bbg, fg=fg, text='运行js',command=lambda :Page_Parser_addActionFunc('run_JS'), font=FONT, width=width_B,height=height_B).grid(
+        column=a_x+2, row=a_y, sticky=tkinter.E + tkinter.W)
+
+    a_y += 1
+    tkinter.Button(top, bg=bbg, fg=fg, text='页面后退',command=lambda :Page_Parser_addActionFunc('back'), font=FONT, width=width_B,height=height_B).grid(
+        column=a_x, row=a_y, sticky=tkinter.E + tkinter.W)
+    tkinter.Button(top, bg=bbg, fg=fg, text='页面刷新',command=lambda :Page_Parser_addActionFunc('refresh'), font=FONT, width=width_B,height=height_B).grid(
+        column=a_x+1, row=a_y, sticky=tkinter.E + tkinter.W)
+    tkinter.Button(top, bg=bbg, fg=fg, text='页面前进',command=lambda :Page_Parser_addActionFunc('forward'), font=FONT, width=width_B,height=height_B).grid(
+        column=a_x+2, row=a_y, sticky=tkinter.E + tkinter.W)
+
+
     top.update()#要预先update一下,否则会卡住
     global url,loader,Page_Parser,DataBase,save_dir
     save_dir = askdirectory(title='选择项目位置')#项目位置
@@ -487,6 +573,11 @@ def Main():
     DataBase = Crawler_controller.data_base#数据库
 
     top.mainloop()
+    #关闭操作
+    loader.stop()
+    DataBase.close_all()
+    url.close()
+    loader.close()
 
 def to_Database(is_tag=True):
     global VarIndex_Input,Var_Input,Data_Input,Page_Parser
@@ -575,6 +666,23 @@ def update_Attributes_BOX():
     Attributes_BOX.delete(0, tkinter.END)
     Attributes_BOX.insert(tkinter.END,*show)
 
+def Func_Args3():#方法args统一转换(第三栏目)
+    global Special_keys, Chains_Input, element_value2_Input, index2_Input, run_time,Var_Input,VarIndex_Input,key_Input
+    try:
+        index = int(VarIndex_Input.get())
+    except:
+        index = 0
+    try:
+        index2 = int(index2_Input.get())
+    except:
+        index2 = 0
+    try:
+        time = int(run_time.get())
+    except:
+        time = 1
+    return dict(Chains=Chains_Input.get(),element_value=Var_Input.get(),index=index,element_value2=element_value2_Input.get(),
+                index2=index2,run_time=time,is_special_keys = bool(Special_keys.get()),key=key_Input.get())
+
 def Func_Args2():#方法args统一转换(第二栏目)
     global CookiesName_Input,Cookies_Input,Tag_Input,Attributes_Dict,Var_Input,VarIndex_Input
     global FindAllText_Input,text_re,limit_Input,recursive_Input,FindAllPATH_Input
@@ -611,6 +719,20 @@ def Func_Args():#方法args统一转换(不支持Frame)
     time=time
     )
 
+def Page_Parser_addActionFunc3(func):
+    global Page_Parser
+    args = Func_Args3()
+    FUNC = {'make_ActionChains':Page_Parser.make_ActionChains,'click':Page_Parser.ActionChains_click,
+            'double_click':Page_Parser.ActionChains_double_click,
+            'click_right':Page_Parser.ActionChains_click_right,'click_and_hold':Page_Parser.ActionChains_click_and_hold,
+            'release':Page_Parser.ActionChains_release,'drag_and_drop':Page_Parser.ActionChains_drag_and_drop,
+            'move':Page_Parser.ActionChains_move,'key_down':Page_Parser.ActionChains_key_down,
+            'key_up':Page_Parser.ActionChains_key_up,'send_keys_to_element':Page_Parser.ActionChains_send_keys_to_element,
+            'send_keys':Page_Parser.ActionChains_send_keys,'ActionChains_run':Page_Parser.ActionChains_run}.get(
+        func,Page_Parser.make_ActionChains)
+    FUNC(**args)
+    Update_Parser_Func_BOX()
+
 def Page_Parser_addActionFunc2(func):
     global Page_Parser
     args = Func_Args2()
@@ -631,7 +753,9 @@ def Page_Parser_addActionFunc(func):
             'deselect_by_value':Page_Parser.deselect_by_value,'deselect_by_text':Page_Parser.deselect_by_text,'select_by_index':Page_Parser.select_by_index,
             'select_by_value':Page_Parser.select_by_value,'select_by_text':Page_Parser.select_by_text,'back':Page_Parser.back,'forward':Page_Parser.forward,
             'refresh':Page_Parser.refresh,'wait_sleep':Page_Parser.wait_sleep,'set_wait':Page_Parser.set_wait,'run_JS':Page_Parser.run_JS,
-            'out':Page_Parser.out_html,'get_Page':Page_Parser.to_text}.get(func,Page_Parser.send_keys)
+            'out':Page_Parser.out_html,'get_Page':Page_Parser.to_text,'get_all_windows':Page_Parser.get_all_windows,
+            'get_now_windows':Page_Parser.get_now_windows,'switch_to_windwos':Page_Parser.switch_to_windwos
+            }.get(func,Page_Parser.send_keys)
     FUNC(**args)
     Update_Parser_Func_BOX()
 
@@ -659,6 +783,23 @@ def Page_Parser_addFindFunc(func):
     FUNC(search,not_all=not_all)
     Update_Parser_Func_BOX()
 
+def Del_Parser_Func():
+    global Page_Parser
+    try:
+        index = Parser_Func_BOX.curselection()[0]
+        Page_Parser.del_func(index,True)
+        Update_Parser_Func_BOX()
+    except:
+        pass
+
+def Tra_Parser_Func():
+    global Page_Parser
+    try:
+        Page_Parser.tra_func()
+        Update_Parser_Func_BOX()
+    except:
+        pass
+
 def Update_Parser_Func_BOX():
     global Parser_Func_BOX,Page_Parser
     Parser_Func_BOX.delete(0,tkinter.END)
@@ -712,15 +853,38 @@ def cookies_BOX_Update(cookies):
         cookies_BOX.delete(0,tkinter.END)
         cookies_BOX.insert(0,*cookies)
 
+def Crawler_Stop():
+    global startLoader_Stop
+    startLoader_Stop = False
+    loader.stop()
+
+def Crawler_Run():
+    global startLoader_Stop
+    def startLoader():
+        global loader,Page_Parser,url,startLoader_Stop
+        loader.stop()#把之前的停止
+        while startLoader_Stop:
+            if url.finish():break
+            loader.strat_urlGet(func_cookie=cookies_BOX_Update)
+            update_URLBOX()
+            Page_Parser.Element_interaction(update_Status)
+        loader.stop()
+
+    startLoader_Stop = True
+    new = threading.Thread(target=startLoader)
+    new.start()
+    update_URLBOX()
+
 def startDownloader():
     def startLoader():
         global loader,Page_Parser
         loader.strat_urlGet(func_cookie=cookies_BOX_Update)
+        update_URLBOX()
         Page_Parser.Element_interaction(update_Status)
+        loader.stop()
 
     new = threading.Thread(target=startLoader)
     new.start()
-    update_URLBOX()
 
 def add_filter_func_HTTPS():
     global url
@@ -750,16 +914,21 @@ def del_url():
     update_URLBOX()
 
 def add_args():
-    global URL_ARGS, UA_Input, use_Cookies_Input,FUNC_Input,DATA_Input
+    global URL_ARGS, UA_Input, use_Cookies_Input,FUNC_Input,DATA_Input,TimeOut_Input
     try:
         data = eval(DATA_Input.get(),{})
     except:
         data = {}
+    try:
+        TimeOut = int(TimeOut_Input.get())
+    except:
+        TimeOut = 5
     re = dict(
         func = FUNC_Input.get(),
         UA = UA_Input.get(),
         cookies = use_Cookies_Input.get(),
-        data=data
+        data=data,
+        time_out=TimeOut
         )
     name = ['no_js','no_java','no_plugins','first_run','head','no_img','new']
     for i in range(len(name)):