Golang爬虫小记|Iwrite作业自动提醒

大一上那次因为Iwrite的作文忘记写了,最近在掘金看到了一个Golang的定时任务库,所以打算利用爬虫定时获取一下未完成的作业,部署到云服务器上,并通过邮箱通知我。

先介绍一下爬虫的基本思路

现代web开发中,当用户登陆后,通常服务端会给用户签发一个令牌,这个令牌通常是Token,session或者其他的,可以被服务端验证的一段文本数据,之后的任何api请求都会去验证这个令牌,确保接口不会被滥用,保护用户隐私数据。

需要使用的库

  • Http请求库 Resty:github.com/go-resty/resty/v2
  • 爬虫库 Colly:github.com/gocolly/colly
  • 定时任务库 Cron:github.com/robfig/cron/v3
  • 邮件发送:gopkg.in/gomail.v2

Iwrite是如何实现认证服务的

登录接口

账号密码是明文传输的,并且有一个service字段,应该是使用的CAS认证,这里不过多介绍,因为我也不懂,这个过程并不难模拟,返回的数据中最有价值的就是ST。我们可以通过ST值获取iWSsiD值,相当于上文提到的令牌。

func Login() (St string,err error) {
	client := resty.New()
	loginData := map[string]string{
		"service": "http://iwrite.unipus.cn/system/login",
		"username": "xxxx",
		"password": "xxxx",
	}
	resp, err := client.R().SetBody(loginData).Post(loginUrl)
	if err != nil {
		return "",err
	}

	resStruct := new(AutoGenerated)
	json.Unmarshal([]byte(resp.String()), resStruct)


	return resStruct.Rs.ServiceTicket,nil
}
type AutoGenerated struct {
	Code string `json:"code"`
	Msg  string `json:"msg"`
	Rs   struct {
		GrantingTicket string `json:"grantingTicket"`
		ServiceTicket  string `json:"serviceTicket"`
		TgtExpiredTime int64  `json:"tgtExpiredTime"`
		Role           string `json:"role"`
		Openid         string `json:"openid"`
		Nickname       string `json:"nickname"`
		Fullname       any    `json:"fullname"`
		Username       string `json:"username"`
		Mobile         string `json:"mobile"`
		Email          any    `json:"email"`
		Perms          string `json:"perms"`
		IsSsoLogin     string `json:"isSsoLogin"`
		IsCompleted    any    `json:"isCompleted"`
		OpenidHash     any    `json:"openidHash"`
		Jwt            string `json:"jwt"`
		Rt             string `json:"rt"`
		CreateTime     any    `json:"createTime"`
		Status         int    `json:"status"`
		Links          []struct {
			Rel  string `json:"rel"`
			Href string `json:"href"`
		} `json:"links"`
	} `json:"rs"`
}

获取到我们想要的令牌

我们可以通过ST值获取iWSsiD值,相当于上文提到的令牌,这里需要注意一下禁止302重定向,来拦截Cookie。

const Url = "http://iwrite.unipus.cn/system/login"
classInfos = make([]ClassInfo, 0)
	//获取iWSsiD值
	client := resty.New()
	resp, err := client.SetRedirectPolicy(resty.NoRedirectPolicy()).R().SetQueryParam("ticket", ST).Get(Url)

	if len(resp.Cookies()) < 3 {
		return 0, nil, errors.New("获取iWSsiD值 失败")
	}
	iwssid := resp.Cookies()[2].Value

使用令牌进入用户主页并获取作业

这里我们采用Colly库,可以很方便的获取到指定Id/Class的内容

const writerUrl = "http://iwrite.unipus.cn/student"
c := colly.NewCollector()
	c.OnRequest(func(r *colly.Request) {
		r.Headers.Add("Cookie", "iWSsiD=\""+iwssid+"\"")
	})

	c.OnHTML(".table-top", func(e *colly.HTMLElement) {
		var classInfo ClassInfo
		classInfo.tableName = e.ChildText("h2.table-name")
		classInfo.class = e.ChildText("div.data.date-con.class-name")
		classInfo.time = e.ChildText("div.time_oneLine span")
		classInfos = append(classInfos, classInfo)

	})

	c.OnHTML("#overNoId", func(e *colly.HTMLElement) {
		text := e.Text
		num, _ = strconv.Atoi(text)
	})

	c.Visit(writerUrl)

将获取的数据通过邮箱发送

其中的xxx为你的邮箱密码

func SendEmail(num int, classInfos []ClassInfo) error {
	dialer := gomail.NewDialer(
		"smtp.qq.com",
		465,
		"2945294768@qq.com",
		"xxx",
	)

	m := gomail.NewMessage()
	m.SetAddressHeader("From", "2945294768@qq.com", "hackerxiao")
	m.SetHeader("To", "2945294768@qq.com")
	m.SetHeader("Subject", "Iwrite作业提醒")

	classInfoHTML := ""
	for _, classInfo := range classInfos {
		classInfoHTML += fmt.Sprintf("<p>%s</p><p>%s</p><p>%s</p><br><br>", classInfo.tableName, classInfo.class, classInfo.time)
	}

	body := fmt.Sprintf(`<div>
		<div>
			Iwrite作业提醒 还有%d个作业未提交
		</div>
		<div style="padding: 8px 40px 8px 50px;">
			%s
		</div>
	</div>`,num, classInfoHTML)

	m.SetBody("text/html", body)

	if err := dialer.DialAndSend(m); err != nil {
		return err
	}

	return nil
}

使用Cron定时执行

func main() {
	c := cron.New()
	c.AddFunc("0 18 * * *", func() {
		st, err := iwrite.Login()
		if err != nil {
			fmt.Println("login error")
		}
		num, classINfos, err := iwrite.GetWriter(st)
		if err != nil {
			fmt.Println("GetWriter error", err)
		}

		iwrite.SendEmail(num, classINfos)
	})
	c.Run()
}
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