受挫项目:使用Selenium自动将数据输入PeopleSoft

2020-06-23 07:12:21

它演示了如何使用Python和Selenium将大量数据输入作业自动化到PeopleSoft中。

它获取所需数据的CSV文件,并自动将其输入PeopleSoft。

如果您有一些艰巨的数据输入任务,我建议您研究一下Selenium以使其自动化。

大约6年来,我不得不使用PeopleSoft做我的部分工作(在大学物理系排课),在这段时间里,我得出的结论是:PeopleSoft是对人类的诅咒。

我甚至不确定PeopleSoft(PS)到底是什么,但对我来说,诅咒是运行我的组织(一所大型大学)的后端数据库上的CRUDing的基于Web的用户界面。我真的为任何使用PS的人感到遗憾(很多人都是这样做的)。你可以在一英里外的屏幕上看到它。紧凑的小字体和小方框散落在屏幕上。没有任何回应的行为,而且它不具诱惑力,速度缓慢,而且没有直觉性。这里的元素没有现代气息(就像靴子一样)。有些盒子太小,装不下他们要装的东西。使用的字体与最初的80x25IBMPC上的字体相似。

咆哮?行!没问题。但PS&39;的人性化设计使其使用起来非常费力。这里有一些例子。

这里有一个盒子,据说可以装五封信,工作日每天一封。不过,它只能容纳四个人:

有时,人们必须专门点击并滚动到其中,以检查是否所有需要的天数都在那里。

有些文本输入框需要以某种格式输入数据,这可以通过在服务器端进行一些简单的表单数据处理来消除。

在本例中,假设我需要在180号楼的101房间放置一个班级。输入180-101怎么样?

好了,终于来了。在我的组织中使用PS的每个人都必须键入额外的空格,并将房间号填零。每个人,每一次。哇。

也许是一件小事,但需要额外的工作和精神上的集中,以确保滴答是正确的。每次都是。

然后是可怕的微调器和对服务器的调用,每个表单条目元素的每个焦点都会改变(=low)。

我发现PS使用起来非常不友好(而且让人精疲力竭)。此外,PS的更改几乎不可能实现,因为它通常由需要多个级别的委员会来批准修复的大型组织使用。

不久前,我曾经说过,只要PS看起来是为机器人编写的,那就让我们为我们找一个来使用它吧!在至少一周的时间里,我一直在考虑将视频对准我的电脑屏幕,并使用OpenCV来控制一台模拟鼠标点击和击键的阿鲁迪诺·莱昂纳多(Arudino Leonardo)输入我的数据。幸运的是,一位做网络开发的朋友曾经给我看过一款名为Selenium的测试工具,所以我决定去看看。它甚至在他们的网站上说,枯燥的基于网络的管理任务也可以(也应该)自动完成……。

是!。为什么不寻找某种类型的自动化来驱动任何PS事务,特别是数据输入呢?

我必须用PS来告诉学校我当地系下学期的日程安排(什么课程、地点、时间、介绍人的名字等),我必须用PS告诉学校有关我当地系下学期的日程安排(什么课程,在哪里,一天中的时间,介绍人的名字,等等)。一旦进入后端数据库,数据就会进入学生注册页面(也是PS的一些派生页面)、工资、学费账单和一些数据可视化工具等。

在内部,当我创建我的系的时间表时,我最终得到了一个CSV文件,其中包含关于我的系即将提供的课程的所有信息。就像这样:

ASTR-101,01,LEC,053-0215,MTWR,03:10 PM,04:00 PM,Y,70,E,LAST 1,First1,emplid1,,ASTR-102,01,01,LEC,,MTWR,Y,120,E,Last2,First2,Emplid2,ASTR-102,02,02,LEC,053-0206,MTWR,04:10 PM,05:Emplid4,,Geol-102,01,01,LEC,,MW,07:40 AM,09:00 AM,Y,120,E,Last 5,First5,emplid5,,Geol-102,02,9999,DIS,180-0233,W,10:10 AM,11:00 AM,Y,30,N,Last 6,First6,emplid6,.。

这通常持续约200行。在这里你可以看到课程、工作日、时间等等。制作这个CSV也是一项很大的工作,但更多的是在计划方面。(我用来做这个规划的遗传算法是另一个话题。)。尽管如此,这是我们的时间表,它必须在规定的截止日期前进入PS,每年四次,每个学期一次。

上一个术语的很大一部分数据在PS中滚动,但是由于通常需要的所有小更改,这种滚动只有很小的用处。还有很多工作要做。此外,PS中的数据视图是不存在的,因此您被迫使用自己的视图。在我的案例中,它用我自己设计的日程安排软件绘制了房间的图形,里面贴着班级。因此,当进入我自己的观点时,与PS保持同步就成了一个大问题。如果我在计划阶段单击将一节课拖到一小时后(可能会无数次将其拖到任意数量的课上),这将如何使其返回PS?

