Python填寫問卷星

Python填寫問卷星

有些無意義的問卷作業(yè),真的沒有必要。
但是作業(yè)既然有了,那就想辦法解決它把。
關(guān)于IP限制的問題,可以使用X-Forwarded-For更換IP。
只會用印象筆記markdown的我,感覺簡書markdown好復(fù)雜。
我想做個目錄,但是[toc]沒反應(yīng),...

1.分析接口

問卷星提交數(shù)據(jù)的url

url需要參數(shù)生成,submiitdata為提交的數(shù)據(jù)

1$2:表示選擇第一問的第二個選項(xiàng),這是單選題的數(shù)據(jù)格式

2.構(gòu)造url

構(gòu)造url需要submittype, curID, t, starttime, ktimes, rn, hlv, jqnonce, jqsign
經(jīng)實(shí)驗(yàn),必要的參數(shù)如下:

  • submittype,curID,ktimes,rn,jqnonce,jqsign
    但是只傳這些參數(shù),會讓你輸入驗(yàn)證碼,最后得出結(jié)果,除了hlv其他參數(shù)都是必要的

必要參數(shù)獲取方式:

  • submittype:我做的是調(diào)查類問卷,固定值為1,其他類型問卷沒試過
  • curlID:問卷網(wǎng)址中含有此數(shù)值,也可以從訪問問卷網(wǎng)址獲取的response中獲取
  • t:時間戳,后三位為隨機(jī)數(shù),推測為提交數(shù)據(jù)的時間,我們可以使用python生成
  • starttime:字符串格式的時間,推測為打開網(wǎng)頁的時間,我們可以使用python生成
  • ktimes:做題的時間,但是不是秒數(shù),根據(jù)做題時間變長而增大,用以生成jasign,我們可以用python生成
  • rn:從訪問問卷網(wǎng)址獲取的response中獲取
  • jqnonce: 從訪問問卷網(wǎng)址獲取的response中獲取,用以生成jqsign
  • jqsign:使用ktimes和jqnonce
    • 經(jīng)過查看js代碼,找到了jqsign的生成函數(shù)
      其中a是jqnonce
      dataenc(a)
      {
      var b = ktimes % 10;
      b == 0 && (b = 1);
      for (var d = [], c = 0; c < a.length; c++) {
          var f = a.charCodeAt(c) ^ b;
          d.push(String.fromCharCode(f))
      }
      return d.join("")
      }
      
      
      轉(zhuǎn)換為python:
          result = []
          b = ktimes % 10
          if b == 0:
              b = 1
          for char in list(jqnonce):
              f = ord(char) ^ b
              result.append(chr(f))
          return ''.join(result)
      

思路有了,可以開工了。
先定義一個問卷星的類:

  • wj_url:要填寫的問卷的url
  • post_url:用來提交數(shù)據(jù)的url
  • header:請求頭
  • cookie:請求使用的cookie,提交問卷cookie可設(shè)置可不設(shè)置
  • data:需要提交的數(shù)據(jù)
import requests
import re
import time
import random

class WenJuanXing:
    def __init__(self, url):
        """
        :param url:要填寫的問卷的url
        """
        self.wj_url = url
        self.post_url = None
        self.header = None
        self.cookie = None
        self.data = None

ktimes生成函數(shù):

    def get_ktimes(self):
        """
        隨機(jī)生成一個ktimes,ktimes是構(gòu)造post_url需要的參數(shù),為一個整數(shù)
        :return:
        """
        return random.randint(5, 18)

header設(shè)置函數(shù):
隨機(jī)生成IP,如果不換IP,提交多了會提示輸入驗(yàn)證碼
很少見到x-forwarded-for能有用的時候,問卷星剛好就可以

    def set_header(self):
        """
        隨機(jī)生成ip,設(shè)置X-Forwarded-For
        ip需要控制ip段,不然生成的大部分是國外的
        :return:
        """
        ip = '{}.{}.{}.{}'.format(112, random.randint(64, 68), random.randint(0, 255), random.randint(0, 255))
        self.header = {
            'X-Forwarded-For': ip,
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko\
                        ) Chrome/71.0.3578.98 Safari/537.36',
        }

