目的:
因为Singcell-Signature需要依赖于Rstudio打开shiny的GUI页面(本质上是一个网页),需要人工慢慢一个个选择通路、点击保存,而且每次点击加载需要大概10秒的加载时间,当通路数量很大的时候就需要花费多时间精力
于是我想到我之前用过Selenium框架爬取过淘宝商品信息,应该也可以在这里实现,因为它是一个可以被Chrome浏览器打开的页面
环境说明
- 服务器端:Centos7运行的服务器版本的Rstudio,相应的R包
- 本地端:Win10, VScode和anaconda Python, 相应的包已经安装好,谷歌浏览器相应版本的Chrome webdriver也部署完毕
一、分析页面遇到的难题
问题1:如何点击下拉选项按钮,然后点击下拉菜单框中的元素
解决方案
网上搜到了这篇文章:https://www.jianshu.com/p/028d05308c7c
#导入select类
from selenium.webdriver.support.ui import Select
#获取相应的webElement
x = Select(driver.find_element_by_id("criteriaX"))
y = Select(driver.find_element_by_id("criteriaY"))
x.select_by_visible_text("UMAP_1")
y.select_by_visible_text("UMAP_2")
问题2: 如何遍历并选择所有的下拉框的所有列表选项元素
大概思路:是获得这个选择框列表的所有元素数据,存储到一个列表里面,然后去遍历选择它
后面一个更加简单的方法,获取列表长度,去遍历对应的索引就可以了
解决方案
搜到了这篇:Selenium处理单选项下拉框列表
Select提供了三种选择方法:
select_by_index(index) ——通过选项的顺序,第一个为 0
select_by_value(value) ——通过value属性
select_by_visible_text(text) ——通过选项可见文本
同时,Select提供了四种方法取消选择:
deselect_by_index(index)
deselect_by_value(value)
deselect_by_visible_text(text)
deselect_all()
所以可以分为三个步骤:
- 根据元素位置找出所有选项的列表
- 根据这个列表的长度去循环遍历索引
- 保存图片
完整代码:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Use for get infomation from Single-Cell Signature Viewer by ChromeDriver
# Author:Robin; Created in 20190831
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException #检查网络请求是否超时
from selenium.webdriver.support.ui import Select
from pyquery import PyQuery as pq
import time
import re
#生成WebDriverWait对象
driver = webdriver.Chrome()
driver.get('http://192.168.3.33:8787/p/7661/') # Siganture打开的页面地址
wait = WebDriverWait(driver, 10) #构建WebDriverWait对象,10秒加载时间
#模拟登录
try:
user_id = wait.until(EC.presence_of_element_located((By.XPATH, '//*[@id="username"]'))) #用户名输入框
passwd = wait.until(EC.presence_of_element_located((By.XPATH, '//*[@id="password"]'))) #密码输入框
submit = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#buttonpanel > button > table >tbody > tr > td.inner'))) #页码跳转确定按钮
user_id.clear() #清空
passwd.clear()
user_id.send_keys('XXX') #输入账号
passwd.send_keys('XXX') #输入密码
submit.click() # 点击登录
except:
print('Something wrong in loading!')
# 选择X轴和Y轴
x = Select(driver.find_element_by_id("criteriaX"))
y = Select(driver.find_element_by_id("criteriaY"))
x.select_by_visible_text("UMAP_1")
y.select_by_visible_text("UMAP_2")
# 遍历所有的Singnature, 并且保存图片
###获取select页面元素对象;
z = Select(driver.find_element_by_id('z'))
###获取所有选择项的页面元素对象;
all_options = z.options
###打印选项总数;
print("列表选项总数:",len(all_options))
###遍历所有索引
for i in range(len(all_options)):
print("元素索引:" + str(i))
z.select_by_index(i) #选择索引对应的元素
print(z.options[i].get_attribute("text"))
print(z.options[i].get_attribute("value"))
#判断保存图片的按钮是否可点击
time.sleep(10) #让页面加载完全
SavePNG = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#SavePlot')))
SaveSVG = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#saveSVG')))
#点击保存
SavePNG.click()
SaveSVG.click()
print('保存成功!')
效果展示
改进
- 其实账号密码那里,可以用一个JSON库从外面的文件读入账号密码,避免直接将账号密码暴露在代码中