当我第一次开始的时候,我会把我的最终计划打印在纸上,拿出一把尺子来记录,然后把每一行都键入PS。通常是180节左右的曲子。我知道这很疯狂,但在大型(政府)组织中,我认为在一台计算机上打印数据输入另一台计算机是相当常见的。在这样的情况下,根本别无选择(蒂娜?)。

这个存储库显示了我如何使用Python读入我的CSV,并使用Selenium为我将其输入到PS中。同步只需删除PS中的内容并重新输入即可。

Selenium是所有流行的网络浏览器(Chrome、Firefox、Safari)的核心,可以通过软件进行控制。这意味着所有的点击、填充框、下拉菜单和保存按钮等都可以使用软件进行控制。我对它使用Python绑定,不知何故,当我运行Python脚本时,会弹出一个Chrome浏览器,上面写着Chrome正由自动化测试软件控制。";这意味着两件事:1)主机服务器(即PS)不知道发生了什么不正常的事情--它毕竟只是Chrome;2)我不点击或键入任何东西来控制这个浏览器;Python脚本控制它

如果您很好奇,有关硒的文档非常棒。第一个Python示例向您展示了总体规划:

从Selenium导入来自Selenium的Webdriver。网络驱动程序。普通的。由硒进口。网络驱动程序。普通的。密钥从Selenium导入密钥。网络驱动程序。支持。UI从Selenium导入WebDriverWait。网络驱动程序。支持。Expect_Conditions从Selenium导入Presence_of_Element_Location。网络驱动程序。支持使用WebDriver将Expect_Conditions作为EC导入。Chrome(';/path/to/chromedriver';)作为驱动程序:WAIT=WebDriverWait(Driver,10)驱动程序。获取(";https://google.com/";)驱动程序。Find_Element(By.。姓名,#34;Q";)。发送密钥(";奶酪";+密钥。RETURN)FIRST_RESULT=WebDriverWait(Driver,5)。直至(EC.。元素的存在位置((由。css_selector,";h3>;div";)print(first_result。get_attribute(";textContent";)。

随便浏览一下代码,就可以看到页面https://google.com/是如何被请求的。Google的搜索框在底层HTML中的引用方式与Q相同,这是很有名的。您告诉Selenium在Google的主搜索页面(Find_Element)的HTML数据中查找该元素。一旦找到,您就可以通过send_key函数将Selenium类型输入到该元素中,文本奶酪后面跟着Return。换句话说,您让Selenium搜索单词Cheose--您将在自动的Chrome视图中看到这一切的发生,脚本将在您的屏幕上弹出。

考虑到Web上的延迟和一般的随机时间延迟,您不会期望立即加载任何服务器页面,因此您告诉Web驱动程序在超时之前始终等待10秒的结果。您可以随心所欲地处理搜索查询的结果。在本例中,等待HTML片段h3>;div。这将启动Google搜索结果页面上的“显示更多”可点击标签。使用python example.py运行此代码将通过最后一行print(first_result.get_attribute(";textContent";))产生结果,并在您的终端中显示文本Show more。

祝贺您:您刚刚自动执行了Google搜索,并从搜索结果中捞到了一些东西。

让我们更进一步,让Selenium单击“下一步”链接,带我们进入搜索结果的第2页。要做到这一点,您必须仔细搜索搜索页面的html代码,并尝试弄清楚Next链接是如何工作的。

为了提供帮助,我下载了Firefox浏览器的开发者版。它有一个网络检查器,您可以在这里找到:

现在你可以从谷歌主页的HTML代码中窥探一下,看看它的哪个部分在生成搜索框。在这种情况下,它是

<;input class=";gLFyf gsfi";maxlength=";2048";name=";q";type=";text";jsaction=";粘贴:puy29d";aria-autoComplete=";两者";aria-haspopup=";false";autocapalize=";off";autocapital。角色=";combobox";spellcheck=";false";title=";search";value=";aria-label=";search";data-ved=";0ahUKEwjywISjl_XpAhV0HjQIHVhCC1oQ39UDCAY";>;

你可以清楚地看到标签的名字,这与我们上面放入的硒类型奶酪是一样的。

因此,我们可以查找HTML id为pnnext的元素(请参阅<;a id=";pnnext";.>;text?)。并告诉Seleniun通过以下方式点击它。

简而言之,这就是您使用Selenium所做的事情:指示它从Web加载页面,然后在读回变量的页面文本中查找您感兴趣的内容,然后对其执行操作。这意味着填写文本框、点击链接等。

然后,我的计划是使用Selenium让我登录到我的企业,并导航到PS数据输入区域。从那里,我的CSV文件的内容将被读取并键入到PS表单的适当位置。

介绍了Selenium的基础知识之后,我现在将展示如何让Selenium将我的数据键入PS。

我不认为有办法让Selenium接管我可能已经亲手启动的网络浏览器会话。所以我得先登录一下我的企业,不过这没什么,这是为即将发生的事情做的很好的热身。所以我的代码是这样开始的:

从Selenium导入Webdriver导入Selenium。网络驱动程序。支持。UI作为Selenium中的UI。网络驱动程序。普通的。密钥从Selenium导入密钥。网络驱动程序。普通的。由硒进口。网络驱动程序。支持。UI从Selenium导入WebDriverWait。网络驱动程序。支持将Expect_Conditions作为EC从Selenium导入。网络驱动程序。支持。UI导入选择导入时间导入CSV导入sys if len(sys.。argv)!=3:打印";用法:autop username password";exit()username=sys。argv[1]密码=sys。argv[2]开始=时间。Time()Browser=WebDriver。Chrome(';/path/to/chromedriver';)浏览器。GET(';https://my.enterprise.web.address';)句柄0=浏览器。Current_Window_Handle打印句柄0 Fill_in_by_id(';username';,username)时间。睡眠(1)Fill_in_by_id(";password";,password)时间。睡眠(1)

所需的导入位于顶部,然后代码开始。我不想通过用户名和密码进行硬编码,所以我将它们作为命令行参数传递,如下所示。

(我知道,我知道,命令行上的密码。)。接下来,我启动一个计时器(以了解作业运行了多长时间),并打开Chrome的Webdriver(也可以使用Safari、Firefox等驱动程序)。此外,还会有大量的照片提供给stdout,帮助我跟踪正在发生的事情。

因此,我拉入企业登录页面,然后使用名为ill_in_by_id的函数填写我的用户名和密码。这是我编写的一个函数,它将填充用id=标记唯一标识的HTML文本框。如上所述,我使用Firefox开发人员浏览器识别了标记。下面是函数Fill_in_by_id:

首先,我们等待id为#34;的元素出现在页面中,清除它(从字面上讲,删除其中可能包含的任何文本),然后发出所需的字符串(就像输入一样)。在PS中,很重要的一点是模拟文本输入末尾的Tab键按下。花了一段时间才明白,这总是强制文本字段与服务器协调(它会调出一个微调器)。然后暂停0.5秒。是的,在使用Selenium时,要习惯于在Python中投入时间。在这里和那里睡眠()会降低您的脚本速度,这样它就不会超过您可能正在与之交谈的任何相对较慢的服务器。

def wait_for_by_id(Elem_Id):打印";正在等待id";+elem_id try:elm=WebDriverWait(浏览器,10)。直至(EC.。元素的可见性_位置((由。id,elem_id)除外:打印";找不到";+elem_id+";。请点击。";x=raw_input(";完成后按[Return].";)elem=false return(Elem)。

如您所见,我们告诉Web驱动程序等待10秒,直到我们重新加载的网页检测到我们要查找的HTML元素变为可见。使用TRY/EXCEPT结构也包含了一点故障保护。我发现PS在其响应时间上是一个极其反复无常的系统。这个版本的waitforbyid()似乎工作得最好,在PS痉挛的情况下,Exception允许我们恢复/继续长时间的输入运行。

您应该能够根据需要使用此计划登录到您的企业。别忘了找到您的登录按钮,这样Selenium就可以单击它让您登录。我的点击方式是:

我的登录按钮的HTML名称为";_EVENTID_PROCESS。Selenium函数find_element_by_name()将找到此按钮,然后.click()将模拟单击。

一旦进入,您可能需要导航到数据输入区域。对我来说,这需要在我的主要大学门户网站上点击几下(门户网站=90年代的单词)。首先,我需要单击HTML id为tabLink_u21l1s5的链接。因此,如下所示的行:

然而,我发现这在处理PS时是不可靠的。换句话说,有时硒只是坐着,显然找不到与这个id的联系。您可能会遇到这样的麻烦,很可能是因为元素位于不同的IFRAME中。(我一直不太理解Selenium是如何处理IFRAME的。我认为它将HTML实体隔离到每个元素中,这意味着您可以直接查看IFRAME中的元素,除非您显式更改为它。)。

您再次看到对waitforbyid()的调用,它执行.click而不是send_key()。这是进行文本填充和单击Selenium之间的唯一区别。

事实证明,在页面中查找元素的一种更严格的方法是对元素使用一个";XPath&34;。这些是进入DOM对象的逐步路径,以明确指向文档中的HTML元素。在整个工作过程中,我逐渐默认使用xpath,因为它们在查找元素方面似乎更可靠,特别是在广阔的PS HTML丛林中。(PS HTML丛林:在某种程度上,我甚至开始为用于与PS和BTW交互的浏览器感到遗憾:Oracle Interactive Dashboard,提供PS数据视图的Oracle Interactive Dashboard锁定了Selenium IDE插件。)。

似乎xpath通常不受欢迎(比如在StackOverflow上),因为从长远来看,它们的健壮性较差,因为对ps的任何代码更改都会破坏它们的使用。(但我认为PS不会有太大变化。到目前为止,我的xpath已经强健了一年多了。)。

Firefox开发人员将向您展示这样的xpath。只需右键单击代码框中的元素HTML,就可以将XPath复制到元素。

在本例中,结果是//*[@id=";tabLink_u21l1s5";]';。因此,是的,我们编写了这对函数,因为Selenium支持xpath:

def WAIT_FOR_BY_XPath(XPath):打印等待XPath";+XPath尝试:elem=WebDriverWait(浏览器,10)。直至(EC.。元素的可见性_位置((由。XPath,XPath)除外:Print";找不到";+XPath+";。请单击。";x=RAW_INPUT(";完成后按[Return].";)elem=false return(Elem)def click_on_by_xpath(Xpath):elem=wait_for_by_xpath(Xpath)if elem!=false:elem。单击()

第一次点击进入门户。在我们门户中的下一次单击是启动到PS,具有此Xpath/html/body/div/div/div[3]/div/div/div[5]/div[2]/div/div[2]/div/div[3]/div/div[1]/h2[1]/a';,因此我们执行以下操作:

第二次点击实质上将我们带到主要的PS起点,因为它连接到大学门户网站。您可以在某种程度上看到什么是xpath:页面中元素的停靠点谱系。在本例中,查看html,然后查看正文,然后查看一些div,等等。在xpath上有很多教程和视频。我发现这个Youtuber的XPath教程很有帮助。

现在是重要时刻。介绍了硒的一些基础知识后,现在是解决将CSV数据自动键入到PS中的时候了。上面的CSV文件具有描述每列的标题,如下所示:

就排课而言,这些字段需要放入PS中可怕的类条目表单中的各种框和下拉列表中。配置一个类有很多框,所有框都需要填入其中一列中的内容。PS中的字段也分布在多个选项卡上。我们开始吧。

再一次,我使用Firefox开发人员查找了我需要的所有框、下拉菜单和选项卡的xpath或ID。例如,第一个选项卡的id为ICTAB_0。例如,";Class Section";(id=CLASS_TBL_CLASS_SECTION$0";)和";关联的CLASS";(id=CLASS_TBL_SSR_Component$0)框位于我的CSV文件的第2列和第3列。

标签为";Meetings";(id=ICTAB_1)的选项卡历来都是最需要处理的选项卡,因为它包含课程的开始、结束和日期框。手动将数据输入此表单非常困难且容易出错。所有的小细节,没有来自web界面的格式帮助,以及在每个表单元素失去焦点后等待的微调工具(甚至连勾选框!)。这都是诅咒的一部分。

为了将CSV中的整行输入到这些制表符组合等中,名为CSV_Fill()的函数编写为:

def CSV_FILL(文件名,CLASS_PREFIX,CLASS_NUMBER):使用OPEN(文件名)作为CSV_FILE:The_FILE=CSV。_FILE:IF ROW[';CLASS';]中行的DictReader(CSV_FILE,DELIMITER=';,';)。LOWER()==(CLASS_PREFIX+';-';+CLASS_NUMBER)。LOWER():ENTER_CLASS_INFO(ROW[';SECTION_NUMBER';],ROW[';ASSOC_NUMBER';],ROW[';TYPE';],ROW[';ENROLL';],ROW[';PRINT';],ROW[';ROOM';],ROW[';DAYS';],ROW[';START';]。],行[';End';],行[';ECAP';],行[';emplid';],行[';主题';],行[';notenbr';])时间。睡眠(1)单击_on_by_id(';$ICField21$new$0$$0';)时间。睡眠(1)WAIT_FOR_SPINER()时间。睡眠(2)#等待加载新表单。DELETE_EMPTY_CLASS_FORM()#清除它的时间。睡眠(2)

它的工作原理是这样的。假设我想自动填入所有课程前缀为phys的物理类,假设我想填入所有121门编号课程(phys-121是生命科学专业的物理)。我会给CSV_Fill(';Courses.csv&39;,';phys&39;,';121';)打电话。

如您所知,它使用的是Python的CSV阅读器(DictReader),该阅读器能够读取CSV文件,并允许用户按名称引用列,如文件第一行中的列标题所示。IF STA。

..