|
@@ -1,13 +1,14 @@
|
|
|
import os
|
|
|
import sys
|
|
|
-import asyncio
|
|
|
import json
|
|
|
import random
|
|
|
import uuid
|
|
|
import time
|
|
|
import traceback
|
|
|
from datetime import datetime
|
|
|
-import aiohttp
|
|
|
+import requests
|
|
|
+from requests.adapters import HTTPAdapter
|
|
|
+from urllib3.util.retry import Retry
|
|
|
|
|
|
sys.path.append(os.getcwd())
|
|
|
from application.common.feishu import FsData
|
|
@@ -51,36 +52,36 @@ class ZhongQingKanDianRelated:
|
|
|
self.expire_flag = False
|
|
|
self.aliyun_log = AliyunLogger(mode=self.mode, platform=self.platform)
|
|
|
self.db_ops = DatabaseOperations(mode=mode, platform=platform)
|
|
|
- self.redis_ops = RedisOperations()
|
|
|
+ self.redis_ops = RedisOperations(mode=mode, platform=platform)
|
|
|
data_rule = FsData()
|
|
|
self.title_rule = data_rule.get_title_rule()
|
|
|
self.LocalLog = Local.logger(self.platform, self.mode)
|
|
|
+ self.session = requests.session()
|
|
|
|
|
|
-
|
|
|
- async def send_request(self, path, data):
|
|
|
+ def send_request(self, path, data):
|
|
|
"""
|
|
|
- 异步发送 POST 请求到指定路径,带有重试机制。
|
|
|
+ 同步发送 POST 请求到指定路径,带有重试机制。
|
|
|
:param path: 请求的 API 路径
|
|
|
:param data: 请求的数据
|
|
|
:return: 响应的 JSON 数据,如果请求失败则返回 None
|
|
|
"""
|
|
|
full_url = f"{self.API_BASE_URL}{path}"
|
|
|
- async with aiohttp.ClientSession(headers=self.COMMON_HEADERS) as session:
|
|
|
- for retry in range(self.MAX_RETRIES):
|
|
|
- try:
|
|
|
- async with session.post(full_url, data=data, timeout=self.TIMEOUT) as response:
|
|
|
- response.raise_for_status()
|
|
|
- self.LocalLog.info(f"{path}响应数据:{await response.json()}")
|
|
|
- return await response.json()
|
|
|
- except (aiohttp.ClientError, json.JSONDecodeError) as e:
|
|
|
- tb_info = traceback.format_exc()
|
|
|
- self.LocalLog.info(f"{path}请求失败:{e} \n{tb_info}")
|
|
|
- self.aliyun_log.logging(
|
|
|
- code="3000",
|
|
|
- message=f"请求 {path} 失败,错误信息: {str(e)}",
|
|
|
- data={"path": path}
|
|
|
- )
|
|
|
- await asyncio.sleep(5)
|
|
|
+
|
|
|
+ for retry in range(self.MAX_RETRIES):
|
|
|
+ try:
|
|
|
+ response = self.session.post(full_url, data=data, timeout=self.TIMEOUT, headers=self.COMMON_HEADERS)
|
|
|
+ response.raise_for_status()
|
|
|
+ self.LocalLog.info(f"{path}响应数据:{response.json()}")
|
|
|
+ return response.json()
|
|
|
+ except Exception as e:
|
|
|
+ tb_info = traceback.format_exc()
|
|
|
+ self.LocalLog.info(f"{path}请求失败:{e} \n{tb_info}")
|
|
|
+ self.aliyun_log.logging(
|
|
|
+ code="3000",
|
|
|
+ message=f"请求 {path} 失败,错误信息: {str(e)}",
|
|
|
+ data={"path": path}
|
|
|
+ )
|
|
|
+ time.sleep(5)
|
|
|
return None
|
|
|
|
|
|
def is_response_valid(self, resp, url):
|
|
@@ -109,21 +110,20 @@ class ZhongQingKanDianRelated:
|
|
|
self.LocalLog.info(f"检查 {url} 响应有效性时出错:{e} \n{tb_info}")
|
|
|
return None
|
|
|
|
|
|
- async def req_related_recommend_list(self, content_id):
|
|
|
+ def req_related_recommend_list(self, content_id):
|
|
|
"""
|
|
|
- 异步请求与指定内容 ID 相关的推荐列表。
|
|
|
+ 同步请求与指定内容 ID 相关的推荐列表。
|
|
|
:param
|
|
|
:return: 相关推荐视频列表的有效响应数据,如果请求失败则返回 None
|
|
|
"""
|
|
|
try:
|
|
|
-
|
|
|
url = '/crawler/zhong_qing_kan_dian/related'
|
|
|
body = json.dumps({
|
|
|
"content_id": f"{content_id}",
|
|
|
"cursor": ""
|
|
|
})
|
|
|
self.LocalLog.info(f"开始请求相关推荐{body}")
|
|
|
- resp = await self.send_request(url, body)
|
|
|
+ resp = self.send_request(url, body)
|
|
|
return self.is_response_valid(resp, url)
|
|
|
except Exception as e:
|
|
|
tb_info = traceback.format_exc()
|
|
@@ -135,9 +135,9 @@ class ZhongQingKanDianRelated:
|
|
|
self.LocalLog.info(f"请求相关推荐视频列表 {url} 时发生异常:{e} \n{tb_info}")
|
|
|
return None
|
|
|
|
|
|
- async def req_detail(self, content_link, **kwargs):
|
|
|
+ def req_detail(self, content_link, **kwargs):
|
|
|
"""
|
|
|
- 异步请求视频详情。
|
|
|
+ 同步请求视频详情。
|
|
|
:param content_link: 视频内容链接
|
|
|
:param kwargs: 额外的视频信息
|
|
|
:return: 无返回值,处理视频详情信息
|
|
@@ -148,7 +148,7 @@ class ZhongQingKanDianRelated:
|
|
|
body = json.dumps({
|
|
|
"content_link": content_link
|
|
|
})
|
|
|
- resp = await self.send_request(url, body)
|
|
|
+ resp = self.send_request(url, body)
|
|
|
if not self.is_response_valid(resp, url):
|
|
|
return
|
|
|
data = resp.get("data", {}).get("data", {})
|
|
@@ -162,8 +162,7 @@ class ZhongQingKanDianRelated:
|
|
|
return
|
|
|
self.LocalLog.info(f"{content_link} 是视频")
|
|
|
data.update(kwargs)
|
|
|
- await self.process_video_obj(data)
|
|
|
- await asyncio.sleep(10)
|
|
|
+ self.process_video_obj(data)
|
|
|
except Exception as e:
|
|
|
tb_info = traceback.format_exc()
|
|
|
self.aliyun_log.logging(
|
|
@@ -173,7 +172,7 @@ class ZhongQingKanDianRelated:
|
|
|
)
|
|
|
self.LocalLog.error(f"请求视频详情,链接 {content_link} 时发生异常:{e} \n{tb_info}")
|
|
|
|
|
|
- async def control_request_related(self):
|
|
|
+ def control_request_related(self):
|
|
|
"""
|
|
|
控制相关推荐视频列表的请求和处理流程。
|
|
|
:return: 无返回值,根据下载数量限制控制流程
|
|
@@ -181,20 +180,26 @@ class ZhongQingKanDianRelated:
|
|
|
while self.limit_flag:
|
|
|
try:
|
|
|
self.LocalLog.info(f"开始推荐视频列表的请求和处理流程,今日已爬 {self.download_cnt} 个视频")
|
|
|
+
|
|
|
content_id = self.redis_ops.get_recommend_video()
|
|
|
if not content_id:
|
|
|
self.LocalLog.info("缓存中【task:zqkd_video_id】没有数据")
|
|
|
- await asyncio.sleep(10)
|
|
|
continue
|
|
|
- related_resp = await self.req_related_recommend_list(content_id)
|
|
|
- self.LocalLog.info(f"获取的推荐列表长度:{len(related_resp)}")
|
|
|
+ time.sleep(random.randint(5, 10))
|
|
|
+ related_resp = self.req_related_recommend_list(content_id)
|
|
|
if not related_resp:
|
|
|
continue
|
|
|
related_list = related_resp.get("data", {}).get("data", [])
|
|
|
+ self.LocalLog.info(f"获取的推荐列表长度:{len(related_list)}")
|
|
|
for related_obj in related_list:
|
|
|
- related_content_link = related_obj.get("share_url")
|
|
|
+ # if not self.limit_flag:
|
|
|
+ # self.LocalLog.info(f"今日视频数量已达最大量{self.download_cnt}")
|
|
|
+ # return
|
|
|
+ related_content_link = related_obj.get("share_info", {}).get("share_url")
|
|
|
+ self.LocalLog.info(f"related_content_link == {related_content_link}")
|
|
|
if related_content_link:
|
|
|
- await self.req_detail(related_content_link, **related_obj)
|
|
|
+ time.sleep(random.randint(5, 10))
|
|
|
+ self.req_detail(related_content_link, **related_obj)
|
|
|
except Exception as e:
|
|
|
tb_info = traceback.format_exc()
|
|
|
self.aliyun_log.logging(
|
|
@@ -204,7 +209,7 @@ class ZhongQingKanDianRelated:
|
|
|
)
|
|
|
self.LocalLog.info(f"控制相关推荐视频请求和处理时发生异常:\n{tb_info}")
|
|
|
|
|
|
- async def process_video_obj(self, video_obj):
|
|
|
+ def process_video_obj(self, video_obj):
|
|
|
"""
|
|
|
处理视频对象,包括检查视频时长、用户信息、保存数据等操作。
|
|
|
:param video_obj: 视频对象,包含视频的各种信息
|
|
@@ -243,9 +248,7 @@ class ZhongQingKanDianRelated:
|
|
|
self.aliyun_log.logging(code="1007", message=f"用户数据写入成功,用户ID:{account_id}")
|
|
|
self.LocalLog.info(f"用户数据写入成功,用户ID: {account_id}")
|
|
|
|
|
|
- if video_duration > self.rule_dict.get("duration", {}).get("max",
|
|
|
- 1200) or video_duration < self.rule_dict.get(
|
|
|
- "duration", {}).get("min", 30):
|
|
|
+ if video_duration > self.rule_dict.get("duration", {}).get("max", 1200) or video_duration < self.rule_dict.get("duration", {}).get("min", 30):
|
|
|
self.aliyun_log.logging(
|
|
|
code="3005",
|
|
|
message=f"视频时长不满足条件[>=30s&<=1200s]视频ID:{video_obj['channel_content_id']},视频时长:{video_duration}"
|
|
@@ -256,14 +259,15 @@ class ZhongQingKanDianRelated:
|
|
|
|
|
|
item.add_video_info("video_id", video_obj['channel_content_id'])
|
|
|
item.add_video_info("video_title", video_obj["title"])
|
|
|
- item.add_video_info("play_cnt", int(video_obj["read_num"]))
|
|
|
+
|
|
|
+ item.add_video_info("play_cnt", int(video_obj["read_count"]))
|
|
|
item.add_video_info("publish_time_stamp", int(int(video_obj["publish_timestamp"]) / 1000))
|
|
|
item.add_video_info("out_user_id", video_obj["channel_account_id"])
|
|
|
item.add_video_info("cover_url", video_obj["image_url_list"][0]['image_url'])
|
|
|
item.add_video_info("like_cnt", 0)
|
|
|
- item.add_video_info("collection_cnt", int(video_obj['collect_num']))
|
|
|
- item.add_video_info("share_cnt", int(video_obj["share_num"]))
|
|
|
- item.add_video_info("comment_cnt", int(video_obj["cmt_num"]))
|
|
|
+ item.add_video_info("collection_cnt", 0)
|
|
|
+ item.add_video_info("share_cnt", int(video_obj["share_count"]))
|
|
|
+ item.add_video_info("comment_cnt", int(video_obj["comment_count"]))
|
|
|
item.add_video_info("video_url", video_obj["video_url_list"][0]['video_url'])
|
|
|
item.add_video_info("out_video_id", int(video_obj["channel_content_id"]))
|
|
|
item.add_video_info("duration", video_obj["video_url_list"][0]['video_duration'])
|
|
@@ -280,7 +284,7 @@ class ZhongQingKanDianRelated:
|
|
|
rule_dict=self.rule_dict,
|
|
|
env=self.env,
|
|
|
item=mq_obj,
|
|
|
- trace_id=trace_id
|
|
|
+ trace_id=traceback.format_exc()
|
|
|
)
|
|
|
if pipeline.process_item():
|
|
|
title_list = self.title_rule.split(",")
|
|
@@ -325,42 +329,21 @@ class ZhongQingKanDianRelated:
|
|
|
)
|
|
|
self.LocalLog.error(f"处理视频对象时发生异常: {e}\n{tb_info}")
|
|
|
|
|
|
- async def run(self):
|
|
|
- """
|
|
|
- 运行主流程,异步执行推荐视频和相关推荐视频的请求,直到达到下载数量限制。
|
|
|
-
|
|
|
- :return: 无返回值,程序运行的主逻辑
|
|
|
- """
|
|
|
- self.LocalLog.info("开始执行中青看点推荐抓取...")
|
|
|
- await asyncio.gather(
|
|
|
- self.control_request_related()
|
|
|
- )
|
|
|
|
|
|
- async def run(self):
|
|
|
+ def run(self):
|
|
|
"""
|
|
|
- 运行主流程,异步执行推荐视频和相关推荐视频的请求,直到达到下载数量限制。
|
|
|
+ 运行主流程,执行相关推荐视频的请求,直到达到下载数量限制。
|
|
|
|
|
|
:return: 无返回值,程序运行的主逻辑
|
|
|
"""
|
|
|
- self.LocalLog.info("开始执行中青看点推荐抓取...")
|
|
|
- await asyncio.gather(
|
|
|
- self.control_request_related()
|
|
|
- )
|
|
|
+ self.LocalLog.info("开始执行中青看点相关推荐抓取...")
|
|
|
+ self.control_request_related()
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
- asyncio.run(ZhongQingKanDianRelated(
|
|
|
+ ZhongQingKanDianRelated(
|
|
|
platform="zhongqingkandian",
|
|
|
mode="recommend",
|
|
|
- rule_dict={"videos_cnt": {"min": 2, "max": 0}},
|
|
|
- user_list=[{"uid": 81522822, "link": "中青看点推荐", "nick_name": "免不了俗"}]
|
|
|
- ).run())
|
|
|
- # content_link = "https://vol.youth.cn/4X32ftEV6SsA9Mq9?signature=6y30XlmbkL9oxwAjJd1PXOBX0idx0ZD1gMQE2nZKW8RNpvPrqz"
|
|
|
- # asyncio.run(ZhongQingKanDian(
|
|
|
- # platform="zhongqingkandian",
|
|
|
- # mode="recommend",
|
|
|
- # rule_dict={
|
|
|
- # {"videos_cnt":{"min":100,"max":0}},{"duration":{"min":30,"max":1200}}
|
|
|
- # },
|
|
|
- # user_list=[{"uid": 81522822, "link": "中青看点推荐", "nick_name": "免不了俗"}]
|
|
|
- # ).req_detail(content_link,"测试"))
|
|
|
+ rule_dict={"videos_cnt": {"min": 3, "max": 0}},
|
|
|
+ user_list=[{"uid": 81525095, "link": "中青看点推荐", "nick_name": "善惡"}]
|
|
|
+ ).run()
|