背景
需要给很多个用户发同样的私信时需要大量重复工作,如果能自动发送私信就能节省很多人力
难点分析
- chrome各端如何相互通信
- 私信怎么发给不同人
- 怎么发送私信
chrome插件怎么开发,各端如何通信
参照<font color=blue>这篇博客</font>,非常详细
私信怎么发给不同人
在网页微博中可以发现点击私信一个陌生人后,会跳转到一个私信窗口,此时url中是携带一个用户uid的,根据这个uid我们通过跳转url来实现给不同用户发私信
怎么发送私信
- 在inject-script中选中输入框
- 给输入框赋值value
- 用js触发敲击空格事件
- 用js触发敲击回车事件
- 需要触发空格事件的原因:单纯赋值并不能触发onChange事件,导致回车不能将消息发出去,触发回车后即可
- 第二步到第四步必须依次触发,键盘io是异步的,所以可以使用定时器控制
inject-script
用途:获取dom,发送私信
function fireKeyEvent(el, evtType, keyCode){
var doc = el.ownerDocument,
win = doc.defaultView || doc.parentWindow,
evtObj;
if(doc.createEvent){
if(win.KeyEvent) {
evtObj = doc.createEvent('KeyEvents');
evtObj.initKeyEvent( evtType, true, true, win, false, false, false, false, keyCode, 0 );
}
else {
evtObj = doc.createEvent('UIEvents');
Object.defineProperty(evtObj, 'keyCode', {
get : function() { return this.keyCodeVal; }
});
Object.defineProperty(evtObj, 'which', {
get : function() { return this.keyCodeVal; }
});
evtObj.initUIEvent( evtType, true, true, win, 1 );
evtObj.keyCodeVal = keyCode;
if (evtObj.keyCode !== keyCode) {
console.log("keyCode " + evtObj.keyCode + " 和 (" + evtObj.which + ") 不匹配");
}
}
el.dispatchEvent(evtObj);
}
else if(doc.createEventObject){
evtObj = doc.createEventObject();
evtObj.keyCode = keyCode;
el.fireEvent('on' + evtType, evtObj);
}
}
function sendText() {
const target = document.querySelector('#webchat-textarea')
let textTimer
if (target) {
clearTimeout(textTimer)
target.value = 'xxx'
setTimeout(() => {
target.focus()
fireKeyEvent(target, 'keydown', 8)
setTimeout(() => {
fireKeyEvent(target, 'keydown', 13)
}, 1000)
}, 1000)
} else {
textTimer = setTimeout(() => {
sendText()
}, 200)
}
}
setTimeout(() => {
sendText()
}, 0)
content-script
用途:注入inject-script,可以与popup.js做通信
function injectCustomJs(jsPath) {
jsPath = jsPath || 'js/inject.js'
var temp = document.createElement('script')
temp.setAttribute('type', 'text/javascript')
temp.src = chrome.extension.getURL(jsPath)
temp.onload = function () {
this.parentNode.removeChild(this)
}
document.head.appendChild(temp)
}
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min
}
function Toast(msg, duration) {
duration = isNaN(duration) ? 3000 : duration
var m = document.createElement('div')
m.innerHTML = msg
m.style.cssText =
'max-width:60%;min-width: 150px;padding:0 14px;height: 40px;color: rgb(255, 255, 255);line-height: 40px;text-align: center;border-radius: 4px;position: fixed;top: 50%;left: 50%;transform: translate(-50%, -50%);z-index: 999999;background: rgba(0, 0, 0,.7);font-size: 16px;'
document.body.appendChild(m)
setTimeout(function () {
var d = 0.5
m.style.webkitTransition =
'-webkit-transform ' + d + 's ease-in, opacity ' + d + 's ease-in'
m.style.opacity = '0'
setTimeout(function () {
document.body.removeChild(m)
}, d * 1000)
}, duration)
}
window.addEventListener('load', function() {
injectCustomJs()
})
let timer
let sendTimer
let uidArr = []
let interval
let initinterval
let status = ''
chrome.extension.onMessage.addListener(function (
request,
sender,
sendResponse
) {
if (request.cmd == 'start') {
Toast('已开始发私信', 2000)
uidArr = request.uids
initinterval = request.interval
interval = (+request.interval + getRandomInt(1, 5)) * 1000
status = 'start'
timer = setInterval(() => {
if (uidArr.length) {
window.open(
`https://api.weibo.com/chat/#/chat?to_uid=${uidArr[0]}&source_from=9`,
'_blank'
)
uidArr.shift()
sendResponse('recived')
} else {
clearInterval(timer)
}
}, interval)
}
if (request.cmd == 'stop') {
status = 'stop'
Toast('已结束发私信', 2000)
clearInterval(timer)
}
if (request.cmd == 'continue') {
status = 'continue'
Toast('已继续发私信', 2000)
timer = setInterval(() => {
if (uidArr.length) {
window.open(
`https://api.weibo.com/chat/#/chat?to_uid=${uidArr[0]}&source_from=9`,
'_blank'
)
uidArr.shift()
sendResponse('recived')
} else {
clearInterval(timer)
}
}, interval)
}
})
sendTimer = setInterval(() => {
chrome.extension.sendMessage(
{ greeting: uidArr, status: status, interval: initinterval },
function (response) {
// console.log('收到来自后台的回复:' + response);
}
)
}, 1000)
if (status === 'stop') {
clearInterval(sendTimer)
}
index.html
用途:点击插件后弹框的结构样式
manifest.json
用途:各种配置项,详情见上文博客
popup-script
用途:index.html的js文件,在index.html中引入,可以做一些事件监听,dom操作的事情
let uidArr = []
let interval = 30
function sendMessageToContentScript(message, callback) {
chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) {
chrome.tabs.sendMessage(tabs[0].id, message, function (response) {
if (callback) callback(response)
})
})
}
document.querySelector('#start').addEventListener('click', function () {
uidArr = document.querySelector('#list').value.split(/\n|\r/)
interval = document.querySelector('#interval').value
sendMessageToContentScript(
{ cmd: 'start', uids: uidArr, interval: interval },
function (response) {
console.log('来自content的回复:' + response)
}
)
})
document.querySelector('#stop').addEventListener('click', function () {
if (document.querySelector('#stop').innerHTML === '停止') {
document.querySelector('#stop').innerHTML = '继续'
sendMessageToContentScript({ cmd: 'stop' }, function (response) {
console.log('来自content的回复:' + response)
})
} else {
document.querySelector('#stop').innerHTML = '停止'
sendMessageToContentScript({ cmd: 'continue' }, function (response) {
console.log('来自content的回复:' + response)
})
}
})
chrome.extension.onMessage.addListener(function (
request,
sender,
sendResponse
) {
if (request.greeting.length) {
document.querySelector('#list').value = request.greeting.join('\n')
}
if (request.status && request.status === 'stop') {
document.querySelector('#stop').innerHTML = '继续'
}
if (request.status && request.status === 'continue') {
document.querySelector('#stop').innerHTML = '停止'
}
if (request.interval) {
document.querySelector('#interval').value = request.interval
}
})
源码地址
https://github.com/chuheji/weibo-sendMessage-Chromextension/tree/master
后记
这个插件是半年前开发的,当时水平有限,代码比较粗糙,见谅