クロールiqiyiを実現します

1.ユーザーがクロールするビデオカテゴリのIDを入力します

その他のタイプとIDについては、
https://list.iqiyi.com/www/2/-------------24-1-1-iqiyi--.htmlにアクセス
して
カテゴリ名を照会できます。channel_idTVシリーズ2映画1バラエティショー6アニメ4ドキュメンタリー3ゲーム8情報25エンターテインメント7ファイナンス24音楽5ミリタリー28教育12

クロールパスのステッチ
https://pcw-api.iqiyi.com/search/recommend/list?channel_id=25&data_type=2&mode=20&page_id=1&ret_num=48&session=52a4f94fc5c1694a19ab31cc66aefa39channel_idを
、ユーザーが必要とするタイプID、
デフォルトのクロールトップ100に置き換えますページのコンテンツは、page_idを1から100まで
循環して、playurl名tvid取得します。

コンテンツをダウンロードする

tvidとplayurlによると、クロールされたリクエストの名前

アニーに電話して保存する

次のステップでは、annieのソースコードを読み取り、aiqiyi部分のみをクロールできます。

付録:キーコード

要求された応答コンテンツは
goで構造定義構造に変換さます

type resp_data struct{
    
    
    Data struct {
    
    
        List []struct{
    
    
            TvId int `json:"tvId"`
            Name string `json:"name"`
            PlayUrl string `json:"playUrl"`
        }`json:"list"`
    } `json:"data"`
}

文字列生成構造

inputjsondata := `{
     
     "code":"A00000","data":{
     
     "card_type":"catelib_video","pingback":{
     
     "bkt":"list_D,list_online","e":"cff4f9c997e0be145100787b4ee5dbab"},"session":"52a4f94fc5c1694a19ab31cc66aefa39","has_next":1,"list":[{
     
     "tvId":17033482400,"albumId":17033482400,"channelId":25,"description":"自6月11日至6月19日,北京连日报告新冠肺炎确诊病例,目前已经累计报告205例,涉及全市9个区。6月20日下午,北京市疾控中心公布了6月16日、17日、18日本市新增报告新冠肺炎确诊病例的情况","name":"北京公布6月16-18日新增确诊病例活动过的小区或场所","playUrl":"http://www.iqiyi.com/v_19rxu5z6bw.html","isAdvance":false,"payMark":0,"payMarkUrl":"","imageUrl":"http://pic1.iqiyipic.com/image/20200620/6e/db/v_149953322_m_601.jpg","duration":"00:29","videoCount":1,"latestOrder":1,"categories":["国内"],"albumName":"北京公布6月16-18日新增确诊病例活动过的小区或场所","albumImageUrl":"","period":"2020-06-20","exclusive":false,"qiyiProduced":false,"sourceId":0,"focus":"","people":{
     
     },"score":"","title":"北京公布6月16-18日新增确诊病例活动过的小区或场所","pingback":{
     
     "doc_id":17033482400}},{
     
     "tvId":17058687400,"albumId":17058687400,"channelId":25,"description":"","name":"全国普速铁路实施电子客票 ,检票速度提升3倍1秒钟可过1名旅客","playUrl":"http://www.iqiyi.com/v_19rxqp4q84.html","isAdvance":false,"payMark":0,"payMarkUrl":"","imageUrl":"http://pic9.iqiyipic.com/image/20200621/0a/5d/v_149974318_m_601.jpg","duration":"02:30","videoCount":1,"latestOrder":1,"categories":["社会"],"albumName":"全国普速铁路实施电子客票 ,检票速度提升3倍1秒钟可过1名旅客","albumImageUrl":"","period":"2020-06-21","exclusive":false,"qiyiProduced":false,"sourceId":0,"focus":"","people":{
     
     },"score":"","title":"全国普速铁路实施电子客票 ,检票速度提升3倍1秒钟可过1名旅客","pingback":{
     
     "doc_id":17058687400}}]}}`
    convert_json_to_struct(inputjsondata)
 convert_json_to_struct实现
