学以致用——植物信息录入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…...
python打卡day49
知识点回顾: 通道注意力模块复习空间注意力模块CBAM的定义 作业:尝试对今天的模型检查参数数目,并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...
React Native 导航系统实战(React Navigation)
导航系统实战(React Navigation) React Navigation 是 React Native 应用中最常用的导航库之一,它提供了多种导航模式,如堆栈导航(Stack Navigator)、标签导航(Tab Navigator)和抽屉…...
FFmpeg 低延迟同屏方案
引言 在实时互动需求激增的当下,无论是在线教育中的师生同屏演示、远程办公的屏幕共享协作,还是游戏直播的画面实时传输,低延迟同屏已成为保障用户体验的核心指标。FFmpeg 作为一款功能强大的多媒体框架,凭借其灵活的编解码、数据…...
线程同步:确保多线程程序的安全与高效!
全文目录: 开篇语前序前言第一部分:线程同步的概念与问题1.1 线程同步的概念1.2 线程同步的问题1.3 线程同步的解决方案 第二部分:synchronized关键字的使用2.1 使用 synchronized修饰方法2.2 使用 synchronized修饰代码块 第三部分ÿ…...
解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错
出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上,所以报错,到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本,cu、torch、cp 的版本一定要对…...
人工智能--安全大模型训练计划:基于Fine-tuning + LLM Agent
安全大模型训练计划:基于Fine-tuning LLM Agent 1. 构建高质量安全数据集 目标:为安全大模型创建高质量、去偏、符合伦理的训练数据集,涵盖安全相关任务(如有害内容检测、隐私保护、道德推理等)。 1.1 数据收集 描…...
适应性Java用于现代 API:REST、GraphQL 和事件驱动
在快速发展的软件开发领域,REST、GraphQL 和事件驱动架构等新的 API 标准对于构建可扩展、高效的系统至关重要。Java 在现代 API 方面以其在企业应用中的稳定性而闻名,不断适应这些现代范式的需求。随着不断发展的生态系统,Java 在现代 API 方…...
java高级——高阶函数、如何定义一个函数式接口类似stream流的filter
java高级——高阶函数、stream流 前情提要文章介绍一、函数伊始1.1 合格的函数1.2 有形的函数2. 函数对象2.1 函数对象——行为参数化2.2 函数对象——延迟执行 二、 函数编程语法1. 函数对象表现形式1.1 Lambda表达式1.2 方法引用(Math::max) 2 函数接口…...
网页端 js 读取发票里的二维码信息(图片和PDF格式)
起因 为了实现在报销流程中,发票不能重用的限制,发票上传后,希望能读出发票号,并记录发票号已用,下次不再可用于报销。 基于上面的需求,研究了OCR 的方式和读PDF的方式,实际是可行的ÿ…...
嵌入式面试常问问题
以下内容面向嵌入式/系统方向的初学者与面试备考者,全面梳理了以下几大板块,并在每个板块末尾列出常见的面试问答思路,帮助你既能夯实基础,又能应对面试挑战。 一、TCP/IP 协议 1.1 TCP/IP 五层模型概述 链路层(Link Layer) 包括网卡驱动、以太网、Wi‑Fi、PPP 等。负责…...
