基于python的问卷星自动填写脚本

引言

疫情期间,总有许多的问卷星需要填写,大多数都是单一内容的重复输入。为了更好地学习(摸鱼),研究了一下问卷星自动填写的方法。

思路历程
selenium

说到网络爬虫,很容易就想到了selenium。作为一个知名的web自动化测试框架,selenium在爬虫中应用广泛。那么首先尝试采用selenium进行操作。

'''
Description: 问卷星自动签到 selenium
'''
from selenium import webdriver
import time

driver = webdriver.Chrome()
driver.get('网站') 

driver.find_element_by_id('q1').send_keys('姓名')
driver.find_element_by_id('q2').send_keys('学号')
driver.find_element_by_xpath('/html/body/div[4]/div[2]/div[2]/div[1]/div/div[1]/div[2]/div[2]/fieldset/div[3]/div[2]/ul/li[2]/a').click()
driver.find_element_by_xpath('/html/body/div[4]/div[2]/div[2]/div[1]/div/div[1]/div[2]/div[2]/fieldset/div[4]/div[2]/ul/li[2]/a').click()
driver.find_element_by_xpath('/html/body/div[4]/div[2]/div[2]/div[1]/div/div[1]/div[2]/div[2]/fieldset/div[5]/div[2]/ul/li[3]/a').click()
driver.find_element_by_xpath('/html/body/div[4]/div[2]/div[2]/div[1]/div/div[1]/div[2]/div[2]/fieldset/div[6]/div[2]/ul/li[1]/a').click()
driver.find_element_by_xpath('/html/body/div[4]/div[2]/div[2]/div[1]/div/div[1]/div[2]/div[2]/fieldset/div[7]/div[2]/ul/li[3]/a').click()
driver.find_element_by_id("submit_button").click()  

time.sleep(0.5) 
driver.quit()

element的获取方法有id/class/xpath,一般选择class和id,也可以用xpath对element进行精确定位(firefox自带获取xpath/cssSelector的选项卡)。然而提交的时候确出现了问题,这种方法会被要求进行验证,并且验证无法成功。其原因就在于问卷星对selenium进行了检测,因此这个方法PASS

mac python自动问卷星 问卷星自动填写脚本python_mac python自动问卷星

selenium 的缺点很明显,比如速度太慢、对版本配置要求严苛,最麻烦是经常要更新对应的驱动还有些网页是可以检测到是否是使用了selenium 。并且selenium 所谓的保护机制不允许跨域 cookies 保存以及登录的时候必须先打开网页然后加载 cookies 再刷新的方式很不友好。

pyppeteer

于是就发现了这款web 自动化测试工具 pyppeteer,虽然支持的浏览器比较单一,但在安装配置的便利性和运行效率方面都要远胜 selenium。介绍 Pyppeteer 之前先说一下 Puppeteer,Puppeteer 是 Google 基于 Node.js 开发的一个工具,主要是用来操纵 Chrome 浏览器的 API,通过 Javascript 代码来操纵 Chrome 浏览器的一些操作,用作网络爬虫完成数据爬取、Web 程序自动测试等任务,其 API 极其完善,功能非常强大。 Pyppeteer 实际上是 Puppeteer 的 Python 版本的实现,是一位来自于日本的工程师依据 Puppeteer 的一些功能开发出来的非官方版本。--(

Pyppeteer 两大特点:chromium浏览器和asyncio框架(Python的一个异步协程库)。由于 Pyppeteer 是基于 asyncio 构建的,它的所有属性和方法 几乎都是coroutine (协程)对象,因此在构建异步程序的时候非常方便,天生就支持异步运行

'''
Description: 问卷星自动签到 pyppeteer
'''
import asyncio
from pyppeteer import launch
from pyppeteer_stealth import stealth    # 反爬虫第三方库

async def main():
    browser = await launch({
        'executablePath': 'C:\Program Files\Google\Chrome\Application\chrome.exe',
        # Pyppeteer 默认使用的是无头浏览器,所以要显示需要给False
        'headless': False,
        'args': ['--no-sandbox', '--window-size=1366,850']
    })

    page = await browser.newPage()
    await page.setViewport({'width':1366,'height':768})
    # 防止页面识别出脚本(反爬虫关键语句)
    await stealth(page)

    await page.goto('网页')
    # 填空题:page.type(selector,text),在指定selector的元素上填写text
    await page.type('#q1', '李四') # CssSelector
    await page.type('#q2', '学号')
    
    # 单选题:先用page.querySelector(selector)找到指定的元素,再调用元素的click()方法、还可以用xpath方法
    # CssSelector: ul在第二个次序、li在第二个次序、a标签在第二个次序
    button = await page.querySelector('#divquestion3 > ul:nth-child(2) > li:nth-child(2) > a:nth-child(1)')
    await button.click()

    button = await page.querySelector('#divquestion4 > ul:nth-child(2) > li:nth-child(2) > a:nth-child(1)')
    await button.click()

    button = await page.querySelector('#divquestion5 > ul:nth-child(2) > li:nth-child(3) > a:nth-child(1)')
    await button.click()

    button = await page.querySelector('#divquestion6 > ul:nth-child(2) > li:nth-child(1) > a:nth-child(1)')
    await button.click()

    button = await page.querySelector('#divquestion7 > ul:nth-child(2) > li:nth-child(3) > a:nth-child(1)')
    await button.click()
   
   	# # 地址题:先点击手动填写地址,再在地址框内填写相应地址
    # address = await page.querySelector("#divquestion7 > ul > li:nth-child(1) > label")
    # await address.click()
    # await page.type('#q9', '地址')
    
    # # 日期选择题:先点击日期选择框,在出现的iframe寻找元素并调用click()方法
    # date1 = await page.querySelector("#q4")
    # await date1.click()
    # frame = page.frames
    # date2 = await frame[1].querySelector('#selectTodayButton')
    # await date2.click()

    # 找到提交按钮提交
    submit = await page.querySelector('#submit_button')
    await submit.click()
    await asyncio.sleep(2)                 
    await browser.close()
    
asyncio.get_event_loop().run_until_complete(main())
# 反爬虫:原理是将get请求转换成undefined, 也可以用stealth库来防止机器人检测
await stealth(page)
await page.evaluateOnNewDocument('Object.defineProperty(navigator, "webdriver", {get: () => undefined})')

# 三种解析方式
Page.querySelector()           # CSS选择器
Page.querySelectorAll()
Page.xpath()                   # xpath  
page.evaluate('window.scrollBy(0, window.innerHeight)') # 执行js语句
# Pyppeteer的evaluate()方法只使用JavaScript字符串,该字符串可以是函数或表达式。可以添加选项force_expr=True,强制Pyppeteer作为表达式处理。

mac python自动问卷星 问卷星自动填写脚本python_mac python自动问卷星_02

总结
  1. selenium和pyppeteer都是一种web自动化测试工具,其中pyppeteer提供了防机器人检测的功能。
  2. 如果用于大量问卷的填写,会出现更多复杂的验证方式,本文仅仅图一乐。
  3. 此后还可以通过windows自带的功能实现脚本定时运行。