python+selenuim實現web自動打卡
阿新 • • 發佈:2022-01-17
python+selenuim實現web自動打卡
摘要:
大概就是在XX背景下,需要每天登入網站填報體溫,所在地資訊等,分析登入時傳送請求邏輯,通過python-selenium實現自動打卡。
思路
通過selenium操作瀏覽器,完成登入->填充表單資訊->定時重複打卡。
- 登入: 使用機器完成登入有兩種方法,一種通過定位驗證碼位置通過ocr識別字符,登入後儲存cookie,之後往瀏覽器中填入cookie即可跳過登入, 其次就是手動維護cookie。分析得到當發起登入請求時,客戶端將生成隨機字串塞入Request-Header的cookie中,
ASP.NET_SessionId=ryhrbiqalg14hgrxhmhd4ie5
CenterSoftWeb=xxxxx; expires=Sun, 23-Jan-2022 07:45:06 GMT; path=/; HttpOnly
,由此組成完整的可跳過登入的cookie - 填充表單資訊 通過selenium操作瀏覽器中元素,完成一系列邏輯操作,(需要下載瀏覽器所對應的驅動driver,chrome+chromedriver)
- 定時重複打卡 Crontab+shell 即可實現每日定時啟動
關於selenium-python,請到網站檢視
具體實現
定位驗證碼位置,由機器識圖,首先啟動操作selenium在當前執行環境下獲取瀏覽器截圖,再將圖片匯入ps中定位驗證碼四角位置畫素值。
獲取到四角位置時,即可儲存驗證碼圖片傳入ocr機器識別。
#儲存截圖 browser.save_screenshot('verification/'+stunumber+'.png') #填入資訊 browser.find_element_by_id("StudentId").send_keys(stunumber) browser.find_element_by_xpath("/html/body/div[1]/div[2]/div/div[2]/form/div[2]/div[2]/input").send_keys(pwd) #圖片剪下 left = 781 top = 336 right = 870 bottom = 369 picture = Image.open('verification/'+stunumber+'.png') picture = picture.crop((left, top, right, bottom)) picture.save('verification/'+stunumber+'-ed.png') #ocr識別 接入的是api yzm_code = moyunocr.getYzm('verification/'+stunumber+'-ed.png') #獲取cookie寫入檔案 dictCookies = browser.get_cookies() jsonCookies = json.dumps(dictCookies) with open('cookies/'+stunumber+'_cookie.txt', 'w') as f: f.write(jsonCookies)
儲存的cookie內容
ps:獲取到得Cookie通過json庫物件轉為文字了,因此格式與官方定義的cookie格式略有差別。
[
{"domain": "dxg.cxxu.edu.cn", "expiry": 1615705350, "httpOnly": true, "name": "CenterSoftWeb", "path": "/", "secure": false, "value": "08CBB2BBDCB3E268D3EE9D0C8046B4C979910509ACF95A1F302336B2826DCAD9CE60311213F70E114CAF84ED18695CB3C6260D17B502F8D42ADC8966B6886C5C78D8B479AC5F152E8CC526E9517C1CF3783D3462632A5EDC0104C19C58AFCE9B020937BD766C253F8A327AE72F11F5ECD4F91E72021B3ECC9C7232BFBCAEF0BA38ACD4246EA9CD293CD7ADFD1BC682DF7FEB194CB8E433804D93B3CF00B299E55DA5530BF7D32523977316BAF9486DBAB85221C5348E587F05220BC9A44EE8901C33ADD15097D87E8305C0FEF8A4A3B9D2B358172EA280D622DE78B53CAE5EE88379B2600F38740BD2D33CFC0192CCD9B2DCE5C8BE4124A4466623C8A96B2499B25C16C9EA128D19C88BA0FD8BC4746F"},
{"domain": "dxg.cxxu.edu.cn", "httpOnly": true, "name": "ASP.NET_SessionId", "path": "/", "secure": false, "value": "qe45ulzkfahnqjvvexj45kcr"}
]
What Cookie
基於HTTP協議本身是無狀態的,無法辨別每次的請求是否由同一個使用者發起,因此可以通過在每次請求頭中放入可識別狀態的資訊。由此引生出cookie與token等兩種身份驗證方式,可簡單理解為 身份識別器。
Cookie發起請求時存在於Request-Header中。
格式:
cookie為一組 name=value形式的資料並以';'分割的列表 例:PHPSESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43; _gat=1
,
What Set-Cookie
Set-Cookie HTTP響應頭用於將Cookie從伺服器傳送到使用者代理,以便使用者代理稍後可以將其傳送回伺服器。要傳送多個Cookie,應在同一響應中傳送多個Set Cookie頭
Attributes屬性
屬性項 | 描述 | 是否必須 |
---|---|---|
cookie-name=cookie-value | name自定但要唯一,value依據業務存值 | 是 |
Expires=date | 1.cookie的最長生存期,2.不設定則是會話cookie 3.截止日期與設定cookie的客戶端相關,過期刪除 | 否 |
Max-Age=number | 類似Expires但優先順序比Expires高 | 否 |
Domain=domain-value | 1.定義接收cookie的主機 2.[.example.com]寫法包含子級域名但可能被忽略 3. | 否 |
Path=path-value | 1.cookie生效路徑 URL中必須存在的路徑 2. | 否 |
Secure | 只有在用https進行請求時才將cookie傳送到伺服器 | 否 |
HttpOnly | 禁止JavaScript訪問cookie | 否 |
SameSite=samesite-value | 控制cookie是否隨跨源請求一起傳送 可選[Strict(禁止跨域),Lax(在使用者從外部網站導航到原網站時傳送cookie,預設 ),None(允許跨域,同時設定Secure)] |
否 |
請求攜帶Cookie
with open('cookies/'+stunumber+'_cookie.txt', 'r', encoding='utf8') as f:
listCookies = json.loads(f.read())
# 往browser裡新增cookies
for cookie in listCookies:
cookie_dict = {
'domain': '.mnnu.edu.cn',
'name': cookie.get('name'),
'value': cookie.get('value'),
"expires": '',
'path': '/',
'httpOnly': False,
'HostOnly': False,
'Secure': False
}
browser.add_cookie(cookie_dict)
browser.refresh()
Linux下selenium配置
前提:由於linux瀏覽器無法介面化,因此在初始化browser時需要額外指定配置
chrome_options = webdriver.ChromeOptions()
# 無頭模式
chrome_options.add_argument('--headless')
# 禁用GPU加速
chrome_options.add_argument('--disable-gpu')
browser = webdriver.Chrome(chrome_options=chrome_options, executable_path='/root/chromedriver')
#全域性隱式等待時間
browser.implicitly_wait(10)
指令碼監聽cookie過期
遍歷指定資料夾下cookie檔案的最後一次修改時間與現在時間的間隔,當間隔超過6天時郵件提醒更新
SIX_DAY_SECONDS=6*24*60*60
SEVEN_DAY_SECONDS=7*24*60*60
def listFile(rootpath):
todayStamp = time.time()
todayTime = dateFormat(todayStamp)
logging.info("==========="+todayTime+"====START====")
fileList = os.listdir(rootpath)
email_msg =""
for i in range(0,len(fileList)):
fullpath = os.path.join(rootpath,fileList[i])
# 判斷是否是檔案
if os.path.isfile(fullpath):
# 獲取最後修改日期
lastTimeStamp = os.path.getmtime(fullpath)
# 相差秒數
diffSeconds = daysDiff(todayStamp,lastTimeStamp)
if SEVEN_DAY_SECONDS-diffSeconds <=0:
logging.info(stunumber+ "您的cookie已經過期")
if diffSeconds<=SEVEN_DAY_SECONDS :
if diffSeconds>=SIX_DAY_SECONDS :
logging.info(stunumber+"您的cookie即將過期 有效時間還剩:"+str((SEVEN_DAY_SECONDS-diffSeconds)//3600)+"小時")
# 傳送郵件提醒
email_msg+=stunumber+"您的cookie即將過期 有效時間還剩:"+str((SEVEN_DAY_SECONDS-diffSeconds)//3600)+"小時\n"
else:
logging.info(stunumber+"您的cookie有效時間還剩:"+str((SEVEN_DAY_SECONDS-diffSeconds)//3600)+"小時")