当前位置: 首页 > news >正文

学以致用——植物信息录入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数据&#xf…...

什么是压敏电阻

下面的这些都是压敏电阻,常常用在一些电源和信号的浪涌防护电路中。这个是它的电路符号,电路中常用RV表示。当压敏电阻两端电压小于压敏电压时,压敏电阻相当于一个阻值非常大的电阻。当压敏电阻两端电压大于压敏电压时,压敏电阻相…...

Leetcode.901 股票价格跨度

题目链接 Leetcode.901 股票价格跨度 Rating : 1709 题目描述 设计一个算法收集某些股票的每日报价,并返回该股票当日价格的 跨度 。 当日股票价格的 跨度 被定义为股票价格小于或等于今天价格的最大连续日数(从今天开始往回数,…...

vue入门(四)组件基础,$emits简单用法

上一篇&#xff1a;vue入门&#xff08;三&#xff09;事件&#xff08;方法&#xff09;处理、侦听器、模板引用 1.组件最基础的用法&#xff1a; 首先有一个button.vue的组件&#xff0c;里面只画了一个按钮 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配置独立看门狗&#xff08;IWDG&#xff09;前言一、独立看门狗的介绍二、实验过程1.STM32CubeMX配置独立看门狗2.代码实现3.硬件连接4.实验结果总结前言 本章介绍使用STM32CubeMX对独立看门狗定时器进行配置的方法。门狗本质上是一个定时器&#xff0c;提供了更高的安…...

医疗方案 | 星辰天合入选“2022智慧新医信优秀解决方案”

近日&#xff0c;由 HC3i数字医疗网主办的《数字化转型驱动下的医院高质量发展论坛》暨 2022 智慧新医信优秀解决方案发布仪式在线上召开。XSKY星辰天合的“智慧医疗软件定义数据基础设施”解决方案成功入选 2022 智慧新医信优秀解决方案&#xff0c;。此次论坛由 HC3i 数字医疗…...

【系统服务实战】tomcat服务的安装实战

未来要更新的专栏&#xff08;此表格后面会继续完善&#xff09; 专栏系列学习路线完成情况云原生系列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 &#xff08;Super Element Structure Analysis Module&#xff09;是由挪威船级社&#xff08;DNV-GL&#xff09;开发的一款有限元分析&#xff08;FEA&#xff09;系统&#xff0c;它以 GeniE、HydroD 和 DeepC 等模块为核心&#xff0c;主要用于海工结构的强度评估、…...

语言文件操作

&#x1f331;博客主页&#xff1a;大寄一场. &#x1f331;系列专栏&#xff1a;C语言学习笔记 &#x1f618;博客制作不易欢迎各位&#x1f44d;点赞⭐收藏➕关注 目录 前言 C语言中的文件打开和关闭 文件指针 文件的打开和关闭 fclose 文件的顺序读写 fseek ftell …...

Java面试题--熔断和降级的区别

熔断和降级都是系统自我保护的一种机制&#xff0c;但二者又有所不同&#xff0c;它们的区别主要体现在以下几点&#xff1a; 概念不同 触发条件不同 归属关系不同 1.概念不同 1.1熔断概念 “熔断”一词早期来自股票市场。熔断&#xff08;Circuit Breaker&#xff09;也…...

阅读笔记5——深度可分离卷积

一、标准卷积 标准卷积在卷积时&#xff0c;同时考虑了特征图的区域和通道信息。 标准卷积的过程如图1-1所示&#xff0c;假设输入特征图的channel3&#xff0c;则每个卷积核的channel都为3&#xff0c;每个卷积核的3个channel对应提取输入特征图的3个channel的特征&#xff08…...

Microsoft Dynamics 365:导入License到服务层,通过Business Central Administration Shell

本文主要是Microsoft Dynamics 365的License导入的图解干货&#xff0c;不多赘述&#xff0c;直接上图&#xff1a;第一步&#xff1a;准备好的License文件放在你喜欢的目录下第二步&#xff1a;到开始程序里找到并打开 Business Central Administration Shell3.第三步&#xf…...

centos6.10安装FastDfs出错的问题

在centos6.10虚拟机安装dfs文件服务器时&#xff0c;安装报错&#xff0c;报错为&#xff1a; gcc: error trying to exec cc1’: execvp: 没有那个文件或目录 1.ping www.baidu.con 排查网络是否通 2.yum update 排查yum源是否可用 3.yum源地址不可用时&#xff0c;修改yu…...

基础组件之内存池

内存池技术 操作系统在运行进程的过程中&#xff0c;会产生内存碎片&#xff0c;降低了内存的使用率。内存池技术就是为了解决/减少内存碎片的一种方法&#xff0c;内部底层的具体实现根据不同业务场景使用不要的方式&#xff0c;以下是一种好理解的方式&#xff0c;供大家一起…...

前端面试题--了解并简单介绍一下typescript

前端面试题–了解并简单介绍一下typescript TypeScript是JavaScript的超集&#xff0c;具有可选的类型并可以编译为纯JavaScript。 从技术上讲TypeScript就是具有静态类型的 JavaScript 。 向JavaScript添加静态类型的原因是什么&#xff1f;我想原因至少有三个&#xff1a; …...

【pytorch】ModuleList 与 ModuleDict

ModuleList 与 ModuleDict1、ModuleList2、ModuleDict3、总结1、ModuleList 1&#xff09;ModuleList 接收一个子模块的列表作为输入&#xff0c;然后也可以类似 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函数其最大特点&#xff1a;输入值是从SELECT语句的结果集中的一行或多行的“窗口”中获取的。如果函数具有OVER子句&a…...

Go设计模式之函数选项模式

目录引入函数选项模式&#xff08;functional options pattern&#xff09;可选参数默认值接口类型版本引入 假设现在需要定义一个包含多个配置项的结构体&#xff0c;具体定义如下&#xff1a; // DoSomethingOption 定义配置项 type DoSomethingOption struct {// a 配置aa…...

Bubblewrap项目部署实战:从开发环境到Google Play发布的完整流程

Bubblewrap项目部署实战&#xff1a;从开发环境到Google Play发布的完整流程 【免费下载链接】bubblewrap Bubblewrap is a Command Line Interface (CLI) that helps developers to create a Project for an Android application that launches an existing Progressive Web A…...

OpenClaw邮件处理助手:Qwen3-14b_int4_awq分类与自动回复

OpenClaw邮件处理助手&#xff1a;Qwen3-14b_int4_awq分类与自动回复 1. 为什么需要邮件自动化助手 每天早晨打开邮箱&#xff0c;看到堆积如山的未读邮件总是让人头疼。订阅的新闻简报、工作沟通、广告推广混杂在一起&#xff0c;手动分类和回复消耗了大量时间。作为技术从业…...

安装Ubuntu后安装ros一键操作

# ROS安装初始配置完整指南&#xff08;新手必看&#xff09; ## 前言 ROS&#xff08;Robot Operating System&#xff09;是机器人软件开发的主流框架&#xff0c;但对于新手来说&#xff0c;安装配置过程往往充满挑战。本文将详细介绍如何使用小鱼的一键安装脚本快速完成ROS…...

在Vivado里调通3/4删余卷积码Viterbi译码:从分支度量到回溯的完整避坑指南

Vivado平台实现3/4删余卷积码Viterbi译码的工程实践 在数字通信系统中&#xff0c;卷积码因其优异的纠错性能被广泛应用。802.11a等标准中采用的删余卷积码技术&#xff0c;通过有选择地删除部分编码比特来提高码率。本文将深入探讨如何在Vivado平台上实现3/4删余卷积码的Viter…...

2025最权威的十大AI写作网站实测分析

Ai论文网站排名&#xff08;开题报告、文献综述、降aigc率、降重综合对比&#xff09; TOP1. 千笔AI TOP2. aipasspaper TOP3. 清北论文 TOP4. 豆包 TOP5. kimi TOP6. deepseek 采取以下策略&#xff0c;能降低内容被辨认成AIGC的可能性&#xff1a;其一&#xff0c;谨慎…...

AnimateDiff与Three.js结合:Web端3D文生视频实践

AnimateDiff与Three.js结合&#xff1a;Web端3D文生视频实践 最近在折腾AI视频生成&#xff0c;发现一个挺有意思的事儿&#xff1a;AnimateDiff这类文生视频模型效果越来越好&#xff0c;但生成的东西大多还是“平面”的&#xff0c;想把它放到网页里&#xff0c;特别是做成有…...

赋能智能体大脑:在快马平台中集成AI模型实现高级对话能力

在探索AI辅助开发的过程中&#xff0c;我发现智能体的核心能力很大程度上取决于其"大脑"——也就是背后支撑决策的AI模型。最近在InsCode(快马)平台实践了一个很有意思的项目&#xff1a;如何为智能体集成AI模型来实现高级对话功能。整个过程让我深刻体会到&#xff…...

An-Labeler:AudioLabellerV3 AI 辅助标注工具详解(自研Qt + FFT/模型自动标注)

An-Labeler V3:AudioLabeller AI 辅助标注工具详解(自研Qt + FFT/模型自动标注) Author: Code-keys (qq_37445230) Version: V3 (2026-03) 系列文章: An-Labeler:AudioLabeller 高效音视频标注工具 [AAn-Labeler:AudioLabellerV3 AI 辅助标注工具详解] 一、V3 版本更新概…...

2.4.快速排序——先分区再递归,为什么它平均这么快却可能退化?

2.4.快速排序——先分区再递归&#xff0c;为什么它平均这么快却可能退化&#xff1f; 系列&#xff1a;搜索与排序 | 第 4 篇&#xff0c;共 16 篇 难度&#xff1a;⭐⭐⭐☆☆ 中等 标签&#xff1a;排序 快速排序 分治 随机化 三路快排 上一篇&#xff1a;2.3.插入排序——像…...

做对这三步,拥有一个聪明的智能问数与分析Agent

这两年&#xff0c;智能问数与分析&#xff0c;几乎已经成了 ToB Agent 里最容易出圈的“爆款场景”。原因不难理解。相比很多还停留在演示层、流程层的 AI 应用&#xff0c;智能问数更接近企业管理者最直接的需求&#xff1a;我有问题&#xff0c;系统能不能立刻给我答案&…...