python自动填写问卷星
参考链接1
参考链接2
用python实现自动填问卷,通过智能验证以及滑动验证
1. 下载浏览器驱动
python自动化填写问卷需要依赖浏览器驱动,这里使用的是谷歌浏览器,所以需要下载chromedriver,且下载的版本要和浏览器版本一致。
- 首先打开谷歌浏览器,点击“帮助”——“关于Google Chrome”,查看浏览器版本。如图:
可以看到谷歌浏览器的版本
查看完版本后打开链接:CNPM Binaries Mirror下载对应系统对应版本的谷歌浏览器驱动。如图:
因为我这里使用的是ubuntu系统故下载linux版本的(其他os同理)
下载完了之后解压
再接下来是配置执行权限:
cd chromedriver_linux64
chmod +x chromedriver
接下来再把它以动到usr/bin
目录下:
sudo mv chromedriver /usr/bin/
测试
接下来进行一个测试。
#coding=utf-8
from selenium import webdriver
from selenium.webdriver.chrome.options import Optionschrome_opt = Options() # 创建参数设置对象.
chrome_opt.add_argument('--headless') # 无界面化.
chrome_opt.add_argument('--disable-gpu') # 配合上面的无界面化.
chrome_opt.add_argument('--window-size=1366,768') # 设置窗口大小, 窗口大小会有影响.
chrome_opt.add_argument("--no-sandbox") #使用沙盒模式运行
# 创建Chrome对象并传入设置信息.
browser = webdriver.Chrome(chrome_options=chrome_opt)
url = "https://www.baidu.com/"
browser.get(url)
print(browser.page_source)
browser.quit()
如果界面里输入了百度首页的html代码就说明成功了。
2. selenium基本配置
selenium本质是通过驱动浏览器,完全模拟浏览器的操作,就像真正的用户在操作一样。这个工具的主要功能包括:测试与浏览器的兼容性——测试你的应用程序看是否能够很好得工作在不同浏览器和操作系统之上。测试系统功能——创建回归测试检验软件功能和用户需求。
selenium库可以通过终端命令pip install selenium
安装。
下面是通用的selenium基本配置
import random # 用于产生随机数
import time # 用于延时
from selenium.webdriver.common.by import By #导入By包进行元素定位
from selenium import webdriver
from selenium.webdriver.chrome.options import Options#实例化一个启动参数对象
chrome_options = Options()#添加启动参数
chrome_options.add_argument('user-agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36"') # 添加请求头
chrome_options.add_argument('--disable-blink-features=AutomationControlled')# 防止被识别
chrome_options.add_experimental_option('excludeSwitches', ['enable-automation']) #设置开发者模式启动chrome_options.add_experimental_option('useAutomationExtension', False) # 关闭selenium对chrome driver的自动控制# chrome_options.maximize_window() # 网页最大化#chrome_options.add_argument('headless') #设置浏览器以无界面方式运行
上面的user-agent
需要根据你自己的操作系统来进行修改,这里我的是linux系统
可以通过以下方法获取这个值
打开谷歌浏览器,打开百度网页(其他网页都可以),然后打开开发者模式(按F12),在百度网页上随便点击一个链接,回到百度那个页面,选择开发者模式中的Network
,滑到最下面就可以看到user-agent
了
3.答题代码
- 设置驱动程序
browser = webdriver.Chrome(options=chrome_options) #设置驱动程序,启动浏览器 (实现以特定参数启动)
browser.execute_cdp_cmd('Page.addScriptToEvaluateOnNewDocument',{'source': 'Object.defineProperty(navigator, "webdriver", {get: () => undefined})'}) #用来执行Chrome开发这个工具命令
- 获取问卷内容
browser.get('https://www.***.**/**/*****.aspx') # 获取问卷信息(此处填问卷链接)
- 单选题
# 问题1的点击 (性别)
randomId = random.randint(1, 2) # 随机点击第一个选项或第二个选项#js实现方式
js = "document.getElementById(\"q1_" + str(randomId) + "\").checked = true"
browser.execute_script(js) #使用js实现点击的效果(调用js方法,同时执行javascript脚本)
js = "document.getElementById(\"q1_" + str(randomId) + "\").click()"
browser.execute_script(js) #使用js实现点击的效果(调用js方法,同时执行javascript脚本)# 延时 太快会被检测是脚本
time.sleep(1)# 问题2 (年龄)
randomId = random.randint(2, 4) # 随机数,5个多选框 随机点击
# js实现方式
js = "document.getElementById(\"q2_" + str(randomId) + "\").checked = true"
browser.execute_script(js)
js = "document.getElementById(\"q2_" + str(randomId) + "\").click()" # 拼接字符串的方式 js找到对应id 点击按钮
browser.execute_script(js)
# 延时
time.sleep(0.1)
- 多选题
# 问题5
randomId = random.randint(1, 3) # 随机数选择(选多少个)for i in range(1, randomId + 1): # 循环 实现多选效果randomId1 = random.randint(1, 6) #随机选择第1到第6个选项之一# 两种js实现方式js = "document.getElementById(\"q5_" + str(randomId1) + "\").checked = true"browser.execute_script(js)js = "document.getElementById(\"q5_" + str(randomId1) + "\").click()"browser.execute_script(js)# 延时
time.sleep(1)
- 填空题
# 问题25#自定义要填的内容
block = ["定义第1个填空","定义第2个填空","定义第3个填空","定义第4个填空","定义第5个填空","定义第6个填空","无"] #在上述内容中随机选择一个填入
randomId = random.randint(0, 5) #(数值下标从0开始)#在题目中随机输入上述内容
browser.find_element_by_id("q25").send_keys(block[randomId]) # 延时
time.sleep(0.1)
4.提交+智能验证+滑块验证
- 提交
首先查看问卷源代码,找到提交按钮在html代码中的位置,并复制“提交”按钮的xpath,如图:
#点击提交
submit = browser.find_element_by_xpath("//*[@id='ctlNext']") #网页源代码的xpath
submit.click() #点击#延时 太快会被检测是脚本
time.sleep(0.5)
- 智能验证
同理,找到确认
、智能验证提示框
在html代码中的位置,并复制对应按钮的xpath,(xpath可能会变,如果下面代码无法使用,则采用上面的方法复制新的xpath代替下面代码中的)
# 模拟点击智能验证按钮
# 先点确认
browser.find_element(By.XPATH,'//*[@id="layui-layer1"]/div[3]/a').click()
time.sleep(1)
# 再点智能验证提示框,进行智能验证
browser.find_element_by_xpath("//div[@id='captcha']").click()
- 滑块验证
from selenium.webdriver import ActionChains
def get_track(distance): # distance为传入的总距离# 移动轨迹track = []# 当前位移current = 0# 计算间隔t = 0.2# 初速度v = 0while current < distance:# 加速度a = 100 + current*random.random()v0 = v# 当前速度v = v0 + a * t# 移动距离# move = v0 * t + 1 / 2 * a * t * tmove = v0 * t + a * t# 当前位移current += move# 加入轨迹track.append(round(move))return track # track列表 返回的是整个滑动条的多个焦点,可以模拟鼠标的缓慢滑动def move_to_gap(driver,slider, tracks): # slider是要移动的滑块,tracks是要传入的移动轨迹ActionChains(driver).click_and_hold(slider).perform()for x in tracks:ActionChains(driver).move_by_offset(xoffset=x, yoffset=0).perform()time.sleep(0.1)ActionChains(driver).release().perform()
上面get_track函数返回的是track列表(其中包含了移动的轨迹),定义当前位移current=0,时间间隔t=0.2,初始速度v=0,接下来通过判断语句,判断当前距离是否小于你所输入的总距离,如果成立,则通过物理的知识,通过加速度a,速度v计算位移,然后将它加到current中。
我改了一下原作者的代码,将加速度的大小随着current大小不规则变化,因为我发现固定加速度会使滑块验证多一个刷新重新验证,随机的加速度来滑动保证每次滑动都不太一样来防止检测出来
move_to_gap函数
①ActionChains(driver).click_and_hold(slider).perform()中
click_and_hold(slider)---点击鼠标左键,不松开,其中slider为需要定位要移动的滑块
(例如huakuai = driver.find_element_by_css_selector('#nc_1_n1z'))
perform()---执行该动作;
②接下来遍历tracks
ActionChains(driver).move_by_offset(xoffset=x, yoffset=0).perform()中move_by_offset(xoffset=x, yoffset=0)---鼠标向右移动x的px
③ActionChains(driver).release().perform()中
release()---释放
在主函数中使用,放在智能验证后面,最后关闭浏览器
try:huakuai = browser.find_element_by_css_selector('#nc_1_n1z')move_to_gap(browser,huakuai, get_track(328))time.sleep(2)
except:pass
finally:browser.quit() # 关闭浏览器
5. 完整代码示例
具体问卷还需要自己对应修改
import random # 用于产生随机数
import time # 用于延时
from selenium.webdriver.common.by import By #导入By包进行元素定位
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver import ActionChains
#实例化一个启动参数对象
chrome_options = Options()#添加启动参数
chrome_options.add_argument('user-agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36"') # 添加请求头
chrome_options.add_argument('--disable-blink-features=AutomationControlled')# 防止被识别
chrome_options.add_experimental_option('excludeSwitches', ['enable-automation']) #设置开发者模式启动chrome_options.add_experimental_option('useAutomationExtension', False) # 关闭selenium对chrome driver的自动控制# chrome_options.maximize_window() # 网页最大化#chrome_options.add_argument('headless') #设置浏览器以无界面方式运行
def get_track(distance): # distance为传入的总距离# 移动轨迹track = []# 当前位移current = 0# 计算间隔t = 0.2# 初速度v = 0while current < distance:# 加速度a = 100 + current*random.random()v0 = v# 当前速度v = v0 + a * t# 移动距离# move = v0 * t + 1 / 2 * a * t * tmove = v0 * t + a * t# 当前位移current += move# 加入轨迹track.append(round(move))return track # track列表 返回的是整个滑动条的多个焦点,可以模拟鼠标的缓慢滑动def move_to_gap(driver,slider, tracks): # slider是要移动的滑块,tracks是要传入的移动轨迹ActionChains(driver).click_and_hold(slider).perform()for x in tracks:ActionChains(driver).move_by_offset(xoffset=x, yoffset=0).perform()time.sleep(0.1)ActionChains(driver).release().perform()num = 120
man = int(num*0.06)
woman = num - man
for epoch in range(num):browser = webdriver.Chrome(options=chrome_options) #设置驱动程序,启动浏览器 (实现以特定参数启动)browser.execute_cdp_cmd('Page.addScriptToEvaluateOnNewDocument',{'source': 'Object.defineProperty(navigator, "webdriver", {get: () => undefined})'}) #用来执行Chrome开发这个工具命令browser.get('https://www.wjx.cn/xx/xxx.aspx') # 获取问卷信息(此处填问卷链接)# 问题1的点击 (性别)if man>0 and woman>0:sex = random.randint(1, 2) # 随机点击第一个选项或第二个选项if sex == 1:man -= 1else:woman -= 1elif man>0 and woman==0:sex = 1man -= 1elif man==0 and woman>0:sex = 2woman -= 1else:break#js实现方式js = "document.getElementById(\"q1_" + str(sex) + "\").checked = true"browser.execute_script(js) #使用js实现点击的效果(调用js方法,同时执行javascript脚本)js = "document.getElementById(\"q1_" + str(sex) + "\").click()"browser.execute_script(js) #使用js实现点击的效果(调用js方法,同时执行javascript脚本)# 延时 太快会被检测是脚本time.sleep(1)# 问题2 (年龄)if sex == 1:seq = [2, 3]weights = [0.7,0.3]elif sex == 2:seq = [1, 2, 3, 4, 5]weights = [0.35,0.45,0.1,0.09,0.01]age = random.choices(seq,weights)[0]# js实现方式js = "document.getElementById(\"q2_" + str(age) + "\").checked = true"browser.execute_script(js)js = "document.getElementById(\"q2_" + str(age) + "\").click()" # 拼接字符串的方式 js找到对应id 点击按钮browser.execute_script(js)# 延时time.sleep(0.1)# 问题3 教龄if age == 1:teachyear = 1elif age == 2:teachyear = random.randint(1,2)elif age == 3:teachyear = random.randint(2,4)elif age == 4:teachyear = random.randint(3,4)elif age == 5:teachyear = 4# js实现方式js = "document.getElementById(\"q3_" + str(teachyear) + "\").checked = true"browser.execute_script(js)js = "document.getElementById(\"q3_" + str(teachyear) + "\").click()" # 拼接字符串的方式 js找到对应id 点击按钮browser.execute_script(js)# 延时time.sleep(0.1)# 问题3 学历if age == 1 or 2:seq = [2,3,4]weights = [0.4,0.5,0.1]edu = random.choices(seq,weights)[0]elif age == 3 or 4:seq = [3, 4]weights = [0.2,0.8]edu = random.choices(seq,weights)[0]elif age == 5:edu = 4# js实现方式js = "document.getElementById(\"q4_" + str(edu) + "\").checked = true"browser.execute_script(js)js = "document.getElementById(\"q4_" + str(edu) + "\").click()" # 拼接字符串的方式 js找到对应id 点击按钮browser.execute_script(js)# 延时time.sleep(0.1)# 问题3 婚育if age == 1:seq = [2,3]weights = [0.15,0.85]marry = random.choices(seq,weights)[0]elif age == 2:seq = [1,2,3]weights = [0.4,0.35,0.25]marry = random.choices(seq,weights)[0]elif age == 3 or 4:seq = [1,2,3]weights = [0.9,0.09,0.01]marry = random.choices(seq,weights)[0]elif age == 5:marry = 1# js实现方式js = "document.getElementById(\"q5_" + str(marry) + "\").checked = true"browser.execute_script(js)js = "document.getElementById(\"q5_" + str(marry) + "\").click()" # 拼接字符串的方式 js找到对应id 点击按钮browser.execute_script(js)# 延时time.sleep(0.1)for i in range(6,32):if i == 8:if edu == 2:seq = [2,3,4]weights = [0.4,0.35,0.15]else:seq = [2,3,4,5]weights = [0.1,0.25,0.4,0.25]elif i == 21:if teachyear in [3,4]:seq = [2,3,4,5]weights = [0.1,0.2,0.3,0.4]elif teachyear == 2:seq = [1,2,3,4,5]weights = [0.1,0.2,0.5,0.2,0.1]else:seq = [1,2,3,4,5]weights = [0.4,0.3,0.2,0.07,0.03]elif teachyear in [3,4]:seq = [1,2,3,4]weights = [0.1,0.45,0.35,0.1]elif teachyear == 2:seq = [2,3,4,5]weights = [0.1,0.35,0.45,0.1]elif teachyear == 1:seq = [3,4,5]weights = [0.25,0.4,0.35]pressure = random.choices(seq,weights)[0]# js实现方式js = "document.getElementById(\"q"+str(i)+"_" + str(pressure) + "\").checked = true"browser.execute_script(js)js = "document.getElementById(\"q"+str(i)+"_" + str(pressure) + "\").click()" # 拼接字符串的方式 js找到对应id 点击按钮browser.execute_script(js)# 延时time.sleep(0.1)for i in range(32,42):seq = [2,3,4,5]weights = [0.05,0.15,0.5,0.3]pressure = random.choices(seq,weights)[0]# js实现方式js = "document.getElementById(\"q"+str(i)+"_" + str(pressure) + "\").checked = true"browser.execute_script(js)js = "document.getElementById(\"q"+str(i)+"_" + str(pressure) + "\").click()" # 拼接字符串的方式 js找到对应id 点击按钮browser.execute_script(js)# 延时time.sleep(0.1)#点击提交submit = browser.find_element_by_xpath("//*[@id='ctlNext']") #网页源代码的xpathsubmit.click() #点击#延时 太快会被检测是脚本time.sleep(0.5)# 模拟点击智能验证按钮# 先点确认browser.find_element(By.XPATH,'//*[@id="layui-layer1"]/div[3]/a').click()time.sleep(1)# 再点智能验证提示框,进行智能验证browser.find_element_by_xpath("//div[@id='captcha']").click()time.sleep(4)try:huakuai = browser.find_element_by_css_selector('#nc_1_n1z')move_to_gap(browser,huakuai, get_track(328))time.sleep(2)except:passfinally:print("No.{} Finished".format(epoch))print("man has {}, woman has {}".format(man,woman))browser.quit()