1. 前言

2021年10月26日,北大地空学院成立20周年。学院为每一位天地人,准备了一张专属的纪念卡。领取的方式比较简单,关注"北大地空SESS"微信公众号,打开《@北大地空,20岁生日快乐!》,然后按文中的说明即可领取专属的纪念卡。

但由于网站上有一个活动是会给’专属卡号尾号为20’的朋友送上神秘礼物。所以,只能写脚本来实现这一枯燥的过程。

2. 进入活动页面

本来以为需要学习微信小程序来写这个脚本。但后来发现可以直接通过 https://jiema.wwei.cn 来扫描上述公众号文章中的二维码来获得活动界面的网址:https://filec8386ebc7632.v4.h5sys.cn/play/oXCeVHq9 ,然后用Chrome登陆这个网页即可。

3. 网页测试

通过第2步的操作进入页面后,发现通过按住并拖动往上滑可以进入下一个页面,然后在下一页需要点击页面下方的按钮上传图片,图片上传完然后点击确定按钮即可得到专属的纪念卡了。整个过程比较简单,因此可以用代码来实现。

明确需求后,就可以用Python来实现这一过程。首先需要使用selenium这个包,然后还需要下载chromedriverselenium 会通过调用chromedriver来实现利用系统中的Chrome完成一系列的操作。

3.1 基本软件安装

selenium的安装

1
pip install selenium

chromedriver不需要安装,直接通过 https://chromedriver.chromium.org/ 下载对应自己Chrome的版本的exe文件即可。

3.2 登录网页

1
2
3
4
5
6
from selenium import webdriver
# change your own chromedriver path
chrome_driver_path = r'C:\Users\Admin\Desktop\chromedriver.exe'
driver = webdriver.Chrome(chrome_driver_path)
url = 'https://filec8386ebc7632.v4.h5sys.cn/play/oXCeVHq9'
driver.get(url)

3.3 按住并拖动往上滑

这一操作可以通过ActionChains来实现。首先可以先找到要按住的元素。可以通过右键Chrome浏览器选择检查,则会在浏览器的右侧出现一个网页源码界面,需要手动找到对应的组件的代码行,然后可以通过右键该行代码可以复制该组件的xpath等信息。由于这里的组件的class的name是唯一的,这里选择通过find_element_by_class_name来获取该组件。代码如下

1
2
3
4
5
6
from selenium.webdriver.common.action_chains import ActionChains
e = driver.find_element_by_class_name('ih5-icon')
v = -10 # 注意上滑为负号
ActionChains(driver).click_and_hold(e).perform()
ActionChains(driver).move_by_offset(xoffset=0, yoffset=v).perform()
ActionChains(driver).release().perform()

3.4 上传图片

这部分需要控制Chrome找到上传图片的按钮,然后点击该按钮。由于上传图片这个组件具体的代码隐藏在好几层div下面,所以用find_element_by_xpath来找更快一些。

1
2
e = driver.find_element_by_xpath("//*[@id='app']/div/div/div/div/div/div[5]/div")
ActionChains(driver).click(e).perform()

这时,会打开一个windows的选择文件的界面,这是selenium就无法处理这种问题了。需要借助于一些其他的工具。这里我使用的是Autoit工具。其下载链接为:https://www.autoitscript.com/site/autoit/downloads/ 。下载该软件,然后安装和别的windows软件安装的方式一样。

3.4.1 AutoIt Window Info

可以打开最开始的那个网页,然后手动操作至出现上传图片的对话框。这时打开AutoIt Window Info工具, 然后用鼠标拖住工具上的Finder Tool的图标到要识别的对话框上,主要是对话框的标题,以及提交的那个按钮的信息等。

3.4.2 SciTE Script Editor

有了上述信息之后,可以用SciTE Script Editor软件来编写一个脚本,内容如下

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
; if your language of the system is Chinese, change Open to 打开 here
ControlFocus("Open","","Edit1")

WinWait("[CLASS:#32770]","",0)

; if your language of the system is Chinese, change Open to 打开 here
; change the path of your own pic
ControlSetText("Open","","Edit1","C:\Users\Admin\Figure_2.png")

; if your language of the system is Chinese, change Open to 打开 here
ControlClick("Open","","Button1");

3.4.3 Compile Script to .exe

有了上述脚本文件后,我们需要利用Compile Scipt to .exe工具将其编译成exe文件,这样就可以在Python中调用该脚本了。编译操作比较简单,点击Browse选择脚本文件,点击Convert将其转化为exe文件。

3.5 调用exe文件上传图片

这部分比较简单,直接上代码

1
2
3
4
5
6
7
8
import os
import time
# 这里防止上一步操作由于网络卡顿造成延迟,需要停顿一下。这样下面调用exe的时候就不会出现调用了脚本后而网页上还没出现相应的打开文件的界面
time.sleep(3)
myexepath = r'C:\Users\Admin\Desktop\upfile.exe'
os.system(myexepath)
# 因为上传完图片后会进入一个新的网页界面,这是网页的布局有变动,谨慎起见可以停顿一下
time.sleep(3)

3.6 点击确认

这一步的逻辑和前面很像,不再赘述,直接上代码

1
2
3
4
5
elem = driver.find_element_by_xpath("//*[@id='app']/div/div/div/div/div[2]/button")
    
ActionChains(driver).click(elem).perform()
# 这里由于确认之后,系统会真正的上传图片,所以需要停顿几秒
time.sleep(3)

3.7 网页截图

这一步可以调用save_screenshot函数来完成

1
2
3
4
filename = 'sess_anni20'
driver.save_screenshot(f'{filename}.png')

driver.quit()

3.8 重复操作来得到20结尾的专属纪念卡

这一步比较简单,加个循环就行了,一般在深夜运行100次,必定会有一个尾号为20的卡,留给读者自己测试吧。

4 参考资料