Categories: automation

WFH google form punch with selenium

公司的 WHF 打卡表單

目前因為三級防疫,所以公司是採取分流上班的,分成兩組 A, B,隔天輪流進公司以及 WFH。
由於勞基法需要有上下班紀錄,所以 WFH 的那天需要線上打卡做紀錄。這個線上打卡的機制是透過 Google 表單 來實做的,就時間到的時候點這個表單的網址,上面填寫以及點選內容然後送出即可。

可是明明都需要用 google 帳號登入了,為什麼表單還得自行填名字呢?

如果只是點一點然後送出整個流程是是還算快的,但是還要自己填名字這大幅降低順暢度,而且每次都要做一次就會深深地覺得是不是有機會更方便一點呢?

表單能少填一點是一點

所以研究了一點 Google 表單,能不能在開這個網址的時候順便先預先填好或是選好選項呢?
很開心是可以的,雖然需要一點點查詢,不過這個表單應該不會變動地太頻繁,能夠先預先好就可以大幅加快打卡的速度。

只要能夠找出對應的 entry.id,就可以做出預填的表單網址!

&entry.688404720=我的名字&entry.224455179=上班&entry.1962636723=Work%20from%20Home&entry.1449878790=否

只要上面段串在原本的表單網址後面,可以看到原本空空的欄位都已經先填寫好了,可以大致上預覽一下沒有問題直接按鈕送出即可。

那麼要怎麼找出這些 entry 的 id 們 呢?可以透過 chrome 的 inspector 來查詢一下,就可以看到了。

直接在 server 上下指令打卡

把上班下班對應填好的網址存起來方便不少,但還是需要最後送出那一步,有沒有可能連這個步驟都省掉呢?另外更甚至能不能夠直接放在公司的伺服器上呢?這樣就可以不用維持自己的電腦開機就可以直接自動地時間到打卡就行了,多麼地開心啊!

是的,這當然也是可以的,透過簡單的 selenium 就可以做到了。不過麻煩的地方是伺服上的有沒有適合的 chrome 瀏覽器可以支援呢?那要怎麼 google 帳號登入呢?

先調查一下,想要跑的伺服器上面雖然沒有裝 google-chrome 但是有 chromium-browser,版本雖然有點舊,不過是支援 headless 模式的。但重點是沒有裝 chromedriver,直接裝 selenium 是找不到的。

可以配合 chromedriver-binary-auto 自動找到對應版本的 chromedriver

$ pip install -U chromedriver-binary-auto

另外 import 的時機也需要注意一下

from selenium import webdriver
import chromedriver_binary

不過在伺服上開發的時候,發現了幾個不太一樣的地方,

  • 指定了相同的 user_data_dir 但還是沒辦法記住登錄的帳號
  • 指定的 headless 跟沒有指定的時候看到的畫面是不太一樣的

為此在開發的過程當中,需要利用遠端 inspect 的功能,才能比較順利地進行下去

chrome_options = Options()
chrome_options.add_argument('--disable-extensions')
chrome_options.add_argument('--disable-gpu')
chrome_options.add_argument('--headless')
chrome_options.add_argument(f'--user-data-dir={args.user_data_dir}')
# chrome_options.add_argument('--remote-debugging-port=9222')
driver = webdriver.Chrome(options=chrome_options)
driver.get(url)  

最後也順便寫了螢幕截圖以及點選 寄送複本 的選項,檢查在送出之前看到的畫面以及確認真的有填到系統當中。

自動地排程判斷時間打卡

在伺服上可以使用下指定的方式自動完成打卡之後,就剩下最後一步了,自動化。
如果是每天都需要打卡的話,其實很簡單使用類似 crontab 的自動排程的工具就可以達成,不過比較不一樣而且有趣的是最開頭有提過

因為分流所以 只有 WFH 那天才會需要填單打卡的

雖然好像可以設計用 到今天的天數 %2 來判斷 group A 或是 group B 是哪幾天需要打,但萬一是週末呢?萬一是放假呢?萬一有天突然想到對調了呢?

為此設計了一個半人工的機制,透過 dates.yaml 的外部檔案來判斷。

update: 2021-06-14
dates:
2021-06-10: B
2021-06-11: A
2021-06-12: N
2021-06-13: N
2021-06-14: N  

接著只要在每天排到的時間執行的時候,重新讀取這個檔案就可以判斷,不需要中斷重新跑。那只要有一個人會定期更新班表就可以了。

def everyday_run(args, punch):
    print(f'Run {punch} {datetime.datetime.now().ctime()}')
    today = datetime.datetime.now().date()
    with open(args.dates) as f:
        dates = yaml.full_load(f)
    if today not in dates['dates']:
        raise ValueError(f'Please update {args.dates}')
    if dates['dates'][today] not in args.group:
        print(f'  Not a WFH day for group {args.group}')
        return
    waits = random.randint(1, 29)
    print(f'  waits {waits} minutes')
    time.sleep(waits * 60)
    print(f'  punch {punch} {datetime.datetime.now().ctime()}')
    punching(args, punch) 

也可以看到避免時間都太剛好,也有加個亂數暫停的機制,另外也有考慮到全遠端的話該如何設定,其實就是同時 group AB 就是。

最後將程式在伺服器上跑起來,觀察看看是不是有正常跑以及有沒有收到複本。目前看起來分流上班好像還會再一陣子,所以看看這個小程式可以被利用多久吧。

yumaokao

Published by
yumaokao

Recent Posts

Invoke Method with JDWP

smali breakpoin...

2 年 ago

tetris3d with plotly

魔術磁力方塊好好玩 魔術磁力方...

3 年 ago

AliasDict, a python dict for alias resolver

用 dict 存 alias ...

3 年 ago

hashcat sha256 from mac address

只給一天期限的憑證檔案 去年幫...

3 年 ago

python rich with asyncio

python rich 畫圖很...

3 年 ago