钉钉机器人自动回复消息_手摸手打开知乎自动回复功能(Golang 模拟http请求,打造知乎自动回复机器人)...

本文介绍了如何利用Golang模拟HTTP请求,结合钉钉机器人实现知乎私信的自动回复功能。通过分析网页请求,获取必要的cookie和x-xsrftoken,构建发送消息的方法,并在服务器上运行实现持续监控和回复。
摘要由CSDN通过智能技术生成

ddc92b0252e82db86ac2e70d51c4cb40.png

我在知乎发了一篇文章,讲述我是如何根治我的神经性皮炎

p0h5:[06月10日更新]2年神经性皮炎的痊愈历程(已根治剩余药膏免费送)多图预警​zhuanlan.zhihu.com
a3e9b7220fbd0f09134295cd592304bb.png

同时把没用完的药免赠送

但是知乎不能发联系方式,于是很多知乎的病友给我发私信

因为工作的原因,公司内网不方便上知乎

手机也用得少

很多时候,知乎病友发来的消息,要很久才能回复,造成了沟通问题

于是考虑能不能自动回复知乎的私信,让病友通过微信交流

分析一波网页请求先

3d2dee9941828991a331014eb1359f31.png
网页请求内容

可以看到,知乎采用的是后端渲染,我们可以直接抓html的内容

首选,我们构造一下请求

这里选用了ghttp这个库

github.com/gogf/gf/g/net/ghttp

package main

