引言
该问卷使用python
+selenium
自动化填写,问卷设置覆盖多种 网页格式,包括
1、文本框输入按钮 2、多选按钮(隐藏与未隐藏) 3、单选按钮(隐藏与未隐藏) 4、提交按钮 5、表格按钮 6、弹窗管理 7、浏览器返回与前进 8、管理cookies
9、等待元素加载(javascript
) 10、网页翻页操作
点击试填问卷,F12
或单击鼠标右键->检查
查看网页源码:
![c100a49755b47e48a13adc089bd8ec06.png](https://i-blog.csdnimg.cn/blog_migrate/c1bbf9f48a61ac7178443b41488be2c8.jpeg)
定位元素
- 点击右上角箭头然后将鼠标悬停在左面网页,即可在网页源码定位该元素。
![246ee4f3f823564f0dfa897e6c75e2f9.png](https://i-blog.csdnimg.cn/blog_migrate/727b50eafb24545bb28ab7ca5088ee18.jpeg)
-
- 题号1的源码
<textarea title="" style="overflow: auto;width:62%;height:22px;"
class="inputtext" value="" id="q1" name="q1"></textarea>
通读源码:id
= 'q1'name
= 'q1'tag_name
= 'textarea'xpath
= '/html/body/div[2]/div[1]/div[2]/div[1]/div/div[1]/div[2]/div[2]/fieldset[1]/div[1]/div[2]/textarea'
-
- 查看题号1的相对/完整路径
![357ac7e81b18dd6207d4cb5d2a014bf3.png](https://i-blog.csdnimg.cn/blog_migrate/7cbbaca5695e96ddd90f5ec61f6b69c3.jpeg)
填写题号1输入框
from selenium import webdriver
driver = webdriver.Chrome() # 配置Google浏览器
driver.get('https://www.wjx.cn/jq/72329412.aspx') # 打开网页
输入数据前清除文本框内容
driver.find_element_by_id('q1').clear()
通过
id
找到该元素,填写内容
driver.find_element_by_id('q1').send_keys(u'把学的写出来')
注意:id
在网页中一般为排他性命名,可以放心使用。
通过name
找到该元素,填写内容
driver.find_element_by_name('q1').send_keys(u'把学的写出来')
通过
tag_name
找到该元素,填写内容
driver.find_element_by_tag_name('textarea').send_keys(u'把学的写出来')
说明:
这种方式比较危险,tag_name
网页源码中存在重名现象,因此不建议使用该种方式
通过xpath
找到该元素,填写内容
driver.find_element_by_xpath('/html/body/div[2]/div[1]/div[2]/div[1]/div/div[1]/div[2]/div[2]/fieldset[1]/div[1]/div[2]/textarea').send_keys(u'把学的写出来')
- 说明:
- 可输入相对路径或绝对路径,在这里输入绝对路径;
send_keys
表示:在输入框中填写内容- 为节省篇幅,都将使用
id
标记题号进行填写;
题号2选择
分析:
题号2 是一个单选题,因此只需要模拟鼠标左键单击对应选项即可。
<li style="width: 49%;">
<a href="javascript:" class="jqRadio jqChecked" rel="q2_1"></a>
<input style="display:none;" type="radio" name="q2" id="q2_1" value="1">
<label for="q2_1">A 男</label>
</li>
说明:
![aca9077fe1b21521bf37d66d974bd44e.png](https://i-blog.csdnimg.cn/blog_migrate/83e5f521ba04cc1705b4f199aa9cc2b8.png)
题号2做了 表单增强,当鼠标悬停在 A男选项时,只要在 红框内都可以选中,而不需要将鼠标精确点击在 圆圈。
因此,以下xpath
都可以使用:
<a href="javascript:" class="jqRadio jqChecked" rel="q2_1"></a>地址
'/html/body/div[2]/div[1]/div[2]/div[1]/div/div[1]/div[2]/div[2]/fieldset[1]/div[2]/div[2]/ul[1]/li[1]/a'
<label for="q2_1">A 男</label>地址
'/html/body/div[2]/div[1]/div[2]/div[1]/div/div[1]/div[2]/div[2]/fieldset[1]/div[2]/div[2]/ul[1]/li[1]/label'
点击:
driver.find_element_by_xpath('/html/body/div[2]/div[1]/div[2]/div[1]/div/div[1]/div[2]/div[2]/fieldset[1]/div[2]/div[2]/ul[1]/li[1]/label').click()
代码:
driver.find_element_by_id('q2_1').click()
题号3选择
# 这是一个表格
<td align="center" style="border-bottom: 1px solid rgb(239, 239, 239); cursor: pointer;">
<a href="javascript:" class="jqCheckbox" style="position:static;"></a>
<input style="display:none;" type="checkbox" value="1" name="q3_0">
</td>
![dd943dcbd1a4a6d5ac3634279412470d.png](https://i-blog.csdnimg.cn/blog_migrate/5694d5b14142c548c395a2918849fee9.jpeg)
有两种方法可以选择:
- 使用网页源码
# num 为上图阿拉伯数字选项:1、2、3、4,和使用矩阵一样
t3_element = 'document.getElementsByName("q3_0")['+ num +'].click()'driver.execute_script(t3_element)
- 使用绝对路径
driver.find_element_by_xpath('/html/body/div[2]/div[1]/div[2]/div[1]/div/div[1]/div[2]/div[2]/fieldset[1]/div[3]/div[2]/table/tbody/tr[1]/td[1]/a').click()
题号4选择
可直接填写后面的输入框,系统会自动补全前面的选项;
推荐使用全路径;
翻页
两种方法
- 模拟鼠标单击
<input type="button" value="下一页" id="btnNext" onclick="show_next_page();" class="finish cancle" style="height:30px;">
-
- 代码
driver.fing_element_by_id('btnNext').click()
- 使用selenium封装操作
- 待续
题号5选择
同上
题号7选择
下拉选项卡
两种方法:
- 遍历:使用
driver.find_element_by_*
时,如果查找到多个元素,会返回一个列表
driver.find_element_by_xpath('//*[@id="q7"]')
# driver.find_element_by_xpath('//*[@name="q7"]')
# 这里使用了相对路径,在找到的元素`id`为`q7`的子元素中
#查找名字为`option`的子孙元素
all_options = element.find_elements_by_tag_name("option")
# 开始遍历
for option in all_options:
if option.get_attribute('value') == '教育/培训/科研/院校':
option.click()
- 使用
webDriver
提供的Select
类- 源码
<select id="q7" name="q7">
<option value="-2">请选择</option>
<option selected="selected" value="1">IT/软硬件服务/电子商务/因特网运营</option>
<option value="2">快速消费品(食品/饮料/化妆品)</option><option value="3">批发/零售</option>
<option value="4">服装/纺织/皮革</option><option value="5">家具/工艺品/玩具</option>
<option value="6">教育/培训/科研/院校</option><option value="7">家电</option>
......
</select>
-
- 代码
from selenium.webdriver.support.ui import Select
select = Select(driver.find_element_by_name('q7'))
# select.select_by_index(index) # 根据索引选择,上述源码未给出index
select.select_by_visible_text("教育/培训/科研/院校") # 根据内容选择
select.select_by_value(6) # 根据value来选择
-
-
- 扩展
-
Select选择器很有用,介绍其他方法
select.deselect_all() # 取消所有选择
.options # 查看所有选项
.all_selected_options # 查看所有已选
题号6选择
题号6含有 网页内嵌,因此处理这种事情比较麻烦。
![58490e82e2d873a61483c8ce663c2cd6.png](https://i-blog.csdnimg.cn/blog_migrate/26563e7a783d51c945fd09360fa5bfd8.jpeg)
可以看到题目6本质上还是下拉选项卡,只是各选项卡之间有某种逻辑关系。
当点击题目6时,原网页将我们引导到另一个网页(<iframe
标签),而另一个网页是内嵌在原网页中的,但是网页元素是分离的,所以当我们要操作另一个网页的元素时需要转到该网页,操作完必须要转回原网页。
#定位到iframe
iframe=driver.find_element_by_id("PDF_i_chezchenz")
#切换到iframe
driver.switch_to.frame(iframe)
select2 = Select(driver.find_element_by_xpath('//*[@id="divDDl"]/div[1]/select'))
select2.select_by_value('华南地区')
select3 = Select(driver.find_element_by_xpath('//*[@id="divDDl"]/div[2]/select'))
select3.select_by_value('广东省')
select4 = Select(driver.find_element_by_xpath('//*[@id="divDDl"]/div[3]/select'))
select4.select_by_value('广州市')
select5 = Select(driver.find_element_by_xpath('//*[@id="divDDl"]/div[4]/select'))
select5.select_by_visible_text('白云区')
# 提交按钮 -> 确定
driver.find_element_by_xpath('//*[@id="form1"]/div[3]/div[2]/input').click()
# 转回原网页
driver.switch_to.default_content()
# 提交
driver.find_element_by_xpath('//*[@id="submit_button"]').click()
# 关闭当前页面
driver.close()
# 关闭浏览器
driver.quit()
完整代码
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import Select, WebDriverWait
# 前台开启浏览器模式
def openChrome():
# 加启动配置
option = webdriver.ChromeOptions()
option.add_argument('disable-infobars')
# 打开chrome浏览器
driver = webdriver.Chrome(chrome_options=option)
return driver
# 授权操作
def operationAuth(driver):
url = "https://www.wjx.cn/jq/72329412.aspx"
driver.get(url)
# 找到输入框并输入查询内容
driver.find_element_by_tag_name('textarea').send_keys(u'把学的写出来')
driver.find_element_by_xpath('/html/body/div[2]/div[1]/div[2]/'
'div[1]/div/div[1]/div[2]/div[2]/fieldset[1]/div[2]/div[2]/ul[1]/li[1]/label').click()
driver.find_element_by_xpath('/html/body/div[2]/div[1]/div[2]/div[1]/div/div[1]/div[2]/'
'div[2]/fieldset[1]/div[3]/div[2]/table/tbody/tr[1]/td[1]/a').click()
driver.find_element_by_xpath('/html/body/div[2]/div[1]/div[2]/div[1]/div/div[1]/div[2]/'
'div[2]/fieldset[1]/div[3]/div[2]/table/tbody/tr[1]/td[2]/a').click()
driver.find_element_by_xpath('/html/body/div[2]/div[1]/div[2]/div[1]/div/div[1]/div[2]/'
'div[2]/fieldset[1]/div[3]/div[2]/table/tbody/tr[1]/td[3]/a').click()
driver.find_element_by_xpath('//*[@id="divquestion3"]/table/tbody/tr[2]/td[1]/a').click()
driver.find_element_by_xpath('//*[@id="divquestion3"]/table/tbody/tr[3]/td[1]/a').click()
driver.find_element_by_xpath('//*[@id="divquestion4"]/ul/li[1]/input[2]').click()
driver.find_element_by_xpath('//*[@id="btnNext"]').click()
driver.find_element_by_xpath('//*[@id="divquestion5"]/ul/li[1]/a').click()
driver.find_element_by_xpath('//*[@id="divquestion5"]/ul/li[2]/a').click()
driver.find_element_by_xpath('//*[@id="divquestion5"]/ul/li[3]/a').click()
# question 7
select = Select(driver.find_element_by_id('q7'))
# select.select_by_index(1)
select.select_by_value('6')
driver.find_element_by_xpath('//*[@id="q6"]').click()
# driver.switch_to.frame(driver.find_elements_by_tag_name("iframe")[0])
driver.switch_to.frame('PDF_i_chezchenz')
select2 = Select(driver.find_element_by_xpath('//*[@id="divDDl"]/div[1]/select'))
select2.select_by_value('华南地区')
select3 = Select(driver.find_element_by_xpath('//*[@id="divDDl"]/div[2]/select'))
select3.select_by_value('广东省')
select4 = Select(driver.find_element_by_xpath('//*[@id="divDDl"]/div[3]/select'))
select4.select_by_value('广州市')
select5 = Select(driver.find_element_by_xpath('//*[@id="divDDl"]/div[4]/select'))
select5.select_by_visible_text('白云区')
driver.find_element_by_xpath('//*[@id="form1"]/div[3]/div[2]/input').click()
driver.switch_to.default_content()
# driver.switch_to.parent_frame()
driver.find_element_by_xpath('/html/body/div[2]/div[1]/div[2]/div[1]/div/div[1]/div[2]/div[4]/table/tbody/tr/td[1]/input').click()
driver.close()
if __name__ == "__main__":
driver = openChrome()
operationAuth(driver)
页面前进和后退
driver.forward()
driver.back()
页面等待网页元素刷新
大多数情况下不会出现这种现象,主要是由于网站是异步开发,也就是说网站上的资源不是在我们访问网页的时候就全部加载完毕的,而是先将基础的数据加载,以达到快速响应,然后在慢慢的加载某些资源,而我们是哟个
selenium
访问网络资源太快,王爷资源又没加载出来,会导致程序崩溃,我们需要等一下程序加载。
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
driver = webdriver.Chrome() driver.get("http://somedomain/url_that_delays_loading")
try:
# 等待元素加载完成,出现在网页内
element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "myDynamicElement")) )
finally:
driver.quit()
程序默认会在 10s时间内,每隔 500ms 调用一次来查看元素是否已经生成,如果本来元素就是存在的,那么会立即返回。
from selenium.webdriver.support import expected_conditions as EC
wait = WebDriverWait(driver, 10)
# 等待元素可被点击
element = wait.until(EC.element_to_be_clickable((By.ID,'someid')))
元素选取
selenium提供了另外的方式来查找元素
from selenium.webdriver.common.by import By driver.find_element(By.XPATH, '//button[text()="Some text"]') .find_elements(By.ID, 'xx') .find_elements(By.NAME, 'xx') .find_elements(By.TAG_NAME, 'xx') .find_elements(By.CLASS_NAME, 'xx') .find_elements(By.CSS_SELECTOR, 'xx') .find_elements(By.LINK_TEXT, 'xx') .find_elements(By.PARTIAL_LINK_TEXT, 'xx')
浏览器窗口转换
如果一个浏览器开了多个网页,可以跳转
# 获取当前的handle名字
handle = driver.current_window_handle
print(f"获取到当前的handle:{handle}" )
# 获取全部的handle
handles = driver.window_handles print(handles)
print(type(handles)) # 结果为list类型
# 切换到最后一个窗口
driver.switch_to_window(handles[-1])
driver.switch_to.window(handles[-1])
# 判断是否切换成功:可根据title判断
print(driver.title)
# 可根据页面唯一元素判断:如特有`id`
# 新页面的元素操作完了,回到第一个页面
driver.close() # 关闭当前窗口
# 转换窗口
driver.switch_to_window(handle) print(driver.title)
参考文档
- 崔庆才博客 -> 爬虫比较厉害
Webdriver
简介 -> WebdriverSelenium with Python
官方文档 -> Selenium with PythonThe Selenium Browser Automation Project
简介 -> The Selenium Browser Automation Project- python+selenium关于等待元素加载的一个坑