目的
根据物种的分类位置,将其中文名、拉丁名、异名、分类概述、描述、生境、国内产地、国外产地等信息在线录入到网站中。
整体思路
- 批量读取属级文件夹下所有物种的EXCEL文件,提取以上提到的各类信息
- 登录网站,进入相应的分类等级下,进行网站表单录入。
核心代码实现
1. 读取文件
1.1遍历文件夹并yield EXCEL文件
- 加载os
import os
- 遍历文件夹EXCEL文件
def read_species(folder):
filelist = os.listdir(folder)
for file in filelist:
filepath = os.path.join(folder, filename)
yield filepath
回头看:
- 读取时应直接添加判断是否为EXCEL文件,虽然存在其他类型文件的情况很少见,但一方面为了保证后续文件读取,另一方面包容操作人员的小失误,这是有必要的,也是优雅的。
1.2.提取信息
- 加载pandas
import pandas
- 硬式(按固定行列)提取
def extra_infos(species):
try:
df = pd.read_excel(file=species, sheet_name='物种百科', keep_default_na=False)
except:
df = pd.read_excel(file=species, sheet_name='Sheet1', keep_default_na=False)
ch_name = df.iat[1, 3] #中文名
ld_name = df.iat[0, 3] #拉丁名
des = df.iat[8, 3] # 描述
fenlei = df.iat[2, 3] # 分类概述
suming = df.iat[5, 3] # 异名
guonei = df.iat[15, 3] # 国内分布
guowai = df.iat[16, 3] # 国外分布
shengjing = df.iat[11, 3] # 生境
return [ch_name, ld_name, des, fenlei, suming, guonei, guowai, shengjing]
代码要点:
- 观察数百个文件后,excel文件的第一个sheet名称或是’物种百科’,或是’Sheet1’。通过try…except…解决
- 多数新发表物种没有对应中文名,pandas会默认将空值读取为NaN,添加keep_default_na=False可以将空值读为空字符串,避免了中文名录入字符串’nan’。
踩过的坑:
- 利用pandas读取某个单元格值时,需要使用df.iat[]。
回头看:
- 在处理读取EXCEL文件Sheet时,起先是考虑直接通过索引读取第一个sheet,但实际操作中出现错误,随机采用sheet名称的读取方法。目前只遇到过这两种情况,显然无法应对将来可能出现的例外情况。但,一般而言,新建EXCEL时默认第一个表单名就是Sheet1,换而言之,操作员可以不更改表单名,减少工作量。
- 我选择了提取固定单元格的方式,固然是根据经验选择了最直接、最没有包容性的方式。在项目最后阶段突然出现了一批文件缺少一行,所以还是应该根据行索引和列索引进行判断,其中还存在并不是所有所需信息的判断信息都在索引行,但必然在所需信息前,那么可以选择逐行遍历单元格,获取信息。
2. selenium自动化网站录入
2.1 selenium配置
参考python webdriver调用Chrome浏览器——chromedriver的安装及配置——极简!!
2.2 webdriver启动
- 加载selenium库
from selenium import webdriver # 最基本、最重要的实例实现
from selenium.webdriver.common.by import By # 定位元素/标签的必需
from selenium.webdriver.chrome.service import Service # 调用chormedriver
from selenium.webdriver.support import expected_conditions as EC # 捕捉弹窗
from selenium.webdriver.support.ui import WebDriverWait # 等待加载
代码要点:
- 见上方代码注释,个人认为虽然看起来导入很多很麻烦,但几乎都是自动化测试现在网站所必需的。
- 创建webdrvier实例
options = webdriver.ChromeOptions()
options.add_argument('--ignore-certificate-errors')
options.add_argument('--disable-notifications') # 前三行本是尝试阻止弹窗,但在本项目中无用
s=Service(r"D:\ALL_Softwares\Python 3.10.4\Scripts\chromedriver.exe") # 配置chromedriver
driver = webdriver.Chrome(service=s)
driver.maximize_window() # 最大化窗口--个人习惯
2.3 身份登录
- 自动化输入用户名+密码
driver.get('http://www.cn-flora.ac.cn:28080/plantonline/frame/toLoginPage')
driver.find_element(By.ID, "_loginName").send_keys(user)
driver.find_element(By.ID, "_loginPwd").send_keys(password)
代码要点:
后面基本上都是selenium的基本操作,参考操作详解
回头看:
细心的你应该发现了,我这里没有最后的登录操作,或者说没有点击submit。其实还有第三个输入项就是常见的验证码。该网站的验证码比较简单,是字母数字组合,纯色背景没有干扰,使用智能识别应当是极易解决了。但由于时间紧迫,我的主要精力用于解决后面核心功能上,也就是表单录入,连环坑啊。后续可以添加上。
在这里我利用tkinter调用后面的录入函数,从而允许操作员自行填写验证码,并选择正确的属。
2.4 核心录入代码
- 新增录入页面的自动化操作实现
def gogogo(driver):
folder = r"C:\Users\bailo\Desktop\111"
for species in read_species(folder):
infos = extra_infos(species) # [ch_name, ld_name, des, fenlei, suming, guonei, guowai, shengjing]
# 定位到新建按钮,点击出现录入表单
driver.switch_to.default_content()
n = driver.find_elements(By.TAG_NAME, 'iframe')[1]
driver.switch_to.frame(n)
o = driver.find_elements(By.TAG_NAME, 'frame')[1]
driver.switch_to.frame(o)
p = driver.find_elements(By.TAG_NAME, 'button')
p[2].click()
# 定位到录入表单
driver.switch_to.default_content()
q = driver.find_elements(By.TAG_NAME, 'iframe')
driver.switch_to.frame(q[1])
r = driver.find_elements(By.TAG_NAME, 'frame')[1]
driver.switch_to.frame(r)
if ch_name is not '':
driver.find_element(By.NAME, 'acName').send_keys(u'%s' % infos[0])
else:
driver.find_element(By.NAME, 'acName').send_keys(u'%s' % infos[1])
driver.find_element(By.NAME, 'acKeywords').send_keys(u'%s' % infos[1])
driver.find_element(By.NAME, 'acExtendProperties').send_keys(u'%s' % infos[4])
driver.find_element(By.NAME, 'acRemark').send_keys(u'%s' % infos[3])
driver.switch_to.frame(driver.find_element(By.TAG_NAME, 'iframe'))
driver.find_element(By.TAG_NAME, 'p').send_keys(u'%s' % infos[2])
driver.switch_to.parent_frame()
driver.find_element(By.NAME, 'acKuozhan3').send_keys(u'%s' % infos[5])
driver.find_element(By.NAME, 'acKuozhan4').send_keys(u'%s' % infos[6])
driver.find_element(By.NAME, 'acKuozhan5').send_keys(u'%s' % infos[7])
driver.find_element(By.TAG_NAME, 'button').submit()
wait = WebDriverWait(driver, 10)
wait.until(EC.alert_is_present()) # 等待录入成功弹窗出现
driver.switch_to.alert.accept() # 确定成功
time.sleep(3) # 等待页面刷新
os.remove(filepath) # 防止意外终止后无法区分是否录入,成功后删除EXCEL文件
代码要点:
- 应用selenium最主要的就是定位元素/标签。一般有By.ID,但实践后发现无法定位,并且存在iframe、frameset、frame互相嵌套和并列的情况,我采用了索引定位的方式,效果不错。
3 tkinter调用webdriver与核心录入
3.1 tkinter操作界面
- 加载tkinter
from tkinter import *
回头看:
图形化界面对操作员来说比较友好,代码编写对程序员来说也不算复杂,两全其美的事情。
- 创建实例并调用webdriver
root = Tk()
root.attributes('-topmost', 1) # 保持tkinter界面处于顶层,方便点击操作
go = Button(root, text='Go', command=lambda: gogogo(driver)) # 创建按钮并绑定录入函数
go.grid(row=0)
options = webdriver.ChromeOptions()
options.add_argument('--ignore-certificate-errors')
options.add_argument('--disable-notifications') # 前三行本是尝试阻止弹窗,但在本项目中无用
s=Service(r"D:\ALL_Softwares\Python 3.10.4\Scripts\chromedriver.exe") # 配置chromedriver
driver = webdriver.Chrome(service=s)
driver.maximize_window() # 最大化窗口--个人习惯
driver.get('http://www.cn-flora.ac.cn:28080/plantonline/frame/toLoginPage')
driver.find_element(By.ID, "_loginName").send_keys(user) # 用户名
driver.find_element(By.ID, "_loginPwd").send_keys(password) # 密码
root.mainloop()
代码要点:
- 保持tkinter界面处于顶层,并不影响webdriver自动化操作,方便点击操作。创建Tk()实例后便创建webdriver.Chrome()实例,打开登陆界面,自动输入用户名和密码后,等待操作员输入验证码并登录。进入录入系统后,需操作员手动选择到属级。点击绑定gogogo()的按钮后即可录入数据。
回头看:
-
目前只专注于核心功能的实现,细节上依赖操作员,基本实现了半自动化。属级录入界面的选择、属级录入界面是否存在以及前文提到的验证码问题都是能解决而受限于时间未实现的非核心功能,后续版本可能会涉及数据的修改,应当完成这些功能。
-
这里的图形化界面很简陋,只有点击运行一个按钮。操作员无法获知数据录入进程,数据质量等操作。后续酌情完善,毕竟前面一点提到的功能都实现的话,图形化界面可以说是冗余的,最多用来显示进程。
整体代码
import pandas as pd
from selenium import webdriver
import time
from selenium.webdriver.common.by import By
from tkinter import *
import os
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
def gogogo(driver):
folder = r"C:\Users\bailo\Desktop\111"
for species in read_species(folder):
infos = extra_infos(species) # [ch_name, ld_name, des, fenlei, suming, guonei, guowai, shengjing]
# 定位到新建按钮,点击出现录入表单
driver.switch_to.default_content()
n = driver.find_elements(By.TAG_NAME, 'iframe')[1]
driver.switch_to.frame(n)
o = driver.find_elements(By.TAG_NAME, 'frame')[1]
driver.switch_to.frame(o)
p = driver.find_elements(By.TAG_NAME, 'button')
p[2].click()
# 定位到录入表单
driver.switch_to.default_content()
q = driver.find_elements(By.TAG_NAME, 'iframe')
driver.switch_to.frame(q[1])
r = driver.find_elements(By.TAG_NAME, 'frame')[1]
driver.switch_to.frame(r)
if ch_name is not '':
driver.find_element(By.NAME, 'acName').send_keys(u'%s' % infos[0])
else:
driver.find_element(By.NAME, 'acName').send_keys(u'%s' % infos[1])
driver.find_element(By.NAME, 'acKeywords').send_keys(u'%s' % infos[1])
driver.find_element(By.NAME, 'acExtendProperties').send_keys(u'%s' % infos[4])
driver.find_element(By.NAME, 'acRemark').send_keys(u'%s' % infos[3])
driver.switch_to.frame(driver.find_element(By.TAG_NAME, 'iframe'))
driver.find_element(By.TAG_NAME, 'p').send_keys(u'%s' % infos[2])
driver.switch_to.parent_frame()
driver.find_element(By.NAME, 'acKuozhan3').send_keys(u'%s' % infos[5])
driver.find_element(By.NAME, 'acKuozhan4').send_keys(u'%s' % infos[6])
driver.find_element(By.NAME, 'acKuozhan5').send_keys(u'%s' % infos[7])
driver.find_element(By.TAG_NAME, 'button').submit()
wait = WebDriverWait(driver, 10)
wait.until(EC.alert_is_present()) # 等待录入成功弹窗出现
driver.switch_to.alert.accept() # 确定成功
time.sleep(3) # 等待页面刷新
os.remove(filepath) # 防止意外终止后无法区分是否录入,成功后删除EXCEL文件
def read_species(folder):
filelist = os.listdir(folder)
for file in filelist:
filepath = os.path.join(folder, filename)
yield filepath
def extra_infos(species):
try:
df = pd.read_excel(file=species, sheet_name='物种百科', keep_default_na=False)
except:
df = pd.read_excel(file=species, sheet_name='Sheet1', keep_default_na=False)
ch_name = df.iat[1, 3] #中文名
ld_name = df.iat[0, 3] #拉丁名
des = df.iat[8, 3] # 描述
fenlei = df.iat[2, 3] # 分类概述
suming = df.iat[5, 3] # 异名
guonei = df.iat[15, 3] # 国内分布
guowai = df.iat[16, 3] # 国外分布
shengjing = df.iat[11, 3] # 生境
return [ch_name, ld_name, des, fenlei, suming, guonei, guowai, shengjing]
root = Tk()
root.attributes('-topmost', 1) # 保持tkinter界面处于顶层,方便点击操作
go = Button(root, text='Go', command=lambda: gogogo(driver)) # 创建按钮并绑定录入函数
go.grid(row=0)
options = webdriver.ChromeOptions()
options.add_argument('--ignore-certificate-errors')
options.add_argument('--disable-notifications') # 前三行本是尝试阻止弹窗,但在本项目中无用
s=Service(r"D:\ALL_Softwares\Python 3.10.4\Scripts\chromedriver.exe") # 配置chromedriver
driver = webdriver.Chrome(service=s)
driver.maximize_window() # 最大化窗口--个人习惯
driver.get('http://www.cn-flora.ac.cn:28080/plantonline/frame/toLoginPage')
driver.find_element(By.ID, "_loginName").send_keys(user) # 用户名
driver.find_element(By.ID, "_loginPwd").send_keys(password) # 密码
root.mainloop()
- 完美实现了录入功能,但小瑕疵还很多,尚且不知是否还有后续工作需要处理。
- 验证码自动识别并输入(尚未完成,如若完成,tkinter将负责任务的选择和进程显示)
- 属级录入界面是否存在、存在则选择、不存在则新建(尚未完成,如若完成read_speces()函数将改写为科级、甚至目级)
- 对于物种信息正确性的验证(尚未完成,如要完成,需要在读取数据时就与iplants网站数据比对,这里比较复杂,牵扯很多专业知识,不作详细论述)
- 自动化修改、自动化删除(尚未完成,如若完成,当以删除功能为主,直接清空上次录入数据,并进行重新录入。修改功能实现的目的也差不多。如若实现,新建、修改、录入这三个功能应当绑定在tkinter中,对目标文件夹进行处理)
- tkinter界面完善(尚未完成,应当有三个功能按钮,一个文件夹选择,一个EXCEL文件列表
共勉
学以致用,方能成才。兴趣是最好的老师,实践是最好的课本,一步步地实现自我价值,苦也乐也。文章来源:https://www.toymoban.com/news/detail-687429.html
后面更新将另作他文。文章来源地址https://www.toymoban.com/news/detail-687429.html
到了这里,关于学以致用——植物信息录入(selenium+pandas+os+tkinter)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!