訪問問卷網(wǎng)址,獲取response:

    def get_response(self):
        """
        訪問問卷網(wǎng)頁,獲取網(wǎng)頁代碼
        :return: get請求返回的response
        """
        response = requests.get(url=self.wj_url, headers=self.header)
        self.cookie = response.cookies
        return response

通過上面的response獲取jqnonce:
由于jqnonce是script里面的一個變量,所以使用正則表達(dá)式提取
我更喜歡xpath,但是好像xpath提不出來

    def get_jqnonce(self, response):
        """
        通過正則表達(dá)式找出jqnonce,jqnonce是構(gòu)造post_url需要的參數(shù)
        :param response: 訪問問卷網(wǎng)頁,返回的reaponse
        :return: 找到的jqnonce
        """
        jqnonce = re.search(r'.{8}-.{4}-.{4}-.{4}-.{12}', response.text)
        return jqnonce.group()

通過response獲取rn:

    def get_rn(self, response):
        """
        通過正則表達(dá)式找出rn,rn是構(gòu)造post_url需要的參數(shù)
        :param response: 訪問問卷網(wǎng)頁,返回的reaponse
        :return: 找到的rn
        """
        rn = re.search(r'\d{9,10}\.\d{8}', response.text)
        return rn.group()

通過response獲取id

    def get_id(self, response):
        """
        通過正則表達(dá)式找出問卷id,問卷是構(gòu)造post_url需要的參數(shù)
        :param response: 訪問問卷網(wǎng)頁,返回的reaponse
        :return: 找到的問卷id
        """
        id = re.search(r'\d{8}', response.text)
        return id.group()

通過jqnonce和ktimes生成jqsign:

    def get_jqsign(self, ktimes, jqnonce):
        """
        通過ktimes和jqnonce計(jì)算jqsign,jqsign是構(gòu)造post_url需要的參數(shù)
        :param ktimes: ktimes
        :param jqnonce: jqnonce
        :return: 生成的jqsign
        """
        result = []
        b = ktimes % 10
        if b == 0:
            b = 1
        for char in list(jqnonce):
            f = ord(char) ^ b
            result.append(chr(f))
        return ''.join(result)

通過response獲取starttime:
獲取starttime的正則表達(dá)式我沒有獲取秒,因?yàn)楂@取秒后會彈驗(yàn)證碼
我猜測:

  • starttime,t, ktimes存在一定關(guān)系,但這些數(shù)據(jù)都是我們偽造的,忽略的秒數(shù)可能會消除我們偽造的虛假
    def get_start_time(self, response):
        """
        通過正則表達(dá)式找出問卷starttime,問卷是構(gòu)造post_url需要的參數(shù)
        :param response: 訪問問卷網(wǎng)頁,返回的reaponse
        :return: 找到的starttime
        """
        start_time = re.search(r'\d+?/\d+?/\d+?\s\d+?:\d{2}', response.text)
        return start_time.group()

終于把各個參數(shù)獲取的差不多了,可以生成url了:

    def set_post_url(self):
        """
        生成post_url
        :return:
        """
        self.set_header()  # 設(shè)置請求頭,更換ip
        response = self.get_response()  # 訪問問卷網(wǎng)頁,獲取response
        ktimes = self.get_ktimes()  # 獲取ktimes
        jqnonce = self.get_jqnonce(response)  # 獲取jqnonce
        rn = self.get_rn(response)  # 獲取rn
        id = self.get_id(response)  # 獲取問卷id
        jqsign = self.get_jqsign(ktimes, jqnonce)  # 生成jqsign
        start_time = self.get_start_time(response)  # 獲取starttime
        time_stamp = '{}{}'.format(int(time.time()), random.randint(100, 200))  # 生成一個時間戳,最后三位為隨機(jī)數(shù)
        url = 'https://www.wjx.cn/joinnew/processjq.ashx?submittype=1&curID={}&t={}&starttim' \
              'e={}&ktimes={}&rn={}&jqnonce={}&jqsign={}'.format(id, time_stamp, start_time, ktimes, rn, jqnonce, jqsign)
        self.post_url = url  # 設(shè)置url
        print(self.post_url)

