你是否还在为学校天天发的问卷调查而苦恼?
你是否还在为天天填写朋友的问卷调查而苦恼?
你是否还在为没人帮你填写问卷调查而苦恼?
废话不多说,直接上解决方案:
没用用过selenium的小朋友记得先安装配置一下:谷歌浏览器驱动的安装及selenium的安装与使用 - 知乎
防止有人不看参数说明,再写一遍:
url 为问卷地址参数, answers 为答案参数 用列表存放答案,比如如果有3题,第一题多选,第二题单选,第三题多选 [ [1, 2], [2], [2, 3] ] 意思就是第一题选A,B 第二题选B 第三题选B,C select 为模式选择参数,默认为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()
版权归原作者 Mount〆 所有, 如有侵权,请联系我们删除。