func convert_json_to_struct(inputjsondata string) (resp_data,error){
    
    
    // 将输入的字符串 转换为  byte 数组
    jsondata := []byte(inputjsondata)
    var struct_data resp_data
    error1 :=json.Unmarshal(jsondata,&struct_data)
    if error1!=nil{
    
    
        return struct_data,error1
    }
    return struct_data,nil
}

ソースコード

package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strconv"
	"sync"
	"time"

	"github.com/gocolly/colly"
)

type RespData struct {
    
    
	Data struct {
    
    
		List []struct {
    
    
			TvId    int    `json:"tvId"`
			Name    string `json:"name"`
			PlayUrl string `json:"playUrl"`
		} `json:"list"`
	} `json:"data"`
}

type DownJob struct {
    
    
	TvId    int    `json:"tvId"`
	Name    string `json:"name"`
	PlayUrl string `json:"playUrl"`
}

//"code":"A00000",
//{
    
    "code":"A00000","data":{
    
    "card_type":"catelib_video","pingback":{
    
    "bkt":"list_D,list_online","e":"cff4f9c997e0be145100787b4ee5dbab"},"session":"52a4f94fc5c1694a19ab31cc66aefa39","has_next":1,"list":[{
    
    "tvId":17033482400,"albumId":17033482400,"channelId":25,"description":"自6月11日至6月19日,北京连日报告新冠肺炎确诊病例,目前已经累计报告205例,涉及全市9个区。6月20日下午,北京市疾控中心公布了6月16日、17日、18日本市新增报告新冠肺炎确诊病例的情况","name":"北京公布6月16-18日新增确诊病例活动过的小区或场所","playUrl":"http://www.iqiyi.com/v_19rxu5z6bw.html","isAdvance":false,"payMark":0,"payMarkUrl":"","imageUrl":"http://pic1.iqiyipic.com/image/20200620/6e/db/v_149953322_m_601.jpg","duration":"00:29","videoCount":1,"latestOrder":1,"categories":["国内"],"albumName":"北京公布6月16-18日新增确诊病例活动过的小区或场所","albumImageUrl":"","period":"2020-06-20","exclusive":false,"qiyiProduced":false,"sourceId":0,"focus":"","people":{
    
    },"score":"","title":"北京公布6月16-18日新增确诊病例活动过的小区或场所","pingback":{
    
    "doc_id":17033482400}},{
    
    "tvId":17058687400,"albumId":17058687400,"channelId":25,"description":"","name":"全国普速铁路实施电子客票 ,检票速度提升3倍1秒钟可过1名旅客","playUrl":"http://www.iqiyi.com/v_19rxqp4q84.html","isAdvance":false,"payMark":0,"payMarkUrl":"","imageUrl":"http://pic9.iqiyipic.com/image/20200621/0a/5d/v_149974318_m_601.jpg","duration":"02:30","videoCount":1,"latestOrder":1,"categories":["社会"],"albumName":"全国普速铁路实施电子客票 ,检票速度提升3倍1秒钟可过1名旅客","albumImageUrl":"","period":"2020-06-21","exclusive":false,"qiyiProduced":false,"sourceId":0,"focus":"","people":{
    
    },"score":"","title":"全国普速铁路实施电子客票 ,检票速度提升3倍1秒钟可过1名旅客","pingback":{
    
    "doc_id":17058687400}}]}}

func ConvertJsonToStruct(InJsonData1 string) (RespData, error) {
    
    
	// 将输入的字符串 转换为  byte 数组
	JsonData1 := []byte(InJsonData1)
	var StructData RespData
	err := json.Unmarshal(JsonData1, &StructData)
	if err != nil {
    
    
		return StructData, err
	}
	return StructData, nil
}

