学以致用——植物信息录入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 Imageclass Main: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()def sign_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.5rangle = (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() # 实例化验证码识别类with open(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('登录过程出现错误,请检查网络连接后重新尝试登录')def send_to_console(self, message, end='\n'):self.console.insert(END, message+end)self.console.see(END)self.root.update()def wait_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)def wait_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()def inspect_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('未检测到选择操作文件夹,请选择')def add_new(self):folder = self.folder.get()count = 0total = len(os.listdir(folder))for file in os.listdir(folder):count += 1filepath = 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)@staticmethoddef read_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 infoif __name__ == '__main__':a = Main()
当勉
程序当如诗一般,简单、简约。当然也不会一蹴而就,不断打磨才成精品。
相关文章:
学以致用——植物信息录入1.0(selenium+pandas+os+tkinter)
目的 书接上文,学以致用——植物信息录入(seleniumpandasostkinter) 更新要点: tkinter界面:自动登录、新增(核心功能)、文件夹选择、流程台selenium自动化操作:验证码识别excel数据…...
什么是压敏电阻
下面的这些都是压敏电阻,常常用在一些电源和信号的浪涌防护电路中。这个是它的电路符号,电路中常用RV表示。当压敏电阻两端电压小于压敏电压时,压敏电阻相当于一个阻值非常大的电阻。当压敏电阻两端电压大于压敏电压时,压敏电阻相…...
Leetcode.901 股票价格跨度
题目链接 Leetcode.901 股票价格跨度 Rating : 1709 题目描述 设计一个算法收集某些股票的每日报价,并返回该股票当日价格的 跨度 。 当日股票价格的 跨度 被定义为股票价格小于或等于今天价格的最大连续日数(从今天开始往回数,…...
vue入门(四)组件基础,$emits简单用法
上一篇:vue入门(三)事件(方法)处理、侦听器、模板引用 1.组件最基础的用法: 首先有一个button.vue的组件,里面只画了一个按钮 button.vue: <script> export default({data(){return{but…...
VBA提高篇_27 OptionBOX_CheckBox_Frame_Image_VBA附加控件
文章目录1.单选按钮OptionBOX:2.复选框CheckBox:3.框架Frame:4.图像Image: (loadPictrue)5. VBA附加控件:6. 适用于很多控件的重要属性:1.单选按钮OptionBOX: 默认时,同一窗体的所有单选按钮均属于同一组,只能选中一个 可通过Frame控件进行分组解决. 2.复选框CheckBox: 一次可以…...
STM32开发(11)----CubeMX配置独立看门狗(IWDG)
CubeMX配置独立看门狗(IWDG)前言一、独立看门狗的介绍二、实验过程1.STM32CubeMX配置独立看门狗2.代码实现3.硬件连接4.实验结果总结前言 本章介绍使用STM32CubeMX对独立看门狗定时器进行配置的方法。门狗本质上是一个定时器,提供了更高的安…...
医疗方案 | 星辰天合入选“2022智慧新医信优秀解决方案”
近日,由 HC3i数字医疗网主办的《数字化转型驱动下的医院高质量发展论坛》暨 2022 智慧新医信优秀解决方案发布仪式在线上召开。XSKY星辰天合的“智慧医疗软件定义数据基础设施”解决方案成功入选 2022 智慧新医信优秀解决方案,。此次论坛由 HC3i 数字医疗…...
【系统服务实战】tomcat服务的安装实战
未来要更新的专栏(此表格后面会继续完善) 专栏系列学习路线完成情况云原生系列linux基本功系列-基础命令汇总已更新51个命令云原生系列linux基本功系列-系统服务实战正在更新文章目录前言一. tomcat的概述1.1 什么是tomcat1.2 tomcat的官网二. tomcat单…...
【图文详解】Unity存储游戏数据的几种方法
Unity3D存储游戏数据的方式1 PlayerPrefs: Unity自带的一种简单的键值存储系统2 ScriptableObject: Unity中最灵活的数据管理工具2.1 如何手动创建和修改数据文件2.2 ScriptableObject优缺点总结3 JSON: 轻量级的数据交换格式3.1 序列化与反序列化3.2 用JsonUtility对对象进行序…...
SESAM 安装教程
SESAM (Super Element Structure Analysis Module)是由挪威船级社(DNV-GL)开发的一款有限元分析(FEA)系统,它以 GeniE、HydroD 和 DeepC 等模块为核心,主要用于海工结构的强度评估、…...
语言文件操作
🌱博客主页:大寄一场. 🌱系列专栏:C语言学习笔记 😘博客制作不易欢迎各位👍点赞⭐收藏➕关注 目录 前言 C语言中的文件打开和关闭 文件指针 文件的打开和关闭 fclose 文件的顺序读写 fseek ftell …...
Java面试题--熔断和降级的区别
熔断和降级都是系统自我保护的一种机制,但二者又有所不同,它们的区别主要体现在以下几点: 概念不同 触发条件不同 归属关系不同 1.概念不同 1.1熔断概念 “熔断”一词早期来自股票市场。熔断(Circuit Breaker)也…...
阅读笔记5——深度可分离卷积
一、标准卷积 标准卷积在卷积时,同时考虑了特征图的区域和通道信息。 标准卷积的过程如图1-1所示,假设输入特征图的channel3,则每个卷积核的channel都为3,每个卷积核的3个channel对应提取输入特征图的3个channel的特征(…...
Microsoft Dynamics 365:导入License到服务层,通过Business Central Administration Shell
本文主要是Microsoft Dynamics 365的License导入的图解干货,不多赘述,直接上图:第一步:准备好的License文件放在你喜欢的目录下第二步:到开始程序里找到并打开 Business Central Administration Shell3.第三步…...
centos6.10安装FastDfs出错的问题
在centos6.10虚拟机安装dfs文件服务器时,安装报错,报错为: gcc: error trying to exec cc1’: execvp: 没有那个文件或目录 1.ping www.baidu.con 排查网络是否通 2.yum update 排查yum源是否可用 3.yum源地址不可用时,修改yu…...
基础组件之内存池
内存池技术 操作系统在运行进程的过程中,会产生内存碎片,降低了内存的使用率。内存池技术就是为了解决/减少内存碎片的一种方法,内部底层的具体实现根据不同业务场景使用不要的方式,以下是一种好理解的方式,供大家一起…...
前端面试题--了解并简单介绍一下typescript
前端面试题–了解并简单介绍一下typescript TypeScript是JavaScript的超集,具有可选的类型并可以编译为纯JavaScript。 从技术上讲TypeScript就是具有静态类型的 JavaScript 。 向JavaScript添加静态类型的原因是什么?我想原因至少有三个: …...
【pytorch】ModuleList 与 ModuleDict
ModuleList 与 ModuleDict1、ModuleList2、ModuleDict3、总结1、ModuleList 1)ModuleList 接收一个子模块的列表作为输入,然后也可以类似 List 那样进行 append 和 extend 操作: net nn.ModuleList([nn.Linear(784, 256), nn.ReLU()]) net.append(nn.…...
Hive窗口函数语法规则、窗口聚合函数、窗口表达式、窗口排序函数 - ROW NUMBER 、口排序函数 - NTILE、窗口分析函数
Hive窗口函数 文章目录Hive窗口函数语法规则窗口聚合函数窗口表达式窗口排序函数 - ROW NUMBER窗口排序函数 - NTILE窗口分析函数窗口函数也叫开窗函数、OLAP函数其最大特点:输入值是从SELECT语句的结果集中的一行或多行的“窗口”中获取的。如果函数具有OVER子句&a…...
Go设计模式之函数选项模式
目录引入函数选项模式(functional options pattern)可选参数默认值接口类型版本引入 假设现在需要定义一个包含多个配置项的结构体,具体定义如下: // DoSomethingOption 定义配置项 type DoSomethingOption struct {// a 配置aa…...
C++初阶-list的底层
目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...
Xshell远程连接Kali(默认 | 私钥)Note版
前言:xshell远程连接,私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...
【WiFi帧结构】
文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成:MAC头部frame bodyFCS,其中MAC是固定格式的,frame body是可变长度。 MAC头部有frame control,duration,address1,address2,addre…...
【网络安全产品大调研系列】2. 体验漏洞扫描
前言 2023 年漏洞扫描服务市场规模预计为 3.06(十亿美元)。漏洞扫描服务市场行业预计将从 2024 年的 3.48(十亿美元)增长到 2032 年的 9.54(十亿美元)。预测期内漏洞扫描服务市场 CAGR(增长率&…...
【大模型RAG】Docker 一键部署 Milvus 完整攻略
本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装;只需暴露 19530(gRPC)与 9091(HTTP/WebUI)两个端口,即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...
dedecms 织梦自定义表单留言增加ajax验证码功能
增加ajax功能模块,用户不点击提交按钮,只要输入框失去焦点,就会提前提示验证码是否正确。 一,模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...
Spring AI 入门:Java 开发者的生成式 AI 实践之路
一、Spring AI 简介 在人工智能技术快速迭代的今天,Spring AI 作为 Spring 生态系统的新生力量,正在成为 Java 开发者拥抱生成式 AI 的最佳选择。该框架通过模块化设计实现了与主流 AI 服务(如 OpenAI、Anthropic)的无缝对接&…...
工业自动化时代的精准装配革新:迁移科技3D视觉系统如何重塑机器人定位装配
AI3D视觉的工业赋能者 迁移科技成立于2017年,作为行业领先的3D工业相机及视觉系统供应商,累计完成数亿元融资。其核心技术覆盖硬件设计、算法优化及软件集成,通过稳定、易用、高回报的AI3D视觉系统,为汽车、新能源、金属制造等行…...
微信小程序云开发平台MySQL的连接方式
注:微信小程序云开发平台指的是腾讯云开发 先给结论:微信小程序云开发平台的MySQL,无法通过获取数据库连接信息的方式进行连接,连接只能通过云开发的SDK连接,具体要参考官方文档: 为什么? 因为…...
Caliper 配置文件解析:config.yaml
Caliper 是一个区块链性能基准测试工具,用于评估不同区块链平台的性能。下面我将详细解释你提供的 fisco-bcos.json 文件结构,并说明它与 config.yaml 文件的关系。 fisco-bcos.json 文件解析 这个文件是针对 FISCO-BCOS 区块链网络的 Caliper 配置文件,主要包含以下几个部…...
