0


学以致用——植物信息录入1.0(selenium+pandas+os+tkinter)

目的

书接上文,学以致用——植物信息录入(selenium+pandas+os+tkinter)

更新要点:

  • tkinter界面:自动登录、新增(核心功能)、文件夹选择、流程台
  • selenium自动化操作:验证码识别
  • excel数据:精准匹配key,获取相应value

操作优化:

  • 只需登录一次即可,操作员可以在当前文件夹完成后,继续选择新的文件夹运行,循环往复。
  • 验证码识别解放操作员手动登录
  • 录入表单的数据准确无误

后续:

  • 对物种信息的正确性验证
  • 自动跳转至属级提交表单
  • tkinter添加用户选择

回头看:

  • ddddocr库搭配PIL库,可以便捷地进行验证码图片识别,在本项目中完美地承担了读取验证码的任务。对于更复杂的验证码还没有验证。
  • selenium自动化操作网页时,在本项目后期运行期间,由于网络波动导致了大量的定位元素失败。由此我认识到WebDriverWait(详情请看代码中)在等待页面元素加载是至关重要的,且应用尽用。
  • selenium在定位frame等元素时,总是无法通过id、name、link_text等方法实现,具体原因未知。但可以采用遍历所有frame元素,再通过索引定位。
  • tkinter图形化是我比较常用的,也比较熟悉。或许将selenium内嵌在tkinter图形化里面有更好的用户体验。未来可以多试验试验。

整体代码

import pandas as pd
import time
import os
from tkinter import*from tkinter.filedialog import askdirectory
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.keys import Keys
import ddddocr
from PIL import Image