import (
	"github.com/gogf/gf/g/net/ghttp"



var req *ghttp.Client


func init()  {
	req=ghttp.NewClient()
}

func main() {
	req.SetHeader("user-agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.80 Safari/537.36")
	req.SetHeader("referer", "https://www.zhihu.com/inbox")
	req.SetHeader("upgrade-insecure-requests","1")
	req.SetHeader("Pragma","no-cache")
	res, _ :=req.Get("https://www.zhihu.com/inbox")
	defer  res.Close()
	fmt.Println(res.ReadAllString())
}

构造一个client,并初始化,加入响应,可以看到,成功响应,但是这是未登陆状态,那么还有一个关键,就是cookie

<!doctype html>
<html lang="zh" data-hairline="true" data-theme="light">
<head>
<meta charSet="utf-8"/>
<title data-react-helmet="true">知乎 - 有问题,上知乎</title>
<meta nport" content="width=device-width,initial-scale=1,maximum-scale=1"/>
<meta name="renderer" content="webkit"/><meta name="force-rendering" content="webkit"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
<meta name="google-site-verification" content="FTeR0c8arOPKh8c5DYh_9uu98_zJbaWw53J-Sch9MTg"/>
<meta name="description" property="og:description" content="有问题,上知乎xxxx"/>
<link rel="shortcut icon" type="image/x-icon" href="https://static.zhihu.com/static/favicon.ico"/>
<link rel="search" type="aensearchdescription+xml" href="https://static.zhihu.com/static/search.xml" title="知乎"/>

现在加入cookie,我们从浏览器拿到的cookie是字符串,需要构造成map

func cookiestringtomap(str string) map[string]string {
	ck:=make(map[string]string)
	str=strings.ReplaceAll(str," ","")
	items:=strings.Split(str,";")
	for _, item := range items {
		v:=strings.Split(item,"=")
		ck[v[0]]=v[1]
	}
	return ck
}

带cookie请求的代码如下

package main

import (
	"fmt"
	"github.com/gogf/gf/g/net/ghttp"
	"strings"
)


var req *ghttp.Client

const COOKIE  = `从网页复制的cookie`


func init()  {
	req=ghttp.NewClient()
}

func main() {
	req.SetHeader("user-agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.80 Safari/537.36")
	req.SetHeader("referer", "https://www.zhihu.com/inbox")
	req.SetHeader("upgrade-insecure-requests","1")
	req.SetHeader("Pragma","no-cache")
	req.SetCookieMap(cookiestringtomap(COOKIE))
	res, _ :=req.Get("https://www.zhihu.com/inbox")
	defer  res.Close()
	fmt.Println(res.ReadAllString())
}


func cookiestringtomap(str string) map[string]string {
	ck:=make(map[string]string)
	str=strings.ReplaceAll(str," ","")
	items:=strings.Split(str,";")
	for _, item := range items {
		v:=strings.Split(item,"=")
		ck[v[0]]=v[1]
	}
	return ck
}

请求结果如下,可以发现,登陆状态已经正常:

<a href="/people/p0h5">
<i class="zg-icon zg-icon-dd-home"></i>我的主页
</a>
</li>

<li>
<a href="/inbox">
<i class="zg-icon zg-icon-dd-pm"></i>私信
<span id="zh-top-nav-pm-count" class="zu-top-nav-pm-count zg-noti-number"
style="visibility:hidden" data-count="0">

</span>
</a>

现在开始发送私信,并抓包,写发私信的方法

0d045b682297fffc9d2e5d5d23cc1a8c.png

可以看到,发送私信,需要message_id,content,type三个参数,我们来找一找

通过分析网页发现

4c662bba6335cecbdac33958b25a733a.png

message_id,type都有了,content就是内容

开始构造发消息方法

func SendMsg(msgid string,content string) int {
	req.SetHeader("x-requested-with","XMLHttpRequest")
	res,err:=req.Post("https://www.zhihu.com/inbox/reply",g.Map{"message_id":msgid,"content":content,"type":"common"})
	if err!=nil{
		log.Println(err.Error())
		return 0
	}
	defer res.Close()
	return res.StatusCode
}

开始运行,走你

SendMsg("1123902504945291264","测试测试")

得到返回
<html><title>403: Forbidden</title><body><h1>403: Forbidden</h1></body></html>

什么鬼,403???不允许我发?

仔细在查看网页请求

原来还有一个x-xsrftoken的请求头,参数从哪儿来的呢?

发现有两个地方可以拿到token

一个是cookie,一个是网页中

c41b9b0209362624b2950119a71bcd94.png

2cf5f0306b817d88a83ce3159dd127a3.png

我决定从网页中拿,同时把最后回复的那个id拿到

这里用到了goquery这个库,来取网页信息

func GetLastIdandToken() (err error,lastid string,token string)  {
	res,err:=req.Get("https://www.zhihu.com/inbox")
	if err!=nil{
		return err,"",""
	}
	defer 	res.Close()
	doc, err := goquery.NewDocumentFromReader(res.Body)
	if err != nil {
		return err,"",""
	}
	lastid = doc.Find("#zh-pm-item-wrap").Find(".zm-pm-item").AttrOr("data-token","")
	token = doc.Find("input[name='_xsrf']").AttrOr("value","")
	return
}

21aca2576108ee55fc3d48300c384fa0.png

ok ,拿到最新的ID和token

接下来在main函数获取启动参数,cookie和最新的消息id

	if len(os.Args)<3{
		log.Println("启动参数为 ./xxx cookie lastid")
		os.Exit(0)
	}
	argcook:=os.Args[1]
	arglastid:=os.Args[2]

再构建一个循环,来不停处理消息

最终代码如下:

package main

import (
	"github.com/PuerkitoBio/goquery"
	"github.com/gogf/gf/g"
	"github.com/gogf/gf/g/net/ghttp"
	"log"
	"math/rand"
	"os"
	"strings"
	"time"
)

var req *ghttp.Client


func init()  {
	req=ghttp.NewClient()
}

func main()  {
	if len(os.Args)<3{
		log.Println("启动参数为 ./xxx cookie lastid")
		os.Exit(0)
	}
	argcook:=os.Args[1]
	arglastid:=os.Args[2]
	req.SetHeader("user-agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.80 Safari/537.36")
	req.SetHeader("referer", "https://www.zhihu.com/inbox")
	req.SetHeader("upgrade-insecure-requests","1")
	req.SetHeader("Pragma","no-cache")
	req.SetCookieMap(cookiestringtomap(argcook))
	req.BrowserMode(true)
	for {
		err,lasid,token:=GetLastIdandToken()
		if err!=nil {
			log.Println(err.Error())
			break
		}
		if lasid!=arglastid {
			log.Println("find new msgid,need reply")
			time.Sleep(2 *time.Second)
			code:=SendMsg(lasid,"你好,xxxxxx" ,token)
			if code==200{
				time.Sleep(2 *time.Second)
				err,lasid,token=GetLastIdandToken()
				if err!=nil {
					log.Println(err.Error())
					break
				}
				if lasid!="" && lasid!=arglastid {
					log.Println("send msg success!","set last id",lasid)
					arglastid=lasid
				}
			}else {
				log.Println("send msg error!",code)
			}
		}
		x:=Getrandom(20)
		//log.Println("等待",x,"秒后继续刷新")
		time.Sleep(time.Second * time.Duration(x))
	}

}

func cookiestringtomap(str string) map[string]string {
	ck:=make(map[string]string)
	str=strings.ReplaceAll(str," ","")
	items:=strings.Split(str,";")
	for _, item := range items {
		v:=strings.Split(item,"=")
		ck[v[0]]=v[1]
	}
	return ck
}

func GetLastIdandToken() (err error,lastid string,token string)  {
	//log.Println("开始请求....")
	res,err:=req.Get("https://www.zhihu.com/inbox")
	if err!=nil{
		return err,"",""
	}
	defer 	res.Close()
	doc, err := goquery.NewDocumentFromReader(res.Body)
	if err != nil {
		return err,"",""
	}
	lastid = doc.Find("#zh-pm-item-wrap").Find(".zm-pm-item").AttrOr("data-token","")
	token = doc.Find("input[name='_xsrf']").AttrOr("value","")
	//log.Println("lastid=",lastid,"    token=",token)
	return
}

func SendMsg(msgid string,content string,token string) int {
	//log.Println("开始发送消息...")
	req.SetHeader("x-requested-with","XMLHttpRequest")
	req.SetHeader("x-xsrftoken",token)
	res,err:=req.Post("https://www.zhihu.com/inbox/reply",g.Map{"message_id":msgid,"content":content,"type":"common"})
	if err!=nil{
		log.Println(err.Error())
		return 0
	}
	defer res.Close()
	//log.Println(res.ReadAllString())
	return res.StatusCode
}

func Getrandom(max int) int64 {
	rand.Seed(time.Now().Unix())
	return int64(rand.Intn(max))
}

编译,压缩,走起

95e9340f9eba7a1cfedccbe35ae9acd3.gif

完事上传服务器并启动

./zhihu.min cookiexxxxxxxxxxxxx 最新的消息id

be1b47d652c3af3a506655e38b1885b0.png

服务器上跑起来OK

现在再次测试

4e1f974bd1b816c9c3f1671a7409394c.gif

现在的逻辑是,不断刷新消息列表,如果本次请求的最新id和上一次不一样,则给最新的消息发送一个消息,所以我自己发了消息,也会得到自动回复。

全文完,上面代码可以直接复制粘贴跑起来

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值