3.生成數(shù)據(jù)

url生成好了,我們基本成功了,剩下的工作就比較輕松了
生成需要提交的數(shù)據(jù):

  • 之前提過了,1$1代表選擇第一問的第一個選項(xiàng)
  • 如果有更多的選項(xiàng)和不同的問題類型,需要瀏覽器抓包了解其結(jié)構(gòu)
  • 可以使用有限制的隨機(jī)函數(shù),是提交的結(jié)果不那么假
  • 我這兒只有一道題作為測試,所以數(shù)據(jù)構(gòu)造的很簡答
    def set_data(self):
        """
        這個函數(shù)中生成問卷的結(jié)果,可根據(jù)問卷結(jié)果,隨機(jī)生成答案
        :return:
        """
        self.data = {
            'submitdata': '1$1'
        }

4.提交數(shù)據(jù)

萬事俱備,只欠東風(fēng)。
如果response.text為22,則代表失敗
會有少數(shù)的失敗,不知道什么原因
post_data函數(shù):

    def post_data(self):
        """
        發(fā)送數(shù)據(jù)給服務(wù)器
        :return: 服務(wù)器返回的結(jié)果
        """
        self.set_data()
        response = requests.post(url=self.post_url, data=self.data, headers=self.header, cookies=self.cookie)
        return response

run函數(shù):
至此我們就可以全自動化的填問卷了,而且不受ip的限制

    def run(self):
        """
        填寫一次問卷
        :return:
        """
        self.set_post_url()
        result = self.post_data()
        print(result.content.decode())

一次填寫多個問卷:

    def mul_run(self, n):
        """
        填寫多次問卷
        :return:
        """
        for i in range(n):
            self.run()

5.啟動啟動

運(yùn)行一下:

if __name__ == '__main__':
    w = WenJuanXing('https://www.wjx.cn/jq/xxxxxxxx.aspx')
    w.mul_run(100)

結(jié)果:
紅色圈出來的22代表失敗,其他的代表成功


結(jié)果

問卷統(tǒng)計(jì):


問卷統(tǒng)計(jì)

地理位置:
位置統(tǒng)計(jì)

6.完整代碼

好了,該睡覺了??
如果覺得速度不夠快,可以用多線程

import requests
import re
import time
import random


