January 5, 2019

利用Python自動填寫google表單(不要傳給你老師XD)

利用Python自動填寫google表單(不要傳給你老師XD)

有些老師會要求學生要製作一個google表單,然後要求學生去調查,真的是一件很麻煩的事情,還要到處麻煩別人。自己填又很浪費時間,尤其是表單選項超多的時候。身為資工具人,就要寫個程式秒殺它。

這篇文章適合有基本程式能力的人

創題目

首先先試試簡單的情況,全單選

提交一份看看

打開提交頁面看看

這時候打開瀏覽器的開發人緣工具 (如果開完還是邊緣人別找我XD
(快捷鍵應該是 ctrl+shift+i)
切換到 Network 面板

接下來隨便填一份提交
然後再看一次開發人員工具應該會看到類似的畫面

根據經驗猜測,第一個大概就是我們要的
點開後滑道最下面看 Form Data

接下來那兩個 entry. 開頭的就是上傳的表單資料
剩下的是什麼呢?不重要了 XD

用 Python 提交一次看看

這邊用的是 Python 內建的 http.client.HTTPSConnection 做 POST 請求,所以不用另外裝其他 module 。

http.client.HTTPConnection(host, port=None, [timeout, ]source_address=None, blocksize=8192)
HTTPConnection.request(method, url, body=None, headers={}, *, encode_chunked=False)

  • method 請求的方式,這裡用 'POST' 就好
  • url 請求的資源,這邊寫表單網址 https://docs.google.com 以後的部份
  • headers 要加上下面那幾項
    • Host: docs.google.com 基於 HTTP 協議要加這行
    • Content-Type: application/x-www-form-urlencoded 因為回傳的內容
    • Connection: close 告訴伺服器傳完後就關閉連線
  • body POST 請求的資料本體 (這裡用 urllib.parse.urlencode 來產生) ,這裡面要放的就是剛剛開發人員工具裡面的 Form Data
import http.client
import urllib.parse


def req():
    try:
        connection = http.client.HTTPSConnection('docs.google.com', 443, timeout=10)
        connection.request(
            method='POST',
            url='/forms/d/e/1FAIpQLSeN7L2W9W4_vJsZJStHWu5Qth_9xNiFgNOgEBeWYu188EGKlA/formResponse',
            headers={
                'Host': 'docs.google.com',
                'Content-Type': 'application/x-www-form-urlencoded',
                'Connection': 'close',
            },
            body=urllib.parse.urlencode({
                'entry.952025576': 'test a',
                'entry.8382262': 'ccc',
                'fvv': '1',
                'draftResponse': '[null,null,"5051129176770073215"]',
                'pageHistory': '0',
                'fbzx': '5051129176770073215',
            })
        )

        with connection.getresponse() as response:
            pass

        print('done')
    except KeyboardInterrupt as exception:
        raise exception
    except Exception as exception:
        print('err', exception)


if __name__ == '__main__':
    req()

保存!(我這邊存 test.py
接下來執行一次看看

python3 test.py

再打開結果頁面看看,發現剛剛送出的結果已經拿到了!

稍微修改一下程式~

剛剛得程式只能回傳一種答案,可是選項友好幾種呢!以單選題來說,選項的就是顯示給用戶看的那個名稱,把它們放進去吧~再用個隨機數隨便選好了(如果你要特別的分佈就自己寫吧,我懶~~)

body=urllib.parse.urlencode({
    'entry.952025576': ['test a', 'test b', 'test c'][random.randrange(3)],
    'entry.8382262': ['aaa', 'bbb', 'ccc'][random.randrange(3)],
    'fvv': '1',
    'draftResponse': '[null,null,"4085283020350513139"]',
    'pageHistory': '0',
    'fbzx': '4085283020350513139',
}

如果覺得太慢呢,可以用多執行緒

import random
import http.client
import urllib.parse
import threading


def req():
    try:
        connection = http.client.HTTPSConnection('docs.google.com', 443, timeout=10)
        connection.request(
            method='POST',
            url='/forms/d/e/1FAIpQLSeN7L2W9W4_vJsZJStHWu5Qth_9xNiFgNOgEBeWYu188EGKlA/formResponse',
            headers={
                'Host': 'docs.google.com',
                'Content-Type': 'application/x-www-form-urlencoded',
                'Connection': 'close',
            },
            body=urllib.parse.urlencode({
                'entry.952025576': ['test a', 'test b', 'test c'][random.randrange(3)],
                'entry.8382262': ['aaa', 'bbb', 'ccc'][random.randrange(3)],
                'fvv': '1',
                'draftResponse': '[null,null,"4085283020350513139"]',
                'pageHistory': '0',
                'fbzx': '4085283020350513139',
            })
        )

        with connection.getresponse() as response:
            pass

        print('done')
    except KeyboardInterrupt as exception:
        raise exception
    except Exception as exception:
        print('err', exception)


def inf_req():
    while True:
        req()


if __name__ == '__main__':
    for _ in range(20):
        threading.Thread(target=inf_req).start()

看看結果怎麼樣吧~

呈現了平均分佈的樣子了呢~
上下的數字還有點對不上,看來 google 覺得這個請求速度有點母湯了呢。
(剛寫完這行的時候就有12000了,不過要這麼多做什麼呢 XD)