//判断是否存在文件
func JudgeFilenameIsExist(dirpath string, filename string) (bool, error) {
    
    
	filename1 := fmt.Sprintf("%s*", filename)
	filepathNames, err := filepath.Glob(filepath.Join(dirpath, filename1))
	if err != nil {
    
    
		return false, err
	} else {
    
    
		if len(filepathNames) == 0 {
    
    
			return false, nil
		} else {
    
    
			log.Output(2, fmt.Sprintf("已存在的视频%v", filepathNames))
			return true, nil
		}
	}
}

//根据用户选择进行 生成对应的文件夹
//以及  对应的 ChannelId
func DealUserChoice(tvTypeName string) (string, string, error) {
    
    
	DirPath1, err := os.Getwd()
	if err != nil {
    
    
		return "", "", errors.New("Getwd error")
	}
	DirPath1 = filepath.Join(DirPath1, tvTypeName)

	ChannelId := "-1"
	switch tvTypeName {
    
    
	case "电视剧":
		ChannelId = "2"
	case "电影":
		ChannelId = "1"
	case "综艺":
		ChannelId = "6"
	case "动漫":
		ChannelId = "4"
	case "纪录片":
		ChannelId = "3"
	case "游戏":
		ChannelId = "8"
	case "资讯":
		ChannelId = "25"
	case "娱乐":
		ChannelId = "7"
	case "财经":
		ChannelId = "24"
	case "音乐":
		ChannelId = "5"
	case "军事":
		ChannelId = "28"
	case "教育":
		ChannelId = "12"
	default:
		return "", "", errors.New("donot know type!")
	}
	log.Output(2, fmt.Sprintf("保存路径 %q ChannelId %v", DirPath1, ChannelId))

	err = os.Mkdir(DirPath1, 0777)
	if err != nil {
    
    
		return DirPath1, ChannelId, errors.New("mkdir error")
	}

	return DirPath1, ChannelId, nil
}

//爬取下载地址,创建下载任务
func CollyCreateJob(DownJobChannel chan DownJob, ChannelId string) error {
    
    
	//定义同步变量
	var wg sync.WaitGroup
	defer wg.Wait()
	// print("1")
	var l sync.Mutex
	PageId1 := 1

	// 创建 8 线程 执行 job
	CpuCount := runtime.NumCPU()
	for UseCpuCount := 0; UseCpuCount < CpuCount; UseCpuCount++ {
    
    
		wg.Add(1)
		go func() {
    
    
			defer wg.Done()
			for {
    
    
				l.Lock()
				if PageId1 > 1000 {
    
    
					l.Unlock()
					return
				}
				ThisPageId1 := PageId1
				PageId1 += 1
				l.Unlock()

				c := colly.NewCollector()
				c.OnResponse(func(r *colly.Response) {
    
    
					RespData1, err := ConvertJsonToStruct(string(r.Body))
					if err != nil {
    
    
						log.Output(2, err.Error())
						return
					}
					for _, onedata := range RespData1.Data.List {
    
    
						DownJobChannel <- onedata
					}

				})
				visiturl := fmt.Sprintf("https://pcw-api.iqiyi.com/search/recommend/list?channel_id=%s&data_type=2&mode=20&PageId1=%d&ret_num=48&session=aca4f9c97bb1be8bc69e34b85a3b95a3", ChannelId, ThisPageId1)
				log.Output(2, "任务信息的url"+visiturl)
				c.Visit(visiturl)
			}
		}()

	}

	return errors.New("colly error")
}

