赞
踩
目录
02 fixed_danxuan()→单选题(只选择某个选项)
03 excluded_danxuan()→单选题(排除一个或一些选项)
04 range_danxuan()→单选题(在m到n范围内单选)
05 restrictive_danxuan()→单选题(在某些选项中选择)
06 textinput_danxuan()→单选题(选项中允许填空)
08 fixed_duoxuan()→多选题(只选择某些选项)
09 excluded_duoxuan()→多选题(排除一个或一些选项)
10 restrictive_duoxuan()→多选题(在某些选项中多选)
11 range_duoxuan()→多选题(在m到n范围内的多选)
12 textinput_duoxuan()→多选题(选项中允许填空)
随机所在城市的选择 random_city_selection()
限制所在城市的选择 restrictive_city_selection()
笔者之前也写过python实现问卷星刷份数的代码与文章(如下)
隔壁寝室刷问卷刷疯了https://blog.csdn.net/knighthood2001/article/details/120175929?spm=1001.2014.3001.5502python自动化------问卷星刷问卷3.0版本https://blog.csdn.net/knighthood2001/article/details/120175929?spm=1001.2014.3001.5502
不过之前写的属于面向过程版本,它有很大的局限性,即根据不同的问卷需要按照逻辑步骤写相应的代码,代码量非常繁琐,并且很多代码都是重复的,因此如果后续查看与更改起来也非麻烦;此外,由于距离上一次写关于问卷星的时间较长,问卷星页面元素定位可能发生了更改,需要重新获取相应的元素定位,如xpath、css selector;再加上由于selenium的升级,之前定位元素的方法被弃用,需要改变之前写的代码。
以上三个原因,使得笔者重新对之前的代码进行增删改查,最终将之前的面向过程版本写成了面向对象版本。通过将一个个的功能封装成函数,在使用时只需要调用即可。代码量大大降低,且无需重复造车轮,对于后续检查与更改来说也比较轻松。
首先创建两个python文件,Sojump的翻译就是问卷星,通过在Sojump.py文件中编写主要函数,在具体问卷.py文件中通过导入Sojump,在编写该问卷的代码,最终实现刷份数。
- import random
- from selenium import webdriver
- import time
- from selenium.webdriver.common.by import By
- from selenium.webdriver.support.select import Select
- import random
- import Sojump
- from Sojump import Wenjuanxing
- import schedule as schedule
!这里的内容是重中之重!
①元素定位分析
xpath
//*[@id="divquestion1"]/ul/li[1]
上述表示的是问卷星问卷第一题的第1个选项
//*[@id="divquestion1"]/ul/li[2]
上述表示的是问卷星问卷第一题的第2个选项
经观察,可以得出问卷星问题的通用xpath,如下
- # 选项的xpath
- base_xpaths = '//*[@id="divquestion{}"]/ul/li'
css_selector
大致思路同上,得到问卷星选项的通用css_selector,如下
- # 选项的css_selector
- base_css_selectors = '#divquestion{} > ul > li:nth-child({})'
允许填空选项的css_selector
有些问题的选项允许填空,其通用css_selector 如下
- # 允许填空选项的css_selector
- input_css_selectors = '#divquestion{} > ul > li:nth-child({}) > input.underline'
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!注意:笔者发现问卷星有两类问卷,其对应的元素定位有所不同。
具体区分如下(笔者也是在写完该文章后突然发现,大家可以自行去试试你的问卷元素定位属于哪一类,第二种由于没有相应的问卷,可能xpath和css_selector定位会发生错误,不过这不是重点,大家只需找到并更改即可)
如果大家发现无法刷问卷,可能就是元素定位出现了问题
- '''适用的可能是问卷星网页无法右键,只能通过F12或者
- ctrl+shift+i快捷键进入开发者工具的问卷,并且打开开发者工具后会显示已在调试程序中暂停'''
- # 选项的xpath
- base_xpaths = '//*[@id="divquestion{}"]/ul/li'
- # 选项的css_selector
- base_css_selectors = '#divquestion{} > ul > li:nth-child({})'
- # 允许填空选项的css_selector
- input_css_selectors = '#divquestion{} > ul > li:nth-child({}) > input.underline'
-
- '''适用的可能是除了上面的情况的问卷星'''
- # 选项的xpath
- base_xpaths = '//*[@id="div{}"]/div/div'
- # 选项的css_selector
- base_css_selectors = 'div{} > div.ui-controlgroup.column{} > div.ui-checkbox.checked'
- # 允许填空选项的css_selector
- input_css_selectors = 'tqq{}_{}'
②创建类并初始化
- class Wenjuanxing(object):
- # 初始化
- def __init__(self, url):
- self.url = url
创建一个Wenjuanxing()的类,并初始化url
接下来就开始编写函数了
在类外面先定义一个count=0,然后使用下面的counter()函数,用以计数是第几次运行代码,刷了几次问卷。
- # 计数器
- def counter(self):
- global count
- count += 1
- w = print("第{}次运行".format(count))
- return w
需要进行伪装的原因:笔者发现是因为问卷星的网页有反爬机制,它会检查你是不是通过selenium访问网页的。大多数情况下,检测基本原理是检测当前浏览器窗口下的window.navigator对象是否包含webdriver这个属性。因为在正常使用浏览器的情况下,这个属性是undefined,然而一旦我们使用了selenium,selenium会给window.navigator设置webdriver属性。很多网站就通过JS判断如果webdrive 属性存在,那就直接屏蔽。以下代码可以在每次页面加载之前就不会给window.navigator设置webdriver属性,从而能够通过智能检测。
详情可以看笔者写的之前的文章
隔壁寝室刷问卷刷疯了https://blog.csdn.net/knighthood2001/article/details/120175929?spm=1001.2014.3001.5502
- # 伪装selenium
- def weizhuang_selenium(self):
- # 躲避智能检测
- self.option = webdriver.ChromeOptions()
- self.option.add_experimental_option('excludeSwitches', ['enable-automation'])
- self.option.add_experimental_option('useAutomationExtension', False)
- self.driver = webdriver.Chrome(options=self.option)
- self.driver.execute_cdp_cmd('Page.addScriptToEvaluateOnNewDocument',
- {'source': 'Object.defineProperty(navigator, "webdriver", {get: () => undefined})'})
- self.driver.get(self.url)
chromedriver的知识我就不细说了,主要讲的是selenium更新后,元素定位的方法发生改变。
以前:
模块
from selenium import webdriver
定位元素方法
- # 1、通过ID进行定位
- find_element_by_id('id')
- # 2、通过名字进行定位
- find_element_by_name('name')
- # 3、通过类名进行元素定位
- find_elements_by_class_name('class_name')
- # 4、通过元素标签属性
- find_element_by_tag_name('tag_name')
- # 5、 通过页面文本信息
- find_element_by_link_text('link_text')
- # 6、通过模糊文本信息
- find_element_by_partial_link_text('partial_link_text')
- # 7、通过查找元素路径
- find_element_by_xpath('xpath')
- # 8、通过页面上的css元素进行定位
- find_element_by_css_selector('css_selector')
更新后:
需要在导入一个模块
- from selenium import webdriver
- from selenium.webdriver.common.by import By
定位元素方法
- driver.find_element(by=By.ID, value='ID')
- driver.find_element(by=By.NAME, value='NAME')
- driver.find_element(by=By.CLASS_NAME, value='CLASS_NAME')
- driver.find_element(by=By.TAG_NAME, value='TAG_NAME')
- driver.find_element(by=By.LINK_TEXT, value='LINK_TEXT')
- driver.find_element(by=By.PARTIAL_LINK_TEXT, value='PARTIAL_LINK_TEXT')
- driver.find_element(by=By.XPATH, value='XPATH')
- driver.find_element(by=By.CSS_SELECTOR, value='CSS_SELECTOR')
- # 01 单选题(随机选择)
- def danxuan(self, i):
- global base_xpaths
- base_xpath = base_xpaths.format(i)
- a = self.driver.find_elements(by=By.XPATH, value=base_xpath)
- b = random.randint(1, len(a))
- self.driver.find_element(by=By.CSS_SELECTOR,
- value=base_css_selectors.format(i, b)).click()
讲解:i表示题号
首先使用全局变量并通过format(i)函数给出具体的题号
a表示定位题目所对应的选项
len(a)表示题目所对应的选项个数
b表示随机生成选项个数以内的一个数
最后定位该选项并点击,完成随机选择
- self.driver.find_element(by=By.CSS_SELECTOR,
- value='#divquestion{} > ul > li:nth-child({}) > label'.format(i, b)).click()
注意:在上面的代码,由于笔者在之前的文章中使用过xpath定位,不过出现了定位不到的现象,所以我使用css_selector进行定位元素。
- # 02 单选题(只选择某个选项)
- def fixed_danxuan(self, i, b):
- self.driver.find_element(by=By.CSS_SELECTOR,
- value=base_css_selectors.format(i, b)).click()
讲解:b表示需要选择的选项在该题目选项中的位置
- # 03 单选题(排除一个或一些选项)
- def excluded_danxuan(self, i, *args):
- global base_xpaths
- base_xpath = base_xpaths.format(i)
- a = self.driver.find_elements(by=By.XPATH, value=base_xpath)
- c = []
- # y是计算arg的个数,方便计算还剩几个选项
- y = 0
- for x in range(1, len(a) + 1):
- c.append(x)
- for arg in args:
- y += 1
- c.remove(arg)
- d = random.choice(c)
- self.driver.find_element(by=By.CSS_SELECTOR,
- value=base_css_selectors.format(i, d)).click()
思路:是创建一个列表c,然后将选项个数添加进列表,之后根据输入的变量,在列表中逐个去除,最终在剩下的列表中随机选择一个,进行定位与点击。
- # 04 单选题(在m到n范围内单选)
- def range_danxuan(self, i, m, n):
- x = random.randint(m, n)
- self.driver.find_element(by=By.CSS_SELECTOR,
- value=base_css_selectors.format(i, x)).click()
思路:是用random.randint(m,n)函数返回一个m到n范围内的随机整数
- # 05 单选题(在某些选项中选择)如6个选项,在1235中单选
- def restrictive_danxuan(self, i, *args):
- m = []
- for arg in args:
- m.append(arg)
- n = random.choice(m)
- self.driver.find_element(by=By.CSS_SELECTOR,
- value=base_css_selectors.format(i, n)).click()
思路:将所输入的参数存入到列表中,然后使用random.choice()函数随机选择其中的一个数
- # 06 单选题(选项中允许填空)
- def textinput_danxuan(self, i, c, wenzi):
- global base_xpaths
- base_xpath = base_xpaths.format(i)
- a = self.driver.find_elements(by=By.XPATH, value=base_xpath)
- b = random.randint(1, len(a))
- self.driver.find_element(by=By.CSS_SELECTOR,
- value=base_css_selectors.format(i, b)).click()
- if c == b:
- time.sleep(0.2)
- self.driver.find_element(by=By.CSS_SELECTOR,
- value=input_css_selectors.format(i, c)).send_keys(wenzi)
思路:首先选择某个选项,如果该选项和自己输入的c相同,即可再输入文字。
- # 07 多选题(随机选择)
- def duoxuan(self, i):
- global base_xpaths
- base_xpath = base_xpaths.format(i)
- a = self.driver.find_elements(by=By.XPATH, value=base_xpath)
- b = len(a)
- # m中存放选项
- m = []
- for x in range(1, b + 1):
- m.append(x)
- c = random.randint(1, b)
- n = random.sample(m, c)
- for o in n:
- self.driver.find_element(by=By.CSS_SELECTOR,
- value=base_css_selectors.format(i, o)).click()
思路:列表m中存放选项;c表示随机生成一个选项以内的数字,即多选题要选择选项的个数;n表示从列表m中随机选择c个个数,返回类型为列表,然后经过遍历,实现多选题的多个选项的选择。
- # 08 多选题(只选择某些选项)
- def fixed_duoxuan(self, i, *args):
- for arg in args:
- self.driver.find_element(by=By.CSS_SELECTOR,
- value=base_css_selectors.format(i, arg)).click()
- # 09 多选题(排除一个或一些的选项)
- def excluded_duoxuan(self, i, *args):
- global base_xpaths
- base_xpath = base_xpaths.format(i)
- a = self.driver.find_elements(by=By.XPATH, value=base_xpath)
- # print(len(a))
- c = []
- # y是计算arg的个数,方便计算还剩几个选项
- y = 0
- for x in range(1, len(a)+1):
- c.append(x)
- for arg in args:
- y += 1
- c.remove(arg)
- # 还剩下几个选项
- z = len(a) - y
- # 多选题选项个数
- b = random.randint(1, z)
- # 多选题用sample()
- d = random.sample(c, b)
- for r in d:
- self.driver.find_element(by=By.CSS_SELECTOR,
- value=base_css_selectors.format(i, r)).click()
思路:列表c中存放选项个数,然后逐一删除输入的参数,然后在剩下的选项中用多选题的思路进行操作。
- # 10 多选题(在某些选项中多选)
- def restrictive_duoxuan(self, i, *args):
- m = []
- for arg in args:
- m.append(arg)
- n = random.randint(1, len(m))
- o = random.sample(m, n)
- for q in o:
- self.driver.find_element(by=By.CSS_SELECTOR,
- value=base_css_selectors.format(i, q)).click()
思路:列表m中存放的内容就是所输入的参数, 然后用多选题的思路进行操作。
- # 11 多选题(在m到n范围内的多选)
- def range_duoxuan(self, i, m, n):
- # 列表c为m到n的选项组,如当m=2,n=5时,c=[2,3,4,5]
- c = []
- for x in range(m, n+1):
- c.append(x)
- # 选项个数
- o = n - m + 1
- # 随机生成要填几个选项
- p = random.randint(1, o)
- d = random.sample(c, p)
- for r in d:
- self.driver.find_element(by=By.CSS_SELECTOR,
- value=base_css_selectors.format(i, r)).click()
思路:列表c为m到n的选项组,如当m=2,n=5时,c=[2,3,4,5],然后用多选题的思路进行操作。
- # 12 多选题(选项中允许填空)
- def textinput_duoxuan(self, i, c, wenzi):
- global base_xpaths
- base_xpath = base_xpaths.format(i)
- a = self.driver.find_elements(by=By.XPATH, value=base_xpath)
- b = len(a)
- # m中存放选项
- m = []
- for x in range(1, b + 1):
- m.append(x)
- # 随机生成要多选的选项个数
- o = random.randint(1, b)
- # 在选项中随机选取o个选项
- n = random.sample(m, o)
- for r in n:
- self.driver.find_element(by=By.CSS_SELECTOR,
- value=base_css_selectors.format(i, r)).click()
- if c == r:
- time.sleep(0.2)
- self.driver.find_element(by=By.CSS_SELECTOR,
- value=input_css_selectors.format(i, c)).send_keys(wenzi)
注意:该函数只适用于一个选项中需要文本输入的多选题。
思路:查看 06 单选题(选项中允许填空)和 07 多选题(随机选择) 即可理解。
- # 13 文本题
- def text(self, i, wenzi):
- self.driver.find_element(by=By.CSS_SELECTOR, value='#q{}'.format(i)).send_keys(wenzi)
思路:通过wenzi参数填写相应的内容,实现文字题的填写。
请选择您所在的城市的题目如上
如上图所示, 问卷星还给出了海外这个选项,不过一般用不到,所以笔者就除去了它,剩下的列表并存在provinces中,之后用random函数即可随机选择城市。
将它存到自制的列表还有一个原因就是selenium的Select提供的三种选择方式select_by_index(index)、select_by_value(value)、select_by_visible_text(visible_text),问卷星中只给出了value,因此很难随机选择。例如:如果给出index,那我们就可以使用random函数进行随机选择。
- provinces = [
- '北京', '天津', '河北', '山西', '内蒙古', '辽宁', '吉林', '黑龙江',
- '上海', '江苏', '浙江', '安徽', '福建', '江西', '山东', '河南',
- '湖北', '湖南', '广东', '广西', '海南', '重庆', '四川', '贵州',
- '云南', '西藏', '陕西', '甘肃', '青海', '宁夏', '新疆', '台湾',
- '香港', '澳门']
注意:
①上图中,省份与城市的选择页面是写在ifame中, 因此需要进行frame和iframe之间的切换。关键不要忘记切换回去。如果没有切换回去,即使点击确定键后,它仍在iframe中,会使得接下来元素定位失败。
②a表示省/直辖市下的城市。
- # 随机所在城市的选择
- def random_city_selection(self, i):
- frame = self.driver.find_element(by=By.XPATH, value='//*[@id="q{}"]'.format(i))
- frame.click()
- # 滚动到最底端
- # self.driver.execute_script("window.scrollTo(0, document.body.scrollHeight)")
- self.driver.switch_to.frame('PDF_i_chezchenz')
-
- ele = self.driver.find_element(by=By.CSS_SELECTOR, value='#province')
- s = Select(ele)
- province = random.choice(provinces)
- s.select_by_value(province)
- a = self.driver.find_elements(by=By.XPATH, value='//*[@id="city"]/label')
- # len(a)表示省下的城市有几个
- # print(len(a))
- b = random.randint(1, len(a))
- self.driver.find_element(by=By.XPATH, value='//*[@id="city"]/label[{}]'.format(b)).click()
- self.driver.find_element(by=By.XPATH, value='//*[@id="form1"]/div[3]/div/input').click()
- # 注意切换回原来的frame
- self.driver.switch_to.parent_frame()
- # 限制所在城市的选择
- def restrictive_city_selection(self, i, arg):
- frame = self.driver.find_element(by=By.XPATH, value='//*[@id="q{}"]'.format(i))
- frame.click()
- # 滚动到最底端
- # self.driver.execute_script("window.scrollTo(0, document.body.scrollHeight)")
- self.driver.switch_to.frame('PDF_i_chezchenz')
-
- ele = self.driver.find_element(by=By.CSS_SELECTOR, value='#province')
- s = Select(ele)
- s.select_by_value(arg)
- a = self.driver.find_elements(by=By.XPATH, value='//*[@id="city"]/label')
- # len(a)表示省下的城市有几个
- # print(len(a))
- b = random.randint(1, len(a))
- self.driver.find_element(by=By.XPATH, value='//*[@id="city"]/label[{}]'.format(b)).click()
- self.driver.find_element(by=By.XPATH, value='//*[@id="form1"]/div[3]/div/input').click()
- # 注意切换回原来的frame
- self.driver.switch_to.parent_frame()
以上代码与随机所在城市的选择的差别主要在于,添加了一个不定参数arg。
通过在具体问卷.py文件中创立一个具有几个城市的列表,然后随机选择它并将其作为arg参数,实现随机选择你所需要的城市。
例如下面的代码:
具体问卷.py
- restrictive_provinces = ['云南', '贵州', '四川']
- restrictive_province = random.choice(restrictive_provinces)
上图所示的就是提交按钮的流程
按步骤写代码,如下
注意:有些步骤需要一点时间,所以加上time.sleep()
- # 提交按钮
- def submit(self):
- # time.sleep(0.5)
- btn = self.driver.find_element(by=By.CSS_SELECTOR, value='#submit_button')
- btn.click()
- # 出现点击验证码验证
- time.sleep(1)
- self.driver.find_element(by=By.XPATH, value='//*[@id="alert_box"]/div[2]/div[2]/div[2]/button').click()
- time.sleep(0.5)
- self.driver.find_element(by=By.XPATH, value='//*[@id="SM_BTN_1"]').click()
- time.sleep(4)
- # 关闭页面
- handles = self.driver.window_handles
- self.driver.switch_to.window(handles[0])
- # time.sleep(0.5)
- # # 刷新页面(可能不需要)
- # self.driver.refresh()
- # 关闭当前页面,如果只有一个页面,则也关闭浏览器
- self.driver.close()
以上就是Sojump.py的全部代码讲解
- # -*- coding: utf-8-*-
- import random
- from selenium import webdriver
- import time
- from selenium.webdriver.common.by import By
- from selenium.webdriver.support.select import Select
-
- """
- 01 单选题(随机选择)
- danxuan()
- 02 单选题(只选择某个选项)
- fixed_danxuan()
- 03 单选题(排除一个或一些选项)
- excluded_danxuan()
- 04 单选题(在m到n范围内单选)
- range_danxuan()
- 05 单选题(在某些选项中选择)如6个选项,在1235中单选
- restrictive_danxuan()
- 06 单选题(选项中允许填空)
- textinput_danxuan()
- 07 多选题(随机选择)
- duoxuan()
- 08 多选题(只选择某些选项)
- fixed_duoxuan()
- 09 多选题(排除一个或一些选项)
- excluded_duoxuan()
- 10 多选题(在某些选项中多选)
- restrictive_duoxuan()
- 11 多选题(在m到n范围内的多选)
- range_duoxuan()
- 12 多选题(选项中允许填空)
- text_input_duoxuan()
- 13 文本题
- text()
- """
- count = 0
- provinces = [
- '北京', '天津', '河北', '山西', '内蒙古', '辽宁', '吉林', '黑龙江',
- '上海', '江苏', '浙江', '安徽', '福建', '江西', '山东', '河南',
- '湖北', '湖南', '广东', '广西', '海南', '重庆', '四川', '贵州',
- '云南', '西藏', '陕西', '甘肃', '青海', '宁夏', '新疆', '台湾',
- '香港', '澳门']
-
- '''适用的可能是问卷星网页无法右键,只能通过F12或者ctrl+shift+i快捷键进入开发者工具的问卷'''
- # 选项的xpath
- base_xpaths = '//*[@id="divquestion{}"]/ul/li'
- # 选项的css
- base_css_selectors = '#divquestion{} > ul > li:nth-child({})'
- # 允许填空选项的css_selector
- input_css_selectors = '#divquestion{} > ul > li:nth-child({}) > input.underline'
-
- '''适用的可能是除了上面的情况的问卷星'''
- # 选项的xpath
- # base_xpaths = '//*[@id="div{}"]/div/div'
- # 选项的css
- # base_css_selectors = 'div{} > div.ui-controlgroup.column{} > div.ui-checkbox.checked'
- # 允许填空选项的css_selector
- # input_css_selectors = 'tqq{}_{}'
-
- class Wenjuanxing(object):
- # 初始化
- def __init__(self, url):
- self.url = url
-
- # 计数器
- def counter(self):
- global count
- count += 1
- w = print("第{}次运行".format(count))
- return w
-
- # 伪装selenium
- def weizhuang_selenium(self):
- # 躲避智能检测
- self.option = webdriver.ChromeOptions()
- self.option.add_experimental_option('excludeSwitches', ['enable-automation'])
- self.option.add_experimental_option('useAutomationExtension', False)
- self.driver = webdriver.Chrome(options=self.option)
- self.driver.execute_cdp_cmd('Page.addScriptToEvaluateOnNewDocument',
- {'source': 'Object.defineProperty(navigator, "webdriver", {get: () => undefined})'})
- self.driver.get(self.url)
-
- # 01 单选题(随机选择)
- def danxuan(self, i):
- global base_xpaths
- base_xpath = base_xpaths.format(i)
- a = self.driver.find_elements(by=By.XPATH, value=base_xpath)
- b = random.randint(1, len(a))
- self.driver.find_element(by=By.CSS_SELECTOR,
- value=base_css_selectors.format(i, b)).click()
-
-
- # 02 单选题(只选择某个选项)
- def fixed_danxuan(self, i, b):
- self.driver.find_element(by=By.CSS_SELECTOR,
- value=base_css_selectors.format(i, b)).click()
-
- # 03 单选题(排除一个或一些选项)
- def excluded_danxuan(self, i, *args):
- global base_xpaths
- base_xpath = base_xpaths.format(i)
- a = self.driver.find_elements(by=By.XPATH, value=base_xpath)
- c = []
- # y是计算arg的个数,方便计算还剩几个选项
- y = 0
- for x in range(1, len(a) + 1):
- c.append(x)
- for arg in args:
- y += 1
- c.remove(arg)
- d = random.choice(c)
- self.driver.find_element(by=By.CSS_SELECTOR,
- value=base_css_selectors.format(i, d)).click()
-
- # 04 单选题(在m到n范围内单选)
- def range_danxuan(self, i, m, n):
- x = random.randint(m, n)
- self.driver.find_element(by=By.CSS_SELECTOR,
- value=base_css_selectors.format(i, x)).click()
-
-
- # 05 单选题(在某些选项中选择)如6个选项,在1235中单选
- def restrictive_danxuan(self, i, *args):
- m = []
- for arg in args:
- m.append(arg)
- n = random.choice(m)
- self.driver.find_element(by=By.CSS_SELECTOR,
- value=base_css_selectors.format(i, n)).click()
-
- # 06 单选题(选项中允许填空)
- def textinput_danxuan(self, i, c, wenzi):
- global base_xpaths
- base_xpath = base_xpaths.format(i)
- a = self.driver.find_elements(by=By.XPATH, value=base_xpath)
- b = random.randint(1, len(a))
- self.driver.find_element(by=By.CSS_SELECTOR,
- value=base_css_selectors.format(i, b)).click()
- if c == b:
- time.sleep(0.2)
- self.driver.find_element(by=By.CSS_SELECTOR,
- value=input_css_selectors.format(i, c)).send_keys(wenzi)
-
-
- # 07 多选题(随机选择)
- def duoxuan(self, i):
- global base_xpaths
- base_xpath = base_xpaths.format(i)
- a = self.driver.find_elements(by=By.XPATH, value=base_xpath)
- b = len(a)
- # m中存放选项
- m = []
- for x in range(1, b + 1):
- m.append(x)
- c = random.randint(1, b)
- n = random.sample(m, c)
- for o in n:
- self.driver.find_element(by=By.CSS_SELECTOR,
- value=base_css_selectors.format(i, o)).click()
-
- # 08 多选题(只选择某些选项)
- def fixed_duoxuan(self, i, *args):
- for arg in args:
- self.driver.find_element(by=By.CSS_SELECTOR,
- value=base_css_selectors.format(i, arg)).click()
-
- # 09 多选题(排除一个或一些的选项)
- def excluded_duoxuan(self, i, *args):
- global base_xpaths
- base_xpath = base_xpaths.format(i)
- a = self.driver.find_elements(by=By.XPATH, value=base_xpath)
- # print(len(a))
- c = []
- # y是计算arg的个数,方便计算还剩几个选项
- y = 0
- for x in range(1, len(a)+1):
- c.append(x)
- for arg in args:
- y += 1
- c.remove(arg)
- # 还剩下几个选项
- z = len(a) - y
- # 多选题选项个数
- b = random.randint(1, z)
- # 多选题用sample()
- d = random.sample(c, b)
- for r in d:
- self.driver.find_element(by=By.CSS_SELECTOR,
- value=base_css_selectors.format(i, r)).click()
-
- # 10 多选题(在某些选项中多选)
- def restrictive_duoxuan(self, i, *args):
- m = []
- for arg in args:
- m.append(arg)
- n = random.randint(1, len(m))
- o = random.sample(m, n)
- for q in o:
- self.driver.find_element(by=By.CSS_SELECTOR,
- value=base_css_selectors.format(i, q)).click()
-
-
- # 11 多选题(在m到n范围内的多选)
- def range_duoxuan(self, i, m, n):
- # 列表c为m到n的选项组,如当m=2,n=5时,c=[2,3,4,5]
- c = []
- for x in range(m, n+1):
- c.append(x)
- # 选项个数
- o = n - m + 1
- # 随机生成要填几个选项
- p = random.randint(1, o)
- d = random.sample(c, p)
- for r in d:
- self.driver.find_element(by=By.CSS_SELECTOR,
- value=base_css_selectors.format(i, r)).click()
-
-
- # 12 多选题(选项中允许填空)
- def text_input_duoxuan(self, i, c, wenzi):
- global base_xpaths
- base_xpath = base_xpaths.format(i)
- a = self.driver.find_elements(by=By.XPATH, value=base_xpath)
- b = len(a)
- # m中存放选项
- m = []
- for x in range(1, b + 1):
- m.append(x)
- # 随机生成要多选的选项个数
- o = random.randint(1, b)
- # 在选项中随机选取o个选项
- n = random.sample(m, o)
- for r in n:
- self.driver.find_element(by=By.CSS_SELECTOR,
- value=base_css_selectors.format(i, r)).click()
- if c == r:
- time.sleep(0.2)
- self.driver.find_element(by=By.CSS_SELECTOR,
- value=input_css_selectors.format(i, c)).send_keys(wenzi)
-
- # 13 文本题
- def text(self, i, wenzi):
- self.driver.find_element(by=By.CSS_SELECTOR, value='#q{}'.format(i)).send_keys(wenzi)
-
- # 随机所在城市的选择
- def random_city_selection(self, i):
- frame = self.driver.find_element(by=By.XPATH, value='//*[@id="q{}"]'.format(i))
- frame.click()
- # 滚动到最底端
- self.driver.execute_script("window.scrollTo(0, document.body.scrollHeight)")
- self.driver.switch_to.frame('PDF_i_chezchenz')
-
- ele = self.driver.find_element(by=By.CSS_SELECTOR, value='#province')
- s = Select(ele)
- province = random.choice(provinces)
- s.select_by_value(province)
- a = self.driver.find_elements(by=By.XPATH, value='//*[@id="city"]/label')
- # len(a)表示省下的城市有几个
- # print(len(a))
- b = random.randint(1, len(a))
- self.driver.find_element(by=By.XPATH, value='//*[@id="city"]/label[{}]'.format(b)).click()
- self.driver.find_element(by=By.XPATH, value='//*[@id="form1"]/div[3]/div/input').click()
- # 注意切换回原来的frame
- self.driver.switch_to.parent_frame()
-
- # 限制所在城市的选择
- def restrictive_city_selection(self, i, arg):
- frame = self.driver.find_element(by=By.XPATH, value='//*[@id="q{}"]'.format(i))
- frame.click()
- # 滚动到最底端
- # self.driver.execute_script("window.scrollTo(0, document.body.scrollHeight)")
- self.driver.switch_to.frame('PDF_i_chezchenz')
-
- ele = self.driver.find_element(by=By.CSS_SELECTOR, value='#province')
- s = Select(ele)
- s.select_by_value(arg)
- a = self.driver.find_elements(by=By.XPATH, value='//*[@id="city"]/label')
- # len(a)表示省下的城市有几个
- # print(len(a))
- b = random.randint(1, len(a))
- self.driver.find_element(by=By.XPATH, value='//*[@id="city"]/label[{}]'.format(b)).click()
- self.driver.find_element(by=By.XPATH, value='//*[@id="form1"]/div[3]/div/input').click()
- # 注意切换回原来的frame
- self.driver.switch_to.parent_frame()
-
- # 提交按钮
- def submit(self):
- # time.sleep(0.5)
- btn = self.driver.find_element(by=By.CSS_SELECTOR, value='#submit_button')
- btn.click()
- # 出现点击验证码验证
- time.sleep(1)
- self.driver.find_element(by=By.XPATH, value='//*[@id="alert_box"]/div[2]/div[2]/div[2]/button').click()
- time.sleep(0.5)
- self.driver.find_element(by=By.XPATH, value='//*[@id="SM_BTN_1"]').click()
- time.sleep(4)
- # 关闭页面
- handles = self.driver.window_handles
- self.driver.switch_to.window(handles[0])
- # time.sleep(0.5)
- # # 刷新页面(可能不需要)
- # self.driver.refresh()
- # 关闭当前页面,如果只有一个页面,则也关闭浏览器
- self.driver.close()
-
-
由于问卷涉及一些内容,不便公开,因此我就将问卷内容马赛克了(如下图),网址也不公布了。大家了解一下题目的类型即可
- # -*- coding: utf-8-*-
- import random
- import Sojump
- from Sojump import Wenjuanxing
- import schedule as schedule
-
- restrictive_provinces = ['云南', '贵州', '四川']
-
- problems_10_1 = ['', 'xxx', 'xx', 'xxx', 'xxx', 'xxx', 'xxx', 'xxx']
-
- problems_10_2 = ['', 'xxx', 'xx', 'xxx', 'xxx', 'xxx', 'xxx', 'xxx', 'xxx']
-
- if __name__ == '__main__':
- url = '问卷星网址'
- wenjuanxing = Wenjuanxing(url)
- def run():
- # 随机内容
- restrictive_province = random.choice(restrictive_provinces)
- problem_10_1 = random.choice(problems_10_1)
- problem_10_2 = random.choice(problems_10_2)
- # 计数器
- wenjuanxing.counter()
- # 伪装selenium
- wenjuanxing.weizhuang_selenium()
- # 问卷题目
- wenjuanxing.danxuan(1)
- wenjuanxing.danxuan(2)
- wenjuanxing.restrictive_danxuan(3, 2, 3, 4, 5)
- wenjuanxing.danxuan(4)
- wenjuanxing.danxuan(5)
- wenjuanxing.danxuan(6)
- wenjuanxing.duoxuan(7)
- wenjuanxing.danxuan(8)
- wenjuanxing.danxuan(9)
- # 第十题为两个选项都可以填空的单选题,因此尝试用try except
- try:
- wenjuanxing.textinput_danxuan(10, 1, problem_10_1)
- # print(problem_10_1)
- wenjuanxing.textinput_danxuan(10, 2, problem_10_2)
- # print(problem_10_2)
- except:
- pass
- wenjuanxing.duoxuan(11)
- wenjuanxing.danxuan(12)
- # 13得考虑一下
- # 第13题虽然是有五个选项的多选题,不过依据逻辑,它只能分成1 3 1 形式,
- # 即要么选择第一个选项,要么在中间三个选项之间进行多选,要么选择最后一个选项。
- a = random.randint(1, 3)
- if a == 1:
- wenjuanxing.fixed_danxuan(13, 1)
- elif a == 2:
- wenjuanxing.range_duoxuan(13, 2, 5)
- else:
- wenjuanxing.fixed_danxuan(13, 6)
- wenjuanxing.danxuan(14)
- wenjuanxing.duoxuan(15)
- wenjuanxing.duoxuan(16)
- wenjuanxing.danxuan(17)
- # 限制省份的随机选择
- # print(restrictive_province)
- wenjuanxing.restrictive_city_selection(18, restrictive_province)
- # time.sleep(3)
- # 提交问卷
- wenjuanxing.submit()
- # 每隔2秒运行
- schedule.every(2).seconds.do(run)
- # 判断条件
- while Sojump.count < 50:
- schedule.run_pending()
-
-
①每隔一段时间运行代码
- import schedule as schedule
- def run():
- pass
-
-
- schedule.every(2).seconds.do(run)
-
- while True:
- schedule.run_pending()
该模板请牢记,上述代码表示每隔五秒运行一次,如果需要每隔一秒运行一次代码,则将其中的
schedule.every(2).seconds.do(run)改为
schedule.every(1).second.do(run)
由于count参数表示代码运行的次数,而问卷星在刷50份后得过一小时后才能继续刷,因此得加个判断(如下),防止程序一直运行。
while Sojump.count < 50:
②编写主体代码
因为一些题目的选项中需要填写文本,以及如果大家需要限定省份的随机随机选择。这就需要制作相应的列表,然后通过随机选取列表中的某个内容,自动填写进问卷。
- restrictive_provinces = ['云南', '贵州', '四川']
-
- problems_10_1 = ['', 'xxx', 'xx', 'xxx', 'xxx', 'xxx', 'xxx', 'xxx']
-
- problems_10_2 = ['', 'xxx', 'xx', 'xxx', 'xxx', 'xxx', 'xxx', 'xxx', 'xxx']
这里需要注意的是: 随机选取列表中内容的代码段需要编写在run()函数中而不能直接写在上述代码下面,否则不经过run()函数,不会进行每隔一段时间运行的过程,其产生的随机内容将在每次使用都不变。这是笔者后来无意发现的,说来惭愧,这一个小失误,导致一次刷的50份的文本内容都一样,因此大家敲代码时需要多思考。
接下来需要调用类
- url = '问卷星网址'
- wenjuanxing = Wenjuanxing(url)
接下来就是编写run()函数,其中主要就是根据问卷内容、题目类型的不同而编写。
代码如下:
- def run():
- # 随机内容
- restrictive_province = random.choice(restrictive_provinces)
- problem_10_1 = random.choice(problems_10_1)
- problem_10_2 = random.choice(problems_10_2)
- # 计数器
- wenjuanxing.counter()
- # 伪装selenium
- wenjuanxing.weizhuang_selenium()
- # 问卷题目
- wenjuanxing.danxuan(1)
- wenjuanxing.danxuan(2)
- wenjuanxing.restrictive_danxuan(3, 2, 3, 4, 5)
- wenjuanxing.danxuan(4)
- wenjuanxing.danxuan(5)
- wenjuanxing.danxuan(6)
- wenjuanxing.duoxuan(7)
- wenjuanxing.danxuan(8)
- wenjuanxing.danxuan(9)
- # 第十题为两个选项都可以填空的单选题,因此尝试用try except
- try:
- wenjuanxing.textinput_danxuan(10, 1, problem_10_1)
- # print(problem_10_1)
- wenjuanxing.textinput_danxuan(10, 2, problem_10_2)
- # print(problem_10_2)
- except:
- pass
- wenjuanxing.duoxuan(11)
- wenjuanxing.danxuan(12)
- # 13得考虑一下
- # 第13题虽然是有五个选项的多选题,不过依据逻辑,它只能分成1 3 1 形式,
- # 即要么选择第一个选项,要么在中间三个选项之间进行多选,要么选择最后一个选项。
- a = random.randint(1, 3)
- if a == 1:
- wenjuanxing.fixed_danxuan(13, 1)
- elif a == 2:
- wenjuanxing.range_duoxuan(13, 2, 5)
- else:
- wenjuanxing.fixed_danxuan(13, 6)
- wenjuanxing.danxuan(14)
- wenjuanxing.duoxuan(15)
- wenjuanxing.duoxuan(16)
- wenjuanxing.danxuan(17)
- # 限制省份的随机选择
- # print(restrictive_province)
- wenjuanxing.restrictive_city_selection(18, restrictive_province)
- # time.sleep(3)
- # 提交问卷
- wenjuanxing.submit()
着重注意一下以下两题
第10题为两个选项都可以填空的单选题,因此尝试用try except。
第13题虽然是有五个选项的多选题,不过依据逻辑,它只能分成1 3 1 形式, 即要么选择第一个选项,要么在中间三个选项之间进行多选,要么选择最后一个选项。
此外,如果要进行随机省份的选择,只需调用即可(如下)
wenjuanxing.random_city_selection(18)
剩下的其他函数在之前的内容中讲过,也比较简单。
问卷星根据题目的不同、题目和选项的搭配能产生很多变化,上述只涉及到几个较常用的几个函数。后续大家如果需要实现一些其他功能的,可以自行编写,也可以与笔者多多交流,完善该模块。
最后希望大家不要光看文章,也可以动手敲敲代码,加深理解。
如果大家发现无法刷问卷,可能就是元素定位出现了问题,可以去看看元素定位属于上述讲的哪一类。
如有错误之处,请批评指正!!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。