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())
}
}