来源网站:JavaScript实现模拟登录 – WhiteNight's Site
2023年6月1日
最近在搞爬取深圳技术大学的教务系统,搞定之后做个笔记。
实际上搞定模拟登录之后后面的就很简单了,只剩下爬课表和转json要处理。
前置准备与puppeteer包
A high-level API to control headless Chrome over the DevTools Protocol
官方描述上面的英文就是,这里直接说该怎么用。
首先导入需要的npm包,然后准备好账号和密码,以及登录界面的Url。这里深圳技术大学教务系统的html为例。
const puppeteer = require('puppeteer');
const fs = require('fs');
const loginUrl = 'https://auth.sztu.edu.cn/idp/authcenter/ActionAuthChain?entityId=jiaowu';
const targetUrl = 'https://jwxt.sztu.edu.cn/jsxsd/framework/xsMain.htmlx';
const username = 'xxxxxxxxxxx';
const password = 'xxxxxxxxxxx';
准备好之后,通过puppeteer包中方法实现模拟浏览器和打开页面。由于像学校教务系统这些经常需要内网,挂着或者外网环境时通常无法访问。所以建议用try-catch接收异常方便后面调试。同时记得自己先尝试访问教务系统的登录界面,看看能不能打开再进行后续测试。
const puppeteer = require('puppeteer');
const fs = require('fs');
const loginUrl = 'https://auth.sztu.edu.cn/idp/authcenter/ActionAuthChain?entityId=jiaowu';
const targetUrl = 'https://jwxt.sztu.edu.cn/jsxsd/framework/xsMain.htmlx';
const username = 'xxxxxxxxxxx';
const password = 'xxxxxxxxxxx';
async function simulateLogin() {
try {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto(loginUrl);
} catch (error) {
console.error('登录失败:', error);
}
}
simulateLogin();
然后想想还需要些啥?模拟登录,说白了还是“登录”。
一般的登录流程:
更详细的登录流程:
我们现在完成了第一步。接下来就是为当前网页的account和password赋值。
直接右键“检查”输入账号和密码的文本框,以深圳技术大学的教务系统为例
这里“检查”的是账号的输入框,可以发现它的nameh和id为”j_username”。有name或者id就好办了,直接检索当前页面各元素,然后给它赋值即可。密码同理,直接放上代码
const puppeteer = require('puppeteer');
const fs = require('fs');
const loginUrl = 'https://auth.sztu.edu.cn/idp/authcenter/ActionAuthChain?entityId=jiaowu';
const targetUrl = 'https://jwxt.sztu.edu.cn/jsxsd/framework/xsMain.htmlx';
const username = 'xxxxxxxxxxx';
const password = 'xxxxxxxxxxx';
async function simulateLogin() {
try {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto(loginUrl);
await page.type('input[name="j_username"]', username);
await page.type('input[name="j_password"]', password);
} catch (error) {
console.error('登录失败:', error);
}
}
simulateLogin();
模拟登录
探讨是否需要跳转网页
现在还差最后一步–模拟点击按钮。
但真的需要去“点击”按钮吗?很明显不需要。按钮只是为了触发响应事件做的,说明你并不需要去“点击”按钮,直接触发它的响应事件即可。
但是既然用了puppeteer包,那不如直接模拟点击按钮,明显省事的多。上面只是提供一种可行的思路,因为有些事件不是通过
当然,对于我学校的教务来说,点击按钮后直接就跳转到了教务界面。然后其他所有的操作都是动态加载的,即全部都在同一个url链接上完成加载。举个例子
但是,假设你和我一样在爬自己学校的课表。但是你的课表页面和登录后的界面是分开的。例子如下
那么就可以分为两种情况。如果你的情况和我一样,可以写跳转,也可以不写。虽然我个人还是建议写个跳转以防万一。
如果是第二种情况,那我强烈建议写跳转。不然又要写一堆模拟点击按钮的操作。而且有些网页的响应事件不是通过button组件触发的,这种情况下你需要检索整个网页的html去“手动”触发响应事件。很明显超级麻烦。所以不如直接跳转到课表界面。
还是以深圳技术大学的教务为例,代码如下
const puppeteer = require('puppeteer');
const fs = require('fs');
const loginUrl = 'https://auth.sztu.edu.cn/idp/authcenter/ActionAuthChain?entityId=jiaowu';
const targetUrl = 'https://jwxt.sztu.edu.cn/jsxsd/framework/xsMain.htmlx';
const username = 'xxxxxxxxxxx';
const password = 'xxxxxxxxxxx';
async function simulateLogin() {
try {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto(loginUrl);
await page.type('input[name="j_username"]', username);
await page.type('input[name="j_password"]', password);
await page.waitForNavigation();
// 如果想写跳转,保留这一行
await page.goto(targetUrl);
// 由于网速不同,建议自行设置等待时间以保证页面完全加载
await page.waitForTimeout(2000);
} catch (error) {
console.error('登录失败:', error);
}
}
simulateLogin();
接下来就是获取课表的html然后继续些什么字符串分割啊,正则表达式处理啊,划分后保存到json文件里啥的操作了。
写者注
和群友讨论的时候,讨论到我们学校的课表界面有个按钮,触发后就是直接把excel形式的课表保存到本地。用这种方式获取课表是最方便的。如果不需要后续数据处理的话可以试着直接保存为excel。
不过这种方法对于需要后续数据处理的有个问题。保存的路径是浏览器的下载路径,没法自定义。即使能自定义,这意味着我后续操作需要多一步获取文件路径的方法。而自动获取路径那是超级,超级麻烦的一件事。100个用户有99个的路径不一样,有英文有中文,有自定义有默认的。
当然,可以让用户通过filepicker去手动选择文件。但这种操作你仔细想一下就会发现,后续会出现很多修改或者实现起来超级麻烦的地方(比如学校给excel的命名规则改了;用户重复导入的话要保留这次导入的,然后把上一次导入的excel文件删了;如果上次导入的文件用户打开了在后台挂着,导致这个文件变为“只读”,你无法删除它;)。
当然并不是说无法实现,只是不建议这么做。如果我是用户我肯定希望我需要手动操作的地方越少越好。
所以最后还是选择了直接把课表网页的html保存下来,对html作操作的方法。这样保存的html直接在JavaScript程序的根目录下,操作起来还是很方便的。
标签:Javascript, 爬虫