classMain:def__init__(self):
        self.root = Tk()
        self.root.attributes('-topmost',1)# 保持tkinter界面处于顶层,方便点击操作
        self.signin = Button(self.root, text='登录系统', command=self.sign_in)# 登录按钮
        self.signin.grid(row=0, column=0)
        self.addnew = Button(self.root, text='新增', command=self.add_new, state=DISABLED)# 新增按钮
        self.addnew.grid(row=0, column=1)
        self.folder = StringVar()
        Label(self.root, textvariable=self.folder).grid(row=1, column=0)# 显示文件夹路径
        self.choose_folder = Button(self.root, text='选择操作文件夹', command=self.inspect_folder, state=DISABLED)# 选择按钮
        self.choose_folder.grid(row=1, column=1)
        self.console = Text(self.root)# 显示台
        self.console.grid(row=2, column=0, columnspan=2)
        self.console.insert(0.0,'首先点击《登录》按钮,完成用户登录后,再点击《选择操作文件夹--属级文件夹》,最后点击《新增》\n')# 初始显示简易操作流程

        self.driver = webdriver.Chrome(service=Service(r"D:\ALL_Softwares\Python 3.10.4\Scripts\chromedriver.exe"))
        self.driver.maximize_window()
        self.wait = WebDriverWait(self.driver,100)
        self.root.mainloop()defsign_in(self):try:
            self.driver.get('http://www.cn-flora.ac.cn:28080/plantonline/frame/toLoginPage')
            self.wait_for_send("_loginName",'id', user)# 用户名
            self.wait_for_send("_loginPwd",'id', pwd)# 密码
            self.wait.until(lambda d: d.find_element(By.ID,'authImage'))# 等待验证码图片加载完成
            self.driver.save_screenshot(r'screenshot.png')# 截屏
            img_element = self.driver.find_element(By.ID,'authImage')#定位到验证码元素
            location = img_element.location # 获取验证码坐标
            size = img_element.size # 获取验证码长宽
            zoom =1.2# 我的电脑是1.5
            rangle =(int(location['x']* zoom),int(location['y']* zoom),int(location['x']* zoom + size['width']* zoom),int(location['y']* zoom + size['height']* zoom))# 根据电脑显示不同配置合适的裁剪大小
            i = Image.open(r'screenshot.png')# 打开截屏
            frame4 = i.crop(rangle)# 裁剪
            frame4 = frame4.convert('RGB')
            frame4.save(r'img.png')# 保存验证码图片
            ocr = ddddocr.DdddOcr()# 实例化验证码识别类withopen(r'img.png','rb')as r:
                img_bytes = r.read()
            res = ocr.classification(img_bytes)# 完成识别
            self.wait_for_send('loginValidCode','name', res)# 验证码
            self.driver.find_element(By.NAME,'loginValidCode').send_keys(Keys.ENTER)# 回车登录
            self.send_to_console('自动登录成功!选择操作文件夹已激活,请点击操作!')
            self.choose_folder.config(state=ACTIVE)# 激活选择操作文件夹
            self.signin.config(state=DISABLED)# 登录按钮失活
            self.root.update()

            os.remove(r'img.png')
            os.remove(r'screenshot.png')except:
            self.send_to_console('登录过程出现错误,请检查网络连接后重新尝试登录')defsend_to_console(self, message, end='\n'):
        self.console.insert(END, message+end)
        self.console.see(END)
        self.root.update()defwait_for_send(self, element, element_type, content):if element_type =='name':
            self.wait.until(lambda d: d.find_element(By.NAME, element))
            self.driver.find_element(By.NAME, element).send_keys(u'%s'% content)elif element_type =='tag':
            self.wait.until(lambda d: d.find_element(By.TAG_NAME, element))
            self.driver.find_element(By.TAG_NAME, element).send_keys(u'%s'% content)elif element_type =='id':
            self.wait.until(lambda d: d.find_element(By.ID, element))
            self.driver.find_element(By.ID, element).send_keys(u'%s'% content)defwait_for_click(self, element, element_type):if element_type =='name':
            self.wait.until(lambda d: d.find_element(By.NAME, element))
            self.driver.find_element(By.NAME, element).click()elif element_type =='tag':
            self.wait.until(lambda d: d.find_element(By.TAG_NAME, element))
            self.driver.find_element(By.TAG_NAME, element).click()elif element_type =='id':
            self.wait.until(lambda d: d.find_element(By.ID, element))
            self.driver.find_element(By.ID, element).click()elif element_type =='link':
            self.wait.until(lambda d: d.find_element(By.LINK_TEXT), element)
            self.driver.find_element(By.LINK_TEXT, element).click()elif element_type =='xpath':
            self.wait.until(lambda d: d.find_element(By.XPATH, element))
            self.driver.find_element(By.XPATH, element).click()definspect_folder(self):
        folder = askdirectory()if folder:
            self.folder.set(folder)
            self.send_to_console(f'成功读取 {folder}')
            self.send_to_console(f'请在网页中选择至{folder.split("/")[-1]}')
            self.choose_folder.config(state=DISABLED)
            filelist = os.listdir(folder)
            self.send_to_console(f'读取到{len(filelist)}个文件,请点击新增开始运行!')
            self.addnew.config(state=ACTIVE)else:
            self.send_to_console('未检测到选择操作文件夹,请选择')defadd_new(self):
        folder = self.folder.get()
        count =0
        total =len(os.listdir(folder))forfilein os.listdir(folder):
            count +=1
            filepath = os.path.join(folder,file)
            self.send_to_console(f'{count} / {total}{file} 处理中...', end='--')
            self.send_to_console('处理数据中...', end='--')
            info = self.read_species(filepath)
            self.send_to_console(f'{info}', end='--')

            self.driver.switch_to.default_content()
            n = self.driver.find_elements(By.TAG_NAME,'iframe')[1]
            self.driver.switch_to.frame(n)
            o = self.driver.find_elements(By.TAG_NAME,'frame')[1]
            self.driver.switch_to.frame(o)
            p = self.driver.find_elements(By.TAG_NAME,'button')
            p[2].click()# 定位到录入表单
            self.driver.switch_to.default_content()
            q = self.driver.find_elements(By.TAG_NAME,'iframe')
            self.driver.switch_to.frame(q[1])
            r = self.driver.find_elements(By.TAG_NAME,'frame')[1]
            self.driver.switch_to.frame(r)
            wait = WebDriverWait(self.driver,100)
            wait.until(lambda d: d.find_element(By.NAME,'acName'))if info['物种中文名']!='':
                self.driver.find_element(By.NAME,'acName').send_keys(u'%s'% info['物种中文名'])else:
                self.driver.find_element(By.NAME,'acName').send_keys(u'%s'% info['物种学名'])
            wait.until(lambda d: d.find_element(By.NAME,'acKeywords'))
            self.driver.find_element(By.NAME,'acKeywords').send_keys(u'%s'% info['物种学名'])
            wait.until(lambda d: d.find_element(By.NAME,'acExtendProperties'))
            self.driver.find_element(By.NAME,'acExtendProperties').send_keys(u'%s'% info['俗名信息'])
            wait.until(lambda d: d.find_element(By.NAME,'acRemark'))
            self.driver.find_element(By.NAME,'acRemark').send_keys(u'%s'% info['分类概念依据'])
            wait.until(lambda d: d.find_element(By.TAG_NAME,'iframe'))
            self.driver.switch_to.frame(self.driver.find_element(By.TAG_NAME,'iframe'))
            self.driver.find_element(By.TAG_NAME,'p').send_keys(u'%s'% info['形态特征'])

            self.driver.switch_to.parent_frame()
            wait.until(lambda d: d.find_element(By.NAME,'acKuozhan3'))
            self.driver.find_element(By.NAME,'acKuozhan3').send_keys(u'%s'% info['国内分布'])
            wait.until(lambda d: d.find_element(By.NAME,'acKuozhan4'))
            self.driver.find_element(By.NAME,'acKuozhan4').send_keys(u'%s'% info['国外分布'])
            wait.until(lambda d: d.find_element(By.NAME,'acKuozhan5'))
            self.driver.find_element(By.NAME,'acKuozhan5').send_keys(u'%s'% info['生境'])

            self.driver.find_element(By.TAG_NAME,'button').submit()
            time.sleep(1)# wait = WebDriverWait(driver, 10)
            wait.until(EC.alert_is_present())# 等待录入成功弹窗出现
            self.driver.switch_to.alert.accept()# 确定成功
            time.sleep(1)# 等待页面刷新

            os.remove(filepath)# 防止意外终止后无法区分是否录入,成功后删除EXCEL文件
            self.root.update()

            self.send_to_console('新建成功并已删除文件!')
        self.send_to_console(f'已完成{folder}。可能存在文件无法检测到的情况,请检查文件夹中是否有未读取文件,如有请更改文件名后再次操作!继续选择操作文件夹或关闭界面!')
        self.choose_folder.config(state=ACTIVE)@staticmethoddefread_species(filepath):try:
            df = pd.read_excel(filepath, sheet_name='物种百科', keep_default_na=False)except:
            df = pd.read_excel(filepath, sheet_name='Sheet1', keep_default_na=False)
        info ={'物种学名':'','物种中文名':'','分类概念依据':'','俗名信息':'','形态特征':'','生境':'','国内分布':'','国外分布':''}for key, item in info.items():for row in df.itertuples():for value in row:if key ==str(value).strip():
                        info[key]= row[4].strip()breakreturn info

if __name__ =='__main__':
    a = Main()

当勉

程序当如诗一般,简单、简约。当然也不会一蹴而就,不断打磨才成精品。

标签: selenium pandas python

本文转载自: https://blog.csdn.net/whitedrogen/article/details/129121438
版权归原作者 ALittleHigh 所有, 如有侵权,请联系我们删除。

“学以致用——植物信息录入1.0(selenium+pandas+os+tkinter)”的评论:

还没有评论