天天看点

element ui select 自动向上向下弹出_[selenium]用Selenium自动填问卷星的问卷

element ui select 自动向上向下弹出_[selenium]用Selenium自动填问卷星的问卷

不知道你家单位是怎么让各位职工上报自己体温的,总之我现在好像一天要报3次这样的感觉,比如这个东西,一天要填1次。每次填报的内容都是一样样的(除了体温以外),但是不能不填,填错了还不好办,怎么办呢?能不能就比较简单的运行一个代码就搞定呢?

路人乙小明:genecards是个好东西,但是如果要能用python访问的话就更好了​zhuanlan.zhihu.com

element ui select 自动向上向下弹出_[selenium]用Selenium自动填问卷星的问卷

之前这篇里面试用了一下selenium,当时拿到page_source以后剩下的事情就全交给beautiful soup了。这一次不是简单的获取页面数据,而是要往上面填东西,所以要更多的依靠selenium。selenium本身不是python的库,但是有python的接口,而python接口的文档在这里。

如何用webdriver打开chrome,如何载入页面这里就不赘述了,最后反正会给出github repo的。这篇文章对应的代码是

health_report.py

,chrome载入的option写在了

selenium_setting.py

里面。和个人有关的一些信息写在了

personal_info.yaml

里面,这个yaml没有传上repo,自己写一个倒也简单

name: xxxx
fosu_id: xxxx
           

目前就先只涉及了这两个个人信息而已。

health_report.py

,

selenium_setting.py

personal_info.yaml

都放在同一个文件夹中。

具体到这个报平安的表,如果做一下分析可以看出来有4种问题:

  1. 最简单的,文本填空题

这种很容易做,就使用selenium的

send_keys

就能搞定

def text_question_fill(question_id,text2input):
    question_ele = driver.find_element_by_id(question_id)
    question_ele.clear()
    question_ele.send_keys(text2input)
           

其中question_id就是题目的id,比如第一题填写姓名,右键点输入框然后选检查,就能看到对应的input元素的id是q1,这个作为函数的第一个参数,自己的姓名作为第二个参数,这个调用就完成了

2. 稍微麻烦一点的,选项题

这种题目的html一般是下面这样的:

<select name="q5" id="q5">
  <option value="-2">请选择</option>
  <option value="18">修复种植科</option>
  <option value="4">医务科</option>
  ...
</select>
           

对于这种组件,当然首先你要弄清楚你要选的那个项目它的value是什么,比如你是修复种植的,那你就找value=18这一项。然后,你需要selenium的Select support。在导入了Select这个类以后,先要实例化,实例化的时候将q5这个问题对应的元素作为参数传入,然后你就做了一个Select的实例,然后对这个实例使用方法

select_by_value

就能选择选项了

selector_q3 = Select(driver.find_element_by_id('q3'))
selector_q3.select_by_value('7')
           

2020-4-16 更新

最近问卷星更新了一下,原来的select标签停用了,改用了div组的形式,用jquery动态更新页面,总之就很噩梦就是了。对于这类情况,selenium有一个Actionchains类可以协助解决。比如对于第三题,虽然现在没法使用select support直接选value=3的项目,但是我可以移动到第三题,点击第三题,按三次方向键下,然后再按回车呀,结果是一样的呀~~

action_1 = ActionChains(driver)
ele_q3 = driver.find_element_by_id('select2-q3-container')
action_1.move_to_element(ele_q3)
action_1.click(ele_q3)
action_1.key_down(Keys.DOWN)
action_1.key_down(Keys.DOWN)
action_1.key_down(Keys.DOWN)
action_1.key_down(Keys.ENTER)
action_1.perform()
           

超简单粗暴……才怪啊!!!!

我发现问卷星这个选项的排序tm居然不是固定的,不是固定的!!!!!!!!

好吧,这样一来我们就需要按一次下,再按一次回车,然后让selenium看一下我们选对了没有

所以把上面的代码做成一个函数,然后递归调用:

def select_actionchain(element,select_val:str):
    action = ActionChains(driver)
    action.move_to_element(element)
    action.click(element)
    action.key_down(Keys.DOWN)
    action.key_down(Keys.ENTER)
    action.perform()
    if element.text==select_val:
        pass
    else:
        select_actionchain(element,select_val)

ele = driver.find_element_by_id('select2-q3-container')
select_actionchain(ele,'行政后勤')

ele2 = driver.find_element_by_id('select2-q5-container')
select_actionchain(ele2,'科研科')
           

来呀,来快活呀,让我看看你还能搞出什么幺蛾子,来呀!!!

3. 还要复杂一些的,日期选择题

element ui select 自动向上向下弹出_[selenium]用Selenium自动填问卷星的问卷

点输入框以后会弹出这个日期选择框,然后点“今天”就可以完成这道题的操作。关键是怎么教电脑去做这个事情。原本我觉得先给日期输入框发送一个click,然后再等个半秒总该弹出来日期选择框了,之后再给今天这个按钮发送click就好了。两个元素都能依靠id找到,所以并不难,才对。

不过这里有个问题,日期选择框是包在iframe里面的。iframe相当于另外一套网页,从主网页这里是搜不到里面的内容的。所以要用到selenium的

switch_to

q4 = driver.find_element_by_id('q4')
q4.click()
time.sleep(1)

#frame switch
driver.switch_to.frame(driver.find_element_by_id('div__calendarIframe'))
#click today
driver.find_element_by_id('selectTodayButton').click()
driver.switch_to.default_content()
           

4. 第四种,最麻烦的,没有id可以找

element ui select 自动向上向下弹出_[selenium]用Selenium自动填问卷星的问卷

比如我是想选择第一项,无,但是看一下html的代码就知道会比较麻烦:

<div class="ui-checkbox">
  <span class="jqcheckwrapper">
    <input type="checkbox" value="1" id="q7_1" name="q7" style="display:none;">
    <a class="jqcheck" href="javascript:;" target="_blank" rel="external nofollow" ></a>
  </span>
  <div class="label" for="q7_1">无</div>
</div>
           

这是一个选项所对应的html代码,我们需要点击的是那个

<a>

元素,这东西不大好找,照理说可以用xpath或者css selector写出来,但是我用的是另外一种方式:

def click_one_div(question_div_id:str, click_index:int, content_should_be='无'):
    check_boxes = driver.find_element_by_id(question_div_id).find_elements_by_class_name('ui-checkbox')
    click_one = check_boxes[click_index]
    print(click_one.find_element_by_class_name('label'))
    assert click_one.find_element_by_class_name('label').text == content_should_be, f"提供的click_index:{click_index}不正确"
    click_one.find_element_by_class_name('jqcheck').click()
           

这个函数第一个参数是问题的id,和其他的问题一样,这种多选题也是有id的。第二个参数是需要点击的选项的次序。比如说我要点第一个,次序就是0,第二个,次序就是1,最后一个次序就是-1,就是按照python list写index的方式写就是了。然后第三个参数是用来做校验的,将选项文本和校验文本比对,费事点错了。

就是这样,四种问题,四种应对方式,repo地址在下面:

beneon/selenium_little_script​github.com

祝君,身体健康