Golang配合QQ机器人获取Pixiv ea7e6c5a5f673669f0d56d8f39056eae每日列表并发送涩图(未完)

T O D O \color{#EE2C2C}{TODO} TODO
− 优 化 命 令 , 增 加 u r l 缓 存 \color{#6495ED}{-优化命令,增加url缓存} url
− 开 放 随 机 s e t u 和 检 索 功 能 \color{#6495ED}{-开放随机setu和检索功能} setu

根据分析好的安卓App Pivix用户登录和获取图片api的response来编写解析json需要的结构体

package fvckPixiv

type UserProfileImageUrls struct {
     
	Px16x16   string `json:"px_16x16"`
	Px170x170 string `json:"px_170x170"`
	Px50x50   string `json:"px_50x50"`
}

type PixOAuthHandler struct {
     
	Account                 string                 `json:"account"`
	Id                      string                 `json:"id"`
	IsMailAuthorized        bool                   `json:"is_mail_authorized"`
	IsPremium               bool                   `json:"is_premium"`
	MailAddress             string                 `json:"mail_address"`
	Name                    string                 `json:"name"`
	ProfileImageUrls        UserProfileImageUrls   `json:"profile_image_urls"`
	RequirePolicyAgreement  bool                   `json:"require_policy_agreement"`
	XRestrict               int                    `json:"x_restrict"`
}

type PixLoginResponseHandler struct {
     
	AccessToken  string          `json:"access_token"`
	DeviceToken  string          `json:"device_token"`
	ExpiresIn    int             `json:"expires_in"`
	RefreshToken string          `json:"refresh_token"`
	Scope        string          `json:"scope"`
	TokenType    string          `json:"token_type"`
	UserOAuth    PixOAuthHandler `json:"user"`
}

type PixLoginResponse struct {
     
	Response PixLoginResponseHandler `json:"response"`
}

//-------------------------Illustration Info----------------------------//

type ImageUrls struct {
     
	Large           string `json:"large"`
	Medium          string `json:"medium"`
	SquareMedium    string `json:"square_medium"`
}

type MetaPages struct {
     

}

type IllustrationInfo struct {
     
	CreateDate      string      `json:"create_date"`
	Height          int         `json:"height"`
	Id              int         `json:"id"`
	ImageUrl        ImageUrls   `json:"image_urls"`
}

type Illustration struct {
     
	Illusts         []IllustrationInfo  `json:"illusts"`
	NextUrl         string              `json:"next_url"`
}

生成构建post请求的参数需要的参数X-Client-Hash和X-Client-Time

package fvckPixiv
import (
	"crypto/md5"
	"encoding/hex"
	"strings"
	"time"
)

var HashSalt string = "28c1fdd170a5204386cb1313c7077b34f83e4aaf4aa829ce78c231e05b0bae2c"

func getXClientHashAndTime() (string, string)  {
     
	var result  string
	var curTime string = getCurFormatTime()
	
	data        := []byte(curTime+HashSalt)
	encodedData := md5.Sum(data)
	
	for _, b := range encodedData {
     
		temp    := make([]byte, 1)
		temp[0] = byte(int(b) & 0xff)
		hexString := hex.EncodeToString(temp)
		if len(hexString) < 2 {
     
			hexString = "0" + hexString
		}
		result = result+hexString
	}
	
	return result, curTime
}

func getCurFormatTime() string {
     
	rawTime := time.Now().Format("2006-01-02 15:04:05")
	var curTime string
	
	for index, timeMsg := range strings.Split(rawTime, " ") {
     
		if index == 0 {
     
			curTime = timeMsg
		} else if index == 1 {
     
			curTime = curTime + "T" + timeMsg + "+08:00"
		}
	}
	return curTime
}

模拟登录&发送请求

package fvckPixiv

import (
	"crypto/tls"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"net/url"
	"strconv"
	"strings"
	"time"
)

type PixClient struct {
     
	clnt             http.Client
	pixLoginResponse PixLoginResponse
	R18illustration	 Illustration
}

func NewPixivClient() *PixClient {
     
	proxyUrl, err := url.Parse("http://127.0.0.1:8118/")
	if err != nil {
     panic(err)}
	
	transport := &http.Transport {
     
		TLSClientConfig: &tls.Config{
     InsecureSkipVerify: false},
		Dial: func(netw, addr string) (net.Conn, error) {
     
			deadline := time.Now().Add(60 * time.Second)
			c, err := net.DialTimeout(netw, addr, time.Second*60)
			if err != nil {
     
				panic(err)
			}
			
			err = c.SetDeadline(deadline)
			return c, err
		},
		ResponseHeaderTimeout: time.Second*60,
		Proxy: http.ProxyURL(proxyUrl),
	}
	return &PixClient {
     
		clnt:             http.Client{
     Transport: transport},
		pixLoginResponse: PixLoginResponse{
     },
	}
}

func (client *PixClient) PixLogin() {
     

	info := "password=fanfan2000&client_id=MOBrBDS8blbauoSck0ZfDbtuzpyT&get_secure_url=true&username=1264625484%40qq.com&include_policy=true&client_secret=lsACyCD94FhDUtGTXi3QzcFE2uU1hqtDaKeqrdwj&device_token=pixiv&grant_type=password"
	
	request, err := http.NewRequest("POST",
		"https://oauth.secure.pixiv.net/auth/token",
		strings.NewReader(info))
	if err != nil {
     
		log.Println(err)
	}
	clientHash, curTime := getXClientHashAndTime()
	
	request.Header.Set("User-Agent", "PixivAndroidApp/5.0.155 (Android 5.1.1; OPPO R17)")
	request.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	request.Header.Set("App-OS", "Android")
	request.Header.Set("App-OS-Version", "5.1.1")
	request.Header.Set("App-Version", "5.0.166")
	request.Header.Set("X-Client-Hash", clientHash)
	request.Header.Set("X-Client-Time", curTime)
	request.Header.Set("Connection", "Keep-Alive")
	request.Header.Set("Content-Length", strconv.Itoa(len(info)))
	
	for key, value := range request.Header {
     
		fmt.Println(key, value)
	}
	
	resp, err := client.clnt.Do(request)
	if err != nil {
     
		panic(err)
	}
	
	data, err := ioutil.ReadAll(resp.Body)
	defer resp.Body.Close()
	if err != nil {
     
		panic(err)
	} else {
     
		log.Println(string(data))
	}
	err = json.Unmarshal(data, &client.pixLoginResponse)
	if err != nil {
     
		panic(err)
	}
	
}

func (client *PixClient) PixivGetR18Daily() {
     
	
	req, err := http.NewRequest("GET",
		"https://app-api.pixiv.net/v1/illust/ranking?filter=for_android&mode=day_r18",
		strings.NewReader(""))
	
	if err != nil {
     panic(err)}
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	req.Header.Set("Authorization", "Bearer " + client.pixLoginResponse.Response.AccessToken)
	req.Header.Set("User-Agent", "PixivAndroidApp/5.0.155 (Android 5.1.1; OPPO R17)")
	req.Header.Set("Accept", "*/*")
	req.Header.Set("Cache-Control", "no-cache")
	
	
	resp, err := client.clnt.Do(req)
	if err != nil {
     
		log.Println(err)
	}
	
	if resp.StatusCode == 400 {
     
		client.PixLogin()
		client.PixivGetR18Daily()
		return
	}
	
	content, err := ioutil.ReadAll(resp.Body)
	if err != nil {
     panic(err)}
	defer resp.Body.Close()
	
	err = json.Unmarshal(content, &client.R18illustration)
	if err != nil {
     
		log.Println(err)
	}
	
}


func (client *PixClient) HSGet(url string) (*http.Response, error) {
     
	
	resp, err := client.clnt.Get(url)
	if err != nil {
     return nil, err}
	
	return resp, nil
}

func (client *PixClient) HSPost(url string, args string) (*http.Response, error) {
     
	
	var rsp io.Reader
	resp, err := client.clnt.Post(url, args, rsp)
	if err != nil {
     
		log.Println(err)
	}
	
	return resp, nil
}

下载文件到本地

package downloader

import (
	"errors"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"strconv"
)

func IsFileExist(filename string, fileSize int64) bool {
     
	
	info, err := os.Stat(filename)
	if os.IsNotExist(err) {
     
		log.Println(info)
		return false
	}
	
	if fileSize == info.Size() {
     
		log.Println("文件已存在!", info.Name(), info.Size(), info.ModTime())
		return true
	}
	del := os.Remove(filename)
	if del != nil {
     
		log.Println(del)
	}
	return false
	
}

func DownloadFile(url string, localPath string,
	feedbacks ...func(length, downLen int64)) error {
     
	
	var (
		fsize   int64
		buf   = make([]byte, 128*1024)
		written int64
	)
	tmpFilePath := localPath + ".download"
	log.Println(tmpFilePath)
	
	client := new(http.Client)
	resp, err := client.Get(url)
	if err != nil {
     
		return err
	}
	
	fsize, err = strconv.ParseInt(resp.Header.Get("Content-Length"), 10, 32)
	if err != nil {
     
		log.Println(err)
	}
	if IsFileExist(localPath, fsize) {
     
		return err
	}
	
	log.Println("fsize", fsize)
	file, err := os.Create(tmpFilePath)
	if err != nil {
     
		return err
	}
	defer file.Close()
	
	if resp.Body == nil {
     
		return errors.New("body is null")
	}
	defer resp.Body.Close()
	
	for {
     
		nr, er := resp.Body.Read(buf)
		if nr > 0 {
     
			nw, ew := file.Write(buf[0:nr])
			if nw > 0 {
     
				written += int64(nw)
			}
			if ew != nil {
     
				err = ew
				break
			}
			if nr != nw {
     
				err = io.ErrShortWrite
				break
			}
		}
		if er != nil {
     
			if er != io.EOF {
     
				err = er
			}
			break
		}
		for _, feedback := range feedbacks {
     
			feedback(fsize, written)
		}
	}
	log.Println(err)
	if err == nil {
     
		file.Close()
		err = os.Rename(tmpFilePath, localPath)
		fmt.Println(err)
	}
	return err
}

机器人检测消息

package main

import (
	"log"
	"net/url"
	"regexp"
	"strconv"
	"strings"
	
	"FuckPixiv/src/fvckPixiv"
	"github.com/catsworld/qq-bot-api"
)

var bot  *qqbotapi.BotAPI
var pix  *fvckPixiv.PixClient

const Host = "127.0.0.1:6700"

func main() {
     
	var err error
	bot, err = qqbotapi.NewBotAPI("", "ws://"+Host, "CQHTTP_SECRET")
	if err != nil {
     
		log.Fatal(err)
	}
	bot.Debug = false
	
	conf := qqbotapi.NewUpdate(0)
	conf.PreloadUserInfo = true
	updates, err := bot.GetUpdatesChan(conf)
	
	pix = fvckPixiv.NewPixivClient()
	pix.PixLogin()
	
	for update := range updates {
     
		if update.Message == nil {
     
			continue
		}
		log.Println(update.Message)
		handleMsg(update)
	}
}

func handleMsg(update qqbotapi.Update) {
     
	if msgSlice := strings.Split(update.Message.Text, " ")
	len(msgSlice) == 2 {
     
		if msgSlice[0] == "KKP" || msgSlice[0] == "kkp" {
     
			re := regexp.MustCompile(`[0-9]{1,2}`)
			
			if re.MatchString(msgSlice[1]) {
     
				index, _ := strconv.Atoi(msgSlice[1])
				picUrl, err := url.Parse(pix.R18illustration.Illusts[index - 1].ImageUrl.Large)
				if err != nil {
     log.Println(err)}
				
				if update.MessageType == "group" {
     
					bot.NewMessage(update.GroupID, "group").ImageWeb(picUrl).Send()
				} else if update.MessageType == "private" {
     
					bot.NewMessage(update.Message.From.ID, "private").ImageWeb(picUrl).Send()
				}
			} else {
     return}
		}
	} else if len(msgSlice) == 1 {
     
		if msgSlice[0] == "色图GKD" {
     
			pix.PixivGetR18Daily()
		}
	}
}

你可能感兴趣的:(golang,go,http)