class WenJuanXing:
    def __init__(self, url):
        """
        :param url:要填寫的問卷的url
        """
        self.wj_url = url
        self.post_url = None
        self.header = None
        self.cookie = None
        self.data = None

    def set_data(self):
        """
        這個函數(shù)中生成問卷的結(jié)果,可根據(jù)問卷結(jié)果,隨機(jī)生成答案
        :return:
        """
        self.data = {
            'submitdata': '1$1'
        }

    def set_header(self):
        """
        隨機(jī)生成ip,設(shè)置X-Forwarded-For
        ip需要控制ip段,不然生成的大部分是國外的
        :return:
        """
        ip = '{}.{}.{}.{}'.format(112, random.randint(64, 68), random.randint(0, 255), random.randint(0, 255))
        self.header = {
            'X-Forwarded-For': ip,
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko\
                        ) Chrome/71.0.3578.98 Safari/537.36',
        }

    def get_ktimes(self):
        """
        隨機(jī)生成一個ktimes,ktimes是構(gòu)造post_url需要的參數(shù),為一個整數(shù)
        :return:
        """
        return random.randint(15, 50)

    def get_response(self):
        """
        訪問問卷網(wǎng)頁,獲取網(wǎng)頁代碼
        :return: get請求返回的response
        """
        response = requests.get(url=self.wj_url, headers=self.header)
        self.cookie = response.cookies
        return response

    def get_jqnonce(self, response):
        """
        通過正則表達(dá)式找出jqnonce,jqnonce是構(gòu)造post_url需要的參數(shù)
        :param response: 訪問問卷網(wǎng)頁,返回的reaponse
        :return: 找到的jqnonce
        """
        jqnonce = re.search(r'.{8}-.{4}-.{4}-.{4}-.{12}', response.text)
        return jqnonce.group()

    def get_rn(self, response):
        """
        通過正則表達(dá)式找出rn,rn是構(gòu)造post_url需要的參數(shù)
        :param response: 訪問問卷網(wǎng)頁,返回的reaponse
        :return: 找到的rn
        """
        rn = re.search(r'\d{9,10}\.\d{8}', response.text)
        return rn.group()

    def get_id(self, response):
        """
        通過正則表達(dá)式找出問卷id,問卷是構(gòu)造post_url需要的參數(shù)
        :param response: 訪問問卷網(wǎng)頁,返回的reaponse
        :return: 找到的問卷id
        """
        id = re.search(r'\d{8}', response.text)
        return id.group()

    def get_jqsign(self, ktimes, jqnonce):
        """
        通過ktimes和jqnonce計(jì)算jqsign,jqsign是構(gòu)造post_url需要的參數(shù)
        :param ktimes: ktimes
        :param jqnonce: jqnonce
        :return: 生成的jqsign
        """
        result = []
        b = ktimes % 10
        if b == 0:
            b = 1
        for char in list(jqnonce):
            f = ord(char) ^ b
            result.append(chr(f))
        return ''.join(result)

    def get_start_time(self, response):
        """
        通過正則表達(dá)式找出問卷starttime,問卷是構(gòu)造post_url需要的參數(shù)
        :param response: 訪問問卷網(wǎng)頁,返回的reaponse
        :return: 找到的starttime
        """
        start_time = re.search(r'\d+?/\d+?/\d+?\s\d+?:\d{2}', response.text)
        return start_time.group()

    def set_post_url(self):
        """
        生成post_url
        :return:
        """
        self.set_header()  # 設(shè)置請求頭,更換ip
        response = self.get_response()  # 訪問問卷網(wǎng)頁,獲取response
        ktimes = self.get_ktimes()  # 獲取ktimes
        jqnonce = self.get_jqnonce(response)  # 獲取jqnonce
        rn = self.get_rn(response)  # 獲取rn
        id = self.get_id(response)  # 獲取問卷id
        jqsign = self.get_jqsign(ktimes, jqnonce)  # 生成jqsign
        start_time = self.get_start_time(response)  # 獲取starttime
        time_stamp = '{}{}'.format(int(time.time()), random.randint(100, 200))  # 生成一個時間戳,最后三位為隨機(jī)數(shù)
        url = 'https://www.wjx.cn/joinnew/processjq.ashx?submittype=1&curID={}&t={}&starttim' \
              'e={}&ktimes={}&rn={}&jqnonce={}&jqsign={}'.format(id, time_stamp, start_time, ktimes, rn, jqnonce, jqsign)
        self.post_url = url  # 設(shè)置url
        print(self.post_url)

    def post_data(self):
        """
        發(fā)送數(shù)據(jù)給服務(wù)器
        :return: 服務(wù)器返回的結(jié)果
        """
        self.set_data()
        response = requests.post(url=self.post_url, data=self.data, headers=self.header, cookies=self.cookie)
        return response

    def run(self):
        """
        填寫一次問卷
        :return:
        """
        self.set_post_url()
        result = self.post_data()
        print(result.content.decode())

    def mul_run(self, n):
        """
        填寫多次問卷
        :return:
        """
        for i in range(n):
            time.sleep(0.1)
            self.run()


if __name__ == '__main__':
    w = WenJuanXing('url')
    w.mul_run(100)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容