node-weibo-simulation-api
Version:
166 lines (162 loc) • 5.95 kB
JavaScript
// 模拟登录微博,并保存cookie备用
;
const request = require('request');
const fs = require('fs');
const querystring = require('querystring');
const encodePostData = require('./encode_post_data.js');
const readline = require('readline');
const {NEED_PIN} = require('../constans/code');
const url = require('url')
class weiboLogin {
constructor(userName, userPwd,onNeedPinCode) {
// 初始化一些登录信息
// 用户名
this.userName = userName;
// 密码
this.userPwd = userPwd;
// 预登陆地址,不带base64编码后的用户名,用于获取登录信息
this.preLoginUrl = "http://login.sina.com.cn/sso/prelogin.php?entry=weibo&checkpin=1&callback=sinaSSOController.preloginCallBack&rsakt=mod&client=ssologin.js(v1.4.18)";
// 登录的网页地址
this.loginUrl = "http://login.sina.com.cn/sso/login.php?client=ssologin.js(v1.4.18)";
// 初始化预登陆数据为空
this.preLoginData = '';
// 初始化验证码为空
this.pinCode = null;
this.onNeedPinCode = onNeedPinCode || function(){};
// 登录状态
// this.loginStatus = 0;
};
async init() {
// 初始化预登陆url,加上base64编码的用户名
this.encodePreLoginUrl();
try {
// 获取预登陆原始数据
let preLoginInitData = await this.getPreLoginData();
// 解析预登陆原始数据
this.preLoginData = await this.parsePreLoginData(preLoginInitData);
// 是否需要验证码
if(this.preLoginData['showpin'] == 1) {
return new Promise((resolve,reject)=>{
let codeUrl = this.getPinImg();
let codeKey = url.parse(codeUrl,true).query.p;
this.onNeedPinCode({
codeKey,
codePictureUrl:codeUrl,
callback:async (code)=>{
// console.log('回调验证码code',code);
this.pinCode = code;
try {
var responseBody = await this.postData();
var finnalLoginUrl = await this.getFinnalLoginUrl(responseBody);
} catch (error) {
return reject(error)
}
return resolve(this.getCookies(finnalLoginUrl));
}
})
})
}
try {
var responseBody = await this.postData();
var finnalLoginUrl = await this.getFinnalLoginUrl(responseBody);
} catch (error) {
return Promise.reject(error)
}
return this.getCookies(finnalLoginUrl);
} catch(err) {
return Promise.reject(err);
}
}
// preLoginUrl构造,加上base64编码的用户名
encodePreLoginUrl() {
let encodeUserName = encodePostData.encryptUserName(this.userName);
this.preLoginUrl = this.preLoginUrl + `&su=${encodeUserName}`;
}
// 获取预登录数据
getPreLoginData() {
return new Promise((resolve, reject) => {
request(this.preLoginUrl, function (error, response, body) {
if (!error && response.statusCode == 200) {
resolve(response.body);
} else {
reject('没有获取到预登录数据');
}
});
});
}
// 解析获取到的预登录数据
parsePreLoginData(data) {
return new Promise((resolve, reject) => {
let reg = /\((.*)\)/;
let preLoginData = JSON.parse(reg.exec(data)[1]);
if(preLoginData) {
resolve(preLoginData);
} else {
reject('没有获取到json');
}
})
};
// 如果有验证码则要输入验证码
getPinImg() {
// 构造验证码的url
let pinImgUrl = `http://login.sina.com.cn/cgi/pin.php?r=${Math.floor(Math.random() * 1e8)}&s=0&p=${this.preLoginData['pcid']}`;
return pinImgUrl;
// request(pinImgUrl).pipe(fs.createWriteStream('./pinCode.png'));
}
// post数据到服务器
postData(pinCode) {
let headers = {
"User-Agent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:48.0) Gecko/20100101 Firefox/48.0",
'Accept-Language': 'zh-cn',
'Content-Type':'application/x-www-form-urlencoded',
'Connection': 'Keep-Alive'
};
let encodeBody = encodePostData.encodePostData(this.userName, this.userPwd, this.preLoginData.servertime,
this.preLoginData.nonce, this.preLoginData.pubkey, this.preLoginData.rsakv, this.pinCode, this.preLoginData['pcid']);
let options = {
method: 'POST',
url: this.loginUrl,
headers: headers,
body: encodeBody,
gzip: true
};
return new Promise((resolve, reject) => {
request(options, (error, response, body) => {
if (!error && response.statusCode == 200) {
response.setEncoding('utf-8');
resolve(response.body);
}else{
reject(response.body)
}
})
})
}
// 获取最终重定向后的地址
getFinnalLoginUrl(responseBody) {
return new Promise((resolve, reject) => {
let reg = /location\.replace\((?:"|')(.*)(?:"|')\)/;
let loginUrl = reg.exec(responseBody)[1];
let parseLoginUrl = querystring.parse(loginUrl);
if(parseLoginUrl.retcode == 0) {
resolve(loginUrl);
} else if (parseLoginUrl.retcode == 101){
reject("登录失败,登录名或密码错误");
} else if (parseLoginUrl.retcode == 2070){
return reject("登录失败,验证码错误");
} else {
reject("未知错误");
}
});
}
// 获取cookie
getCookies(finnalLoginUrl) {
return new Promise((resolve, reject) => {
let j = request.jar();
request.get({url: finnalLoginUrl, jar: j}, function (error, reponse, body) {
let cookies = j.getCookieString(finnalLoginUrl);
resolve(cookies);
})
})
}
}
exports.weiboLogin = weiboLogin;