赞
踩
废话不多说,直接上解决方案:
没用用过selenium的小朋友记得先安装配置一下:谷歌浏览器驱动的安装及selenium的安装与使用 - 知乎
防止有人不看参数说明,再写一遍:
url 为问卷地址参数,answers 为答案参数 用列表存放答案,比如如果有3题,第一题多选,第二题单选,第三题多选 [ [1, 2], [2], [2, 3] ] 意思就是第一题选A,B 第二题选B 第三题选B,Cselect 为模式选择参数,默认为2 1: 自主模式,根据自己填写的answer进行填写问卷 2: 随机模式,通过random生成随机数进行填写问卷 flag 为bool类型参数,默认为False 值为True: 无头模式,即不显示浏览器 值为False: 正常模式
注意:由于时间有限,目前我只做了单选和多选这两类选择题的自动填写,后续有时间的话会继续更新其他类型的题;
实现思路都大差不差,大家也可以参考代码自己更新
2023年11月29日 20:51第一次更新
多了如下几种题型:
type=1
type=5
type=6
type=9
2023年12月5日第二次更新
更新了答案参数用法,由列表改为字典,更加人性化,操作更加简单,可以自己选择题目填写答案。
''' url 为问卷地址参数, answers 为答案参数 用字典存放答案,比如如果有3题,第一题多选,第二题填空,第三题单选 { 1: [2, 4], 2: "无建议", 3: 3, } 意思就是第一题选B,D 第二题填无建议 第三题选C select 为模式选择参数,默认为2 1: 自主模式,根据自己填写的answer进行填写问卷 2: 随机模式,通过random生成随机数进行填写问卷 flag 为bool类型参数,默认为False 值为True: 无头模式,即不显示浏览器 值为False: 正常模式 '''当填写问卷提交过快时,会有反爬,这次更新解决了三种反爬:
对话框确认验证 智能检测按钮验证 滑块验证可以根据输入指定填写次数
下面直接上代码:
- import random
- import time
-
- from selenium import webdriver
- from selenium.webdriver.common.by import By
- from selenium.webdriver import ChromeOptions, ActionChains
-
- '''
- url 为问卷地址参数,
- answers 为答案参数
- 用字典存放答案,比如如果有3题,第一题多选,第二题填空,第三题单选
- {
- 1: [2, 4],
- 2: "无建议",
- 3: 3,
- }
- 意思就是第一题选B,D 第二题填无建议 第三题选C
- select 为模式选择参数,默认为2
- 1: 自主模式,根据自己填写的answer进行填写问卷
- 2: 随机模式,通过random生成随机数进行填写问卷
- flag 为bool类型参数,默认为False
- 值为True: 无头模式,即不显示浏览器
- 值为False: 正常模式
- '''
-
-
- class WenJuanXing:
- def __init__(self, url, answers, select=2, flag=False):
- # 初始化变量
- self.driver = None
- self.url = url
- self.answers = answers
- self.select = select
- # 初始化浏览器驱动
- self.options = ChromeOptions()
- self.options.headless = flag
- self.options.add_experimental_option('excludeSwitches', ['enable-automation'])
- self.options.add_experimental_option('useAutomationExtension', False)
-
- def parse(self):
- divs = self.driver.find_elements(By.CSS_SELECTOR, '.field.ui-field-contain') # 拿到所有的问题
- for div in divs:
- div_num = divs.index(div) + 1 # 题号
- div_type = int(div.get_attribute('type')) # 问题类型
-
- if div_type == 1: # 填空题
- question = div.find_element(By.CSS_SELECTOR, 'input')
- if self.select == 1:
- question.send_keys(self.answers[div_num])
- else:
- input_type = question.get_attribute('type')
- if input_type == "text":
- question.send_keys("无建议")
-
- elif input_type == "tel":
- question.send_keys("18")
-
- if div_type == 3: # 单选题
- checks = div.find_elements(By.CSS_SELECTOR, '.ui-radio') # 拿到所有的选项
- if self.select == 1: # 模式1:自主模式
- checks[self.answers[div_num] - 1].click()
- else: # 模式2:随机模式
- check_num = len(checks) # 选项数目
- ans = random.randint(1, check_num) # 随机生成答案
- checks[ans - 1].click()
-
- if div_type == 4: # 多选题
- checks = div.find_elements(By.CSS_SELECTOR, '.ui-checkbox') # 拿到所有选项
- if self.select == 1: # 模式1:自主模式
- for ans in self.answers[div_num]:
- checks[ans - 1].click()
- else: # 模式2:随机模式
- check_num = len(checks) # 选项数目
- num = random.randint(1, check_num) # 随机生成选项数
- ansArr = [] # 随机生成的答案数组
- for i in range(num):
- c = random.randint(1, check_num) # 随机生成答案
- if c not in ansArr:
- ansArr.append(c)
- for ans in ansArr: # 根据随机数组里的答案进行选择
- checks[ans - 1].click()
-
- if div_type == 5:
- lis = div.find_elements(By.CSS_SELECTOR, '.onscore>li')
- if self.select == 1:
- lis[answers[div_num] - 1].click()
- else:
- lis_num = len(lis)
- ans = random.randint(1, lis_num)
- lis[ans - 1].click()
-
- if div_type == 6:
- trs = div.find_elements(By.CSS_SELECTOR, 'tr[tp="d"]')
- for tr in trs:
- tds = tr.find_elements(By.CSS_SELECTOR, 'td>a')
- if self.select == 1:
- tr_index = trs.index(tr)
- tds[self.answers[div_num][tr_index] - 1].click()
- else:
- td_num = len(tds)
- ans = random.randint(1, td_num) # 随机生成答案
- tds[ans - 1].click()
-
- if div_type == 9:
- questions = div.find_elements(By.CSS_SELECTOR, 'input')
- for question in questions:
- if self.select == 1:
- que_index = questions.index(question)
- question.send_keys(self.answers[div_num][que_index])
- else:
- input_type = question.get_attribute('type')
- inputmode = question.get_attribute('inputmode')
- if input_type == "text":
- if inputmode == "decimal":
- min_num = int(question.get_attribute('min'))
- max_num = int(question.get_attribute('max'))
- ans = random.randint(min_num, max_num)
- question.send_keys(ans)
-
- print(f'第{div_num}题已做完')
- self.driver.find_element(By.CSS_SELECTOR, '#ctlNext').click() # 提交
- # 验证
- self.verify()
- print('提交成功')
-
- def verify(self):
- try:
- self.driver.find_element(By.CSS_SELECTOR, '#layui-layer1 .layui-layer-btn0').click()
- time.sleep(1)
- print('点击对话框确认验证')
- except:
- print('没有对话框验证')
- try:
- self.driver.find_element(By.CSS_SELECTOR, '#rectMask').click()
- time.sleep(3)
- print('有智能检测按钮验证')
- except:
- print('没有智能检测按钮验证')
- # 滑块验证
- try:
- slider = self.driver.find_element(By.XPATH, '//*[@id="nc_1__scale_text"]/span')
- if str(slider.text).startswith("请按住滑块"):
- width = slider.size.get('width')
- ActionChains(self.driver).drag_and_drop_by_offset(slider, width, 0).perform()
- print('滑块验证')
- except:
- print('没有滑块验证')
-
- def run(self):
- # 启动浏览器跳转到答题页面
- self.driver = webdriver.Chrome(options=self.options)
- self.driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
- "source": """
- Object.defineProperty(navigator, 'webdriver', {
- get: () => undefined
- })
- """
- })
- self.driver.get(self.url)
- self.driver.implicitly_wait(5)
- self.driver.maximize_window() # 最大化浏览器窗口
- # 做题
- self.parse()
- # 阻塞和关闭
- # time.sleep(1)
- # input()
- self.driver.close()
-
-
- if __name__ == '__main__':
- url = '问卷url'
- answers = {
- 1: [2, 4], # 1
- 2: [2, 5], # 2
- 3: 3, # 3·
- 4: [1, 3, 5], # 4
- 5: [1, 2, 4], # 5
- 6: 2, # 6·
- 7: 3, # 7·
- 8: [4, 5], # 8
- 9: 1, # 9·
- 10: 2, # 10·
- 11: [2, 4, 5], # 11
- 12: [1, 3, 4], # 12
- 13: [1, 4, 5], # 13
- 14: [1, 2, 5], # 14
- 15: 1 # 15·
- }
-
- select = 2
- flag = False
- wenjuan = WenJuanXing(url, answers, select=select, flag=False)
- # wenjuan.run()
- num = int(input('请输入你要提交的次数'))
- for i in range(num):
- print(f'===============第{i+1}次==================')
- wenjuan.run()
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。