func ClimbVideo(DirPath1, ChannelId string) error {
    
    
	//定义同步变量
	var wg sync.WaitGroup
	defer wg.Wait()

	// 爬取网站创建任务 最大任务数
	DownJobChannel := make(chan DownJob, 2000)

	//使用colly 爬取视频 并创建任务
	wg.Add(1)
	go func() {
    
    
		defer wg.Done()
		err := CollyCreateJob(DownJobChannel, ChannelId)
		if err != nil {
    
    
			log.Output(2, err.Error())
			return
		}
	}()

	// 创建 8 线程 执行 job
	CpuCount := runtime.NumCPU()

	var CountLock sync.Mutex
	downCount := 0
	sumCount := 0
	for UseCpuCount := 0; UseCpuCount < CpuCount; UseCpuCount++ {
    
    
		// 启用 和 虚拟 cpu核数 相同的 go 程, 减少启用过多的go程带来的 调度消耗
		ThisGoCount := UseCpuCount
		wg.Add(1)
		go func() {
    
    
			defer wg.Done()
			for {
    
    
				// var OneJob DownJob
				OneJob := <-DownJobChannel
				filename := fmt.Sprintf("%v_%v", OneJob.TvId, OneJob.Name)
				bool1, err := JudgeFilenameIsExist(DirPath1, filename)
				if err != nil {
    
    
					log.Output(2, err.Error())
					return
				}
				if bool1 == false {
    
    
					//判断任务状态的信道
					waitchan := make(chan int)
					//执行任务
					go func() {
    
    
						//执行完成后, 给信道完成信号
						defer func() {
    
    
							waitchan <- 1
						}()
						// 下载文件
						cmd := exec.Command("annie", "-O", filename, "-o", DirPath1, OneJob.PlayUrl)
						//err := cmd.Run()  //执行到此处时会阻塞等待10秒
						stdout, _ := cmd.StdoutPipe()
						err := cmd.Run()

						// out_bytes, _ := ioutil.ReadAll(stdout)
						_, _ = ioutil.ReadAll(stdout)
						stdout.Close()

						CountLock.Lock()
						downCount += 1
						sumCount += 1
						CountLock.Unlock()

						if err != nil {
    
    
							log.Output(2, "错误 "+err.Error()+" 下载地址 "+OneJob.PlayUrl+" 当前进程编号 "+strconv.Itoa(ThisGoCount))
						} else {
    
    
							log.Output(2, "下载的文件 "+filename+" 下载数 "+strconv.Itoa(downCount)+" 当前进程编号 "+strconv.Itoa(ThisGoCount))
						}
					}()
					select {
    
    
					//任务超过 5 分钟则超时
					case <-waitchan:
					case <-time.After(5 * 60 * time.Second):
						// case <-time.After(1 * time.Second):
						log.Output(2, "任务超时 跳过任务  当前进程编号"+string(ThisGoCount))
						continue
					}

				}

				// video_file_path := filepath.Join(DirPath1,filename)

			}
		}()
	}
	log.Output(2, fmt.Sprintf("cpu核数: %v ,cpu使用数 %v ", CpuCount, CpuCount))

	return nil
}

func init() {
    
    

	log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)
	logFile, err := os.OpenFile("./job.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
	// defer log.Output(2, "一个日志")
	if err != nil {
    
    
		log.Panic("打开日志文件异常")
	}
	log.SetOutput(logFile)
}

func main() {
    
    
	// 类型的编号 , 在这里查看 https://list.iqiyi.com/www/25/-------------24-1-2-iqiyi--.html
	// 常见的类型
	// 电影1
	// 综艺6
	// 动漫4
	// 纪录片3
	// 游戏8
	// 资讯25
	// 娱乐7
	// 财经24
	// 音乐5
	// 军事28
	// 教育12

	// saveDirName := "资讯"
	// downTypeID := "25"
	// saveDirName := "音乐"
	// downTypeID := "5"

	// 由用户输入爬取内容
	tvTypeName := "资讯"
	DirPath1, ChannelId, err := DealUserChoice(tvTypeName)
	if err != nil {
    
    
		log.Output(2, fmt.Sprintf(" %v %v ", ChannelId, err.Error()))
	}
	//climb 爬取视频到指定路径

	err = ClimbVideo(DirPath1, ChannelId)
	if err != nil {
    
    
		log.Output(2, err.Error())
	}
}

おすすめ

転載: blog.csdn.net/qq_43373608/article/details/107217611