kuaishou_follow.py 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702
  1. # -*- coding: utf-8 -*-
  2. # @Author: wangkun
  3. # @Time: 2023/2/24
  4. import os
  5. import random
  6. import sys
  7. import time
  8. import requests
  9. import urllib3
  10. sys.path.append(os.getcwd())
  11. from common.common import Common
  12. from common.feishu import Feishu
  13. from common.publish import Publish
  14. proxies = {"http": None, "https": None}
  15. class Follow:
  16. # 已抓取视频数量
  17. get_person_video_count = []
  18. get_all_video_count = []
  19. # 小程序:关注列表翻页参数
  20. follow_pcursor = ""
  21. # 小程序:个人主页视频列表翻页参数
  22. person_pcursor = ""
  23. # 视频发布时间
  24. send_time = 0
  25. # 配置微信
  26. wechat_sheet = Feishu.get_values_batch("follow", "kuaishou", "WFF4jw")
  27. Referer = wechat_sheet[2][3]
  28. NS_sig3 = wechat_sheet[3][3]
  29. NS_sig3_origin = wechat_sheet[4][3]
  30. did = wechat_sheet[5][3]
  31. session_key = wechat_sheet[6][3]
  32. unionid = wechat_sheet[7][3]
  33. eUserStableOpenId = wechat_sheet[8][3]
  34. openId = wechat_sheet[9][3]
  35. eOpenUserId = wechat_sheet[10][3]
  36. kuaishou_wechat_app_st = wechat_sheet[11][3]
  37. passToken = wechat_sheet[12][3]
  38. userId = wechat_sheet[13][3]
  39. # 过滤敏感词
  40. @classmethod
  41. def sensitive_words(cls):
  42. # 敏感词库列表
  43. word_list = []
  44. # 从云文档读取所有敏感词,添加到词库列表
  45. lists = Feishu.get_values_batch("follow", "kuaishou", "HIKVvs")
  46. for i in lists:
  47. for j in i:
  48. # 过滤空的单元格内容
  49. if j is None:
  50. pass
  51. else:
  52. word_list.append(j)
  53. return word_list
  54. # 下载规则
  55. @staticmethod
  56. def download_rule(d_duration, d_width, d_height, d_play_cnt, d_like_cnt, d_share_cnt):
  57. """
  58. 下载视频的基本规则
  59. :param d_duration: 时长
  60. :param d_width: 宽
  61. :param d_height: 高
  62. :param d_play_cnt: 播放量
  63. :param d_like_cnt: 点赞量
  64. :param d_share_cnt: 分享量
  65. :return: 满足规则,返回 True;反之,返回 False
  66. """
  67. if int(float(d_duration)) >= 40:
  68. if int(d_width) >= 0 or int(d_height) >= 0:
  69. if int(d_play_cnt) >= 5000:
  70. if int(d_like_cnt) >= 5000 or int(d_share_cnt) >= 1000:
  71. return True
  72. else:
  73. return False
  74. else:
  75. return False
  76. else:
  77. return False
  78. else:
  79. return False
  80. # 删除飞书关注人列表
  81. @classmethod
  82. def del_follow_user_from_feishu(cls, log_type):
  83. try:
  84. while True:
  85. follow_sheet = Feishu.get_values_batch(log_type, "kuaishou", "2OLxLr")
  86. if len(follow_sheet) == 1:
  87. Common.logger(log_type).info('删除完成\n')
  88. return
  89. else:
  90. for i in range(1, len(follow_sheet)):
  91. Feishu.dimension_range(log_type, "kuaishou", "2OLxLr", 'ROWS', i+1, i+1)
  92. time.sleep(0.5)
  93. break
  94. except Exception as e:
  95. Common.logger(log_type).error('del_follow_user_from_feishu异常:{}', e)
  96. # 从小程序中,关注用户列表同步至云文档
  97. @classmethod
  98. def get_follow_users_to_feishu(cls, log_type):
  99. try:
  100. follow_list = []
  101. follow_sheet = Feishu.get_values_batch(log_type, "kuaishou", "2OLxLr")
  102. url = "https://wxmini-api.uyouqu.com/rest/wd/wechatApp/relation/fol?"
  103. headers = {
  104. "content-type": "application/json",
  105. "Accept-Encoding": "gzip,compress,br,deflate",
  106. "User-Agent": 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_7_1 like Mac OS X)'
  107. ' AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148'
  108. ' MicroMessenger/8.0.20(0x18001442) NetType/WIFI Language/zh_CN',
  109. "Referer": str(cls.Referer),
  110. }
  111. params = {
  112. "__NS_sig3": str(cls.NS_sig3),
  113. "__NS_sig3_origin": str(cls.NS_sig3_origin)
  114. }
  115. cookies = {
  116. "did": str(cls.did),
  117. "preMinaVersion": "v3.109.0",
  118. "sid": "kuaishou.wechat.app",
  119. "appId": "ks_wechat_small_app_2",
  120. "clientid": "13",
  121. "client_key": "f60ac815",
  122. "kpn": "WECHAT_SMALL_APP",
  123. "kpf": "OUTSIDE_ANDROID_H5",
  124. "language": "zh_CN",
  125. "smallAppVersion": "v3.114.0",
  126. "session_key": str(cls.session_key),
  127. "unionid": str(cls.unionid),
  128. "eUserStableOpenId": str(cls.eUserStableOpenId),
  129. "openId": str(cls.openId),
  130. "eOpenUserId": str(cls.eOpenUserId),
  131. "kuaishou.wechat.app_st": str(cls.kuaishou_wechat_app_st),
  132. "passToken": str(cls.passToken),
  133. "userId": str(cls.userId)
  134. }
  135. json_text = {
  136. "count": 20,
  137. "pcursor": str(cls.follow_pcursor),
  138. "ftype": 1
  139. }
  140. urllib3.disable_warnings()
  141. r = requests.post(url=url, headers=headers, params=params,
  142. cookies=cookies, json=json_text, proxies=proxies, verify=False)
  143. if "fols" not in r.json():
  144. Common.logger(log_type).warning("从小程序中获取关注用户列表:{}", r.text)
  145. else:
  146. users = r.json()["fols"]
  147. for i in range(len(users)):
  148. uid = users[i]["targetId"]
  149. nick = users[i]["targetName"]
  150. sex = users[i]["targetSex"]
  151. description = users[i]["targetUserText"]
  152. if "followReason" in users[i]:
  153. follow_reason = users[i]["followReason"]
  154. else:
  155. follow_reason = ""
  156. follow_time = users[i]["time"]
  157. is_friend = users[i]["isFriend"]
  158. # print(f"uid:{uid}")
  159. follow_list.append(uid)
  160. # print(f"follow_list:{follow_list}")
  161. # 同步已关注的用户至云文档
  162. if uid not in [j for i in follow_sheet for j in i]:
  163. time.sleep(1)
  164. Feishu.insert_columns(log_type, "kuaishou", "2OLxLr", "ROWS", 1, 2)
  165. time.sleep(1)
  166. values = [[uid, nick, sex, description, follow_reason, follow_time, str(is_friend)]]
  167. Feishu.update_values(log_type, "kuaishou", "2OLxLr", "A2:L2", values)
  168. else:
  169. Common.logger(log_type).info("用户:{},在云文档中已存在", nick)
  170. cls.follow_pcursor = r.json()["pcursor"]
  171. # 翻页,直至到底了
  172. if cls.follow_pcursor != "no_more":
  173. cls.get_follow_users_to_feishu(log_type)
  174. else:
  175. Common.logger(log_type).info("从小程序中同步关注用户至云文档完成\n")
  176. except Exception as e:
  177. Common.logger(log_type).error("从小程序中,关注用户列表同步至云文档异常:{}\n", e)
  178. # 从云文档获取关注用户列表
  179. @classmethod
  180. def get_follow_users(cls, log_type):
  181. try:
  182. follow_sheet = Feishu.get_values_batch(log_type, "kuaishou", "2OLxLr")
  183. if len(follow_sheet) == 1:
  184. Common.logger(log_type).info("暂无关注用户")
  185. else:
  186. follow_dict = {}
  187. for i in range(1, len(follow_sheet)):
  188. uid = follow_sheet[i][0]
  189. nick = follow_sheet[i][1]
  190. if uid is None or nick is None:
  191. pass
  192. else:
  193. follow_dict[nick] = uid
  194. return follow_dict
  195. except Exception as e:
  196. Common.logger(log_type).error("从云文档获取关注用户列表异常:{}\n", e)
  197. # 从云文档获取取消关注用户列表
  198. @classmethod
  199. def get_unfollow_users(cls, log_type):
  200. try:
  201. unfollow_sheet = Feishu.get_values_batch(log_type, "kuaishou", "WRveYg")
  202. if len(unfollow_sheet) == 1:
  203. Common.logger(log_type).info("暂无取消关注用户")
  204. else:
  205. unfollow_list = []
  206. nick_list = []
  207. for i in range(1, len(unfollow_sheet)):
  208. uid = unfollow_sheet[i][0]
  209. nick = unfollow_sheet[i][1]
  210. nick_list.append(nick)
  211. unfollow_list.append(uid)
  212. Common.logger(log_type).info("取消关注用户列表:{}", nick_list)
  213. return unfollow_list
  214. except Exception as e:
  215. Common.logger(log_type).error("从云文档获取取消关注用户列表异常:{}", e)
  216. # 小程序:关注/取消关注用户
  217. @classmethod
  218. def follow_unfollow(cls, log_type, is_follow, uid):
  219. try:
  220. url = "https://wxmini-api.uyouqu.com/rest/wd/wechatApp/relation/follow?"
  221. headers = {
  222. "content-type": "application/json",
  223. "Accept-Encoding": "gzip,compress,br,deflate",
  224. "User-Agent": 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_7_1 like Mac OS X)'
  225. ' AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148'
  226. ' MicroMessenger/8.0.20(0x18001442) NetType/WIFI Language/zh_CN',
  227. "Referer": str(cls.Referer),
  228. }
  229. params = {
  230. "__NS_sig3": str(cls.NS_sig3),
  231. "__NS_sig3_origin": str(cls.NS_sig3_origin)
  232. }
  233. cookies = {
  234. "did": str(cls.did),
  235. "preMinaVersion": "v3.109.0",
  236. "sid": "kuaishou.wechat.app",
  237. "appId": "ks_wechat_small_app_2",
  238. "clientid": "13",
  239. "client_key": "f60ac815",
  240. "kpn": "WECHAT_SMALL_APP",
  241. "kpf": "OUTSIDE_ANDROID_H5",
  242. "language": "zh_CN",
  243. "smallAppVersion": "v3.114.0",
  244. "session_key": str(cls.session_key),
  245. "unionid": str(cls.unionid),
  246. "eUserStableOpenId": str(cls.eUserStableOpenId),
  247. "openId": str(cls.openId),
  248. "eOpenUserId": str(cls.eOpenUserId),
  249. "kuaishou.wechat.app_st": str(cls.kuaishou_wechat_app_st),
  250. "passToken": str(cls.passToken),
  251. "userId": str(cls.userId)
  252. }
  253. if is_follow == "follow":
  254. ftype = 1
  255. elif is_follow == "unfollow":
  256. ftype = 2
  257. else:
  258. ftype = 1
  259. json_text = {
  260. "touid": uid,
  261. "ftype": ftype,
  262. "page_ref": 84
  263. }
  264. r = requests.post(url=url, headers=headers, cookies=cookies, params=params, json=json_text)
  265. if is_follow == "follow":
  266. if r.json()["result"] != 1:
  267. Common.logger(log_type).warning("{}", r.text)
  268. else:
  269. Common.logger(log_type).info("关注:{}, {}", uid, r)
  270. else:
  271. if r.json()["result"] != 1:
  272. Common.logger(log_type).warning("{}", r.text)
  273. else:
  274. Common.logger(log_type).info("取消关注:{}, {}", uid, r)
  275. except Exception as e:
  276. Common.logger(log_type).error("关注/取消关注异常:{}", e)
  277. # 获取个人主页视频
  278. @classmethod
  279. def get_user_videos(cls, log_type, uid):
  280. try:
  281. time.sleep(1)
  282. url = "https://wxmini-api.uyouqu.com/rest/wd/wechatApp/feed/profile?"
  283. headers = {
  284. "content-type": "application/json",
  285. "Accept-Encoding": "gzip,compress,br,deflate",
  286. "User-Agent": 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_7_1 like Mac OS X) '
  287. 'AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 '
  288. 'MicroMessenger/8.0.26(0x18001a34) NetType/WIFI Language/zh_CN',
  289. "Referer": str(cls.Referer),
  290. }
  291. params = {
  292. "__NS_sig3": str(cls.NS_sig3),
  293. "__NS_sig3_origin": str(cls.NS_sig3_origin)
  294. }
  295. cookies = {
  296. "did": str(cls.did),
  297. "sid": "kuaishou.wechat.app",
  298. "appId": "ks_wechat_small_app_2",
  299. "clientid": "13",
  300. "client_key": "f60ac815",
  301. "kpn": "WECHAT_SMALL_APP",
  302. "kpf": "OUTSIDE_IOS_H5",
  303. "language": "zh_CN",
  304. "smallAppVersion": "v3.131.0",
  305. "mod": "iPhone(11<iPhone12%2C1>)",
  306. "sys": "iOS%2014.7.1",
  307. 'wechatVersion': '8.0.26',
  308. "brand": "iPhone",
  309. "session_key": str(cls.session_key),
  310. "unionid": str(cls.unionid),
  311. "eUserStableOpenId": str(cls.eUserStableOpenId),
  312. "openId": str(cls.openId),
  313. "eOpenUserId": str(cls.eOpenUserId),
  314. "kuaishou.wechat.app_st": str(cls.kuaishou_wechat_app_st),
  315. "passToken": str(cls.passToken),
  316. "userId": str(cls.userId)
  317. }
  318. json_text = {
  319. "count": 12,
  320. "pcursor": str(cls.person_pcursor),
  321. "eid": str(uid)
  322. }
  323. urllib3.disable_warnings()
  324. r = requests.post(url=url, headers=headers, params=params, cookies=cookies,
  325. json=json_text, proxies=proxies, verify=False)
  326. # Common.logger(log_type).info("response:{}\n\n", r.text)
  327. if "feeds" not in r.json():
  328. # Feishu.bot(log_type, "follow:get_videos_from_person:"+r.text)
  329. Common.logger(log_type).warning("response:{}", r.text)
  330. elif r.json()["feeds"] == 0:
  331. Common.logger(log_type).warning("用户主页无视频\n")
  332. return
  333. else:
  334. feeds = r.json()["feeds"]
  335. for i in range(len(feeds)):
  336. # 视频标题过滤话题及处理特殊字符
  337. kuaishou_title = feeds[i]["caption"]
  338. title_split1 = kuaishou_title.split(" #")
  339. if title_split1[0] != "":
  340. title1 = title_split1[0]
  341. else:
  342. title1 = title_split1[-1]
  343. title_split2 = title1.split(" #")
  344. if title_split2[0] != "":
  345. title2 = title_split2[0]
  346. else:
  347. title2 = title_split2[-1]
  348. title_split3 = title2.split("@")
  349. if title_split3[0] != "":
  350. title3 = title_split3[0]
  351. else:
  352. title3 = title_split3[-1]
  353. video_title = title3.strip().replace("\n", "") \
  354. .replace("/", "").replace("快手", "").replace(" ", "") \
  355. .replace(" ", "").replace("&NBSP", "").replace("\r", "") \
  356. .replace("#", "").replace(".", "。").replace("\\", "") \
  357. .replace(":", "").replace("*", "").replace("?", "") \
  358. .replace("?", "").replace('"', "").replace("<", "") \
  359. .replace(">", "").replace("|", "").replace("@", "")[:40]
  360. if "photoId" not in feeds[i]:
  361. video_id = "0"
  362. else:
  363. video_id = feeds[i]["photoId"]
  364. if "viewCount" not in feeds[i]:
  365. video_play_cnt = "0"
  366. else:
  367. video_play_cnt = feeds[i]["viewCount"]
  368. if "likeCount" not in feeds[i]:
  369. video_like_cnt = "0"
  370. else:
  371. video_like_cnt = feeds[i]["likeCount"]
  372. if "shareCount" not in feeds[i]:
  373. video_share_cnt = "0"
  374. else:
  375. video_share_cnt = feeds[i]["shareCount"]
  376. if "commentCount" not in feeds[i]:
  377. video_comment_cnt = "0"
  378. else:
  379. video_comment_cnt = feeds[i]["commentCount"]
  380. if "duration" not in feeds[i]:
  381. video_duration = "0"
  382. else:
  383. video_duration = int(int(feeds[i]["duration"]) / 1000)
  384. if "width" not in feeds[i] or "height" not in feeds[i]:
  385. video_width = "0"
  386. video_height = "0"
  387. else:
  388. video_width = feeds[i]["width"]
  389. video_height = feeds[i]["height"]
  390. if "timestamp" not in feeds[i]:
  391. video_send_time = "0"
  392. else:
  393. video_send_time = feeds[i]["timestamp"]
  394. cls.send_time = int(int(video_send_time) / 1000)
  395. if "userName" not in feeds[i]:
  396. user_name = "0"
  397. else:
  398. user_name = feeds[i]["userName"].strip().replace("\n", "") \
  399. .replace("/", "").replace("快手", "").replace(" ", "") \
  400. .replace(" ", "").replace("&NBSP", "").replace("\r", "")
  401. if "userId" not in feeds[i]:
  402. user_id = "0"
  403. else:
  404. user_id = feeds[i]["userId"]
  405. if "headUrl" not in feeds[i]:
  406. head_url = "0"
  407. else:
  408. head_url = feeds[i]["headUrl"]
  409. if "webpCoverUrls" in feeds[i]:
  410. cover_url = feeds[i]["webpCoverUrls"][-1]["url"]
  411. elif "coverUrls" not in feeds[i]:
  412. cover_url = "0"
  413. elif len(feeds[i]["coverUrls"]) == 0:
  414. cover_url = "0"
  415. else:
  416. cover_url = feeds[i]["coverUrls"][0]["url"]
  417. if "mainMvUrls" not in feeds[i]:
  418. video_url = "0"
  419. elif len(feeds[i]["mainMvUrls"]) == 0:
  420. video_url = "0"
  421. else:
  422. video_url = feeds[i]["mainMvUrls"][0]["url"]
  423. Common.logger(log_type).info("video_title:{}".format(video_title))
  424. Common.logger(log_type).info("user_name:{}".format(user_name))
  425. Common.logger(log_type).info("video_play_cnt:{}".format(video_play_cnt))
  426. Common.logger(log_type).info("video_like_cnt:{}".format(video_like_cnt))
  427. Common.logger(log_type).info("video_duration:{}秒".format(video_duration))
  428. Common.logger(log_type).info("video_send_time:{}".format(
  429. time.strftime("%Y/%m/%d %H:%M:%S", time.localtime(int(video_send_time) / 1000))))
  430. Common.logger(log_type).info("video_url:{}".format(video_url))
  431. # 过滤无效视频
  432. if video_id == "0" \
  433. or head_url == "0" \
  434. or cover_url == "0" \
  435. or video_url == "0" \
  436. or video_duration == "0" \
  437. or video_send_time == "0" \
  438. or user_name == "0" \
  439. or user_id == "0" \
  440. or video_title == "":
  441. Common.logger(log_type).info("无效视频\n")
  442. # 视频发布时间 <= 7 天
  443. elif int(time.time()) - int(int(video_send_time) / 1000) > 604800:
  444. Common.logger("follow").info("发布时间:{},超过7天\n", time.strftime(
  445. "%Y/%m/%d %H:%M:%S", time.localtime(int(video_send_time) / 1000)))
  446. cls.person_pcursor = ""
  447. return
  448. # 判断敏感词
  449. elif cls.download_rule(video_duration, video_width, video_height, video_play_cnt,
  450. video_like_cnt, video_share_cnt) is False:
  451. Common.logger(log_type).info("不满足下载规则\n".format(kuaishou_title))
  452. elif any(word if word in kuaishou_title else False for word in cls.sensitive_words()) is True:
  453. Common.logger(log_type).info("视频已中敏感词:{}\n".format(kuaishou_title))
  454. # 从云文档去重: 推荐榜_已下载表
  455. elif str(video_id) in [j for m in Feishu.get_values_batch(log_type, "kuaishou", "3cd128") for j in m]:
  456. Common.logger(log_type).info("该视频已下载:{}\n", video_title)
  457. # 从云文档去重: 用户主页_已下载表
  458. elif str(video_id) in [j for m in Feishu.get_values_batch(log_type, "kuaishou", "fYdA8F") for j in m]:
  459. Common.logger(log_type).info("该视频已下载:{}\n", video_title)
  460. # 从云文档去重:用户主页_feeds
  461. elif str(video_id) in [j for n in Feishu.get_values_batch(log_type, "kuaishou", "wW5cyb") for j in n]:
  462. Common.logger(log_type).info("该视频已在feeds中:{}\n", video_title)
  463. else:
  464. Feishu.insert_columns("follow", "kuaishou", "wW5cyb", "ROWS", 1, 2)
  465. # 获取当前时间
  466. get_feeds_time = int(time.time())
  467. # 工作表中写入数据
  468. values = [[time.strftime("%Y/%m/%d %H:%M:%S", time.localtime(int(get_feeds_time))),
  469. "用户主页",
  470. str(video_id),
  471. video_title,
  472. video_play_cnt,
  473. video_comment_cnt,
  474. video_like_cnt,
  475. video_share_cnt,
  476. video_duration,
  477. str(video_width) + "*" + str(video_height),
  478. time.strftime(
  479. "%Y/%m/%d %H:%M:%S", time.localtime(int(video_send_time) / 1000)),
  480. user_name,
  481. user_id,
  482. head_url,
  483. cover_url,
  484. video_url]]
  485. # 等待 1s,防止操作云文档太频繁,导致报错
  486. time.sleep(1)
  487. Feishu.update_values("follow", "kuaishou", "wW5cyb", "A2:T2", values)
  488. Common.logger("follow").info("添加视频至follow_feeds成功:{}\n", video_title)
  489. cls.get_person_video_count.append(video_id)
  490. # # 抓取足够多数量的视频
  491. # if len(cls.get_person_video_count) >= 1:
  492. # Common.logger(log_type).info('已抓取{}:{}条视频\n', user_name, len(cls.get_person_video_count))
  493. # cls.person_pcursor = ""
  494. # cls.get_person_video_count = []
  495. # return
  496. if r.json()["pcursor"] == 'no_more':
  497. Common.logger(log_type).info('没有更多作品了\n')
  498. return
  499. elif len(cls.get_person_video_count) < 1:
  500. Common.logger(log_type).info('休眠 10-20 秒,翻页')
  501. time.sleep(random.randint(10, 20))
  502. # 翻页
  503. cls.person_pcursor = r.json()["pcursor"]
  504. cls.get_user_videos(log_type, uid)
  505. except Exception as e:
  506. Common.logger(log_type).error("get_videos_from_person异常:{}\n", e)
  507. # 获取所有关注列表的用户视频
  508. @classmethod
  509. def get_videos_from_follow(cls, log_type, env):
  510. try:
  511. user_list = cls.get_follow_users(log_type)
  512. if len(user_list) == 0:
  513. Common.logger(log_type).warning('用户ID列表为空\n')
  514. else:
  515. while True:
  516. for k, v in user_list.items():
  517. Common.logger(log_type).info('正在获取 {} 主页视频\n', k)
  518. cls.person_pcursor = ""
  519. cls.get_user_videos(log_type, str(v))
  520. cls.run_download_publish(log_type, env)
  521. if len(cls.get_all_video_count) >= 100:
  522. cls.get_all_video_count = []
  523. Common.logger(log_type).info('今日已抓取{}条视频\n', len(cls.get_all_video_count))
  524. return
  525. else:
  526. Common.logger(log_type).info('随机休眠 10-30 秒\n')
  527. time.sleep(random.randint(10, 30))
  528. except Exception as e:
  529. Common.logger(log_type).error('get_videos_from_follow异常:{}\n', e)
  530. # 下载/上传
  531. @classmethod
  532. def download_publish(cls, log_type, env):
  533. try:
  534. follow_feeds_sheet = Feishu.get_values_batch(log_type, "kuaishou", "wW5cyb")
  535. for i in range(1, len(follow_feeds_sheet)):
  536. time.sleep(1)
  537. download_video_id = follow_feeds_sheet[i][2]
  538. download_video_title = follow_feeds_sheet[i][3]
  539. download_video_play_cnt = follow_feeds_sheet[i][4]
  540. download_video_comment_cnt = follow_feeds_sheet[i][5]
  541. download_video_like_cnt = follow_feeds_sheet[i][6]
  542. download_video_share_cnt = follow_feeds_sheet[i][7]
  543. download_video_duration = follow_feeds_sheet[i][8]
  544. download_video_resolution = follow_feeds_sheet[i][9]
  545. download_video_send_time = follow_feeds_sheet[i][10]
  546. download_user_name = follow_feeds_sheet[i][11]
  547. download_user_id = follow_feeds_sheet[i][12]
  548. download_head_url = follow_feeds_sheet[i][13]
  549. download_cover_url = follow_feeds_sheet[i][14]
  550. download_video_url = follow_feeds_sheet[i][15]
  551. Common.logger(log_type).info("正在判断第{}行,视频:{}", i + 1, download_video_title)
  552. # 过滤空行及空标题视频
  553. if download_video_id is None \
  554. or download_video_id == "" \
  555. or download_video_title is None \
  556. or download_video_title == "":
  557. # 删除行或列,可选 ROWS、COLUMNS
  558. Feishu.dimension_range(log_type, "kuaishou", "wW5cyb", "ROWS", i + 1, i + 1)
  559. Common.logger(log_type).warning("标题为空或空行,删除成功\n")
  560. return
  561. # 从已下载视频表中去重:推荐榜_已下载表
  562. elif str(download_video_id) in [j for m in Feishu.get_values_batch(
  563. log_type, "kuaishou", "3cd128") for j in m]:
  564. # 删除行或列,可选 ROWS、COLUMNS
  565. Feishu.dimension_range(log_type, "kuaishou", "wW5cyb", "ROWS", i + 1, i + 1)
  566. Common.logger(log_type).info("视频已下载:{},删除成功\n", download_video_title)
  567. return
  568. # 从已下载视频表中去重:用户主页_已下载表
  569. elif str(download_video_id) in [j for m in Feishu.get_values_batch(
  570. log_type, "kuaishou", "fYdA8F") for j in m]:
  571. # 删除行或列,可选 ROWS、COLUMNS
  572. Feishu.dimension_range(log_type, "kuaishou", "wW5cyb", "ROWS", i + 1, i + 1)
  573. Common.logger(log_type).info("视频已下载:{},删除成功\n", download_video_title)
  574. return
  575. else:
  576. # 下载封面
  577. Common.download_method(log_type=log_type, text="cover",
  578. d_name=str(download_video_title), d_url=str(download_cover_url))
  579. # 下载视频
  580. Common.download_method(log_type=log_type, text="video",
  581. d_name=str(download_video_title), d_url=str(download_video_url))
  582. # 保存视频信息至 "./videos/{download_video_title}/info.txt"
  583. with open("./videos/" + download_video_title + "/" + "info.txt",
  584. "a", encoding="UTF-8") as f_a:
  585. f_a.write(str(download_video_id) + "\n" +
  586. str(download_video_title) + "\n" +
  587. str(download_video_duration) + "\n" +
  588. str(download_video_play_cnt) + "\n" +
  589. str(download_video_comment_cnt) + "\n" +
  590. str(download_video_like_cnt) + "\n" +
  591. str(download_video_share_cnt) + "\n" +
  592. str(download_video_resolution) + "\n" +
  593. str(int(time.mktime(
  594. time.strptime(download_video_send_time, "%Y/%m/%d %H:%M:%S")))) + "\n" +
  595. str(download_user_name) + "\n" +
  596. str(download_head_url) + "\n" +
  597. str(download_video_url) + "\n" +
  598. str(download_cover_url) + "\n" +
  599. "kuaishou_person")
  600. Common.logger(log_type).info("==========视频信息已保存至info.txt==========")
  601. # 上传视频
  602. Common.logger(log_type).info("开始上传视频:{}".format(download_video_title))
  603. our_video_id = Publish.upload_and_publish(log_type, env, "play")
  604. our_video_link = "https://admin.piaoquantv.com/cms/post-detail/" + str(our_video_id) + "/info"
  605. Common.logger(log_type).info("视频上传完成:{}", download_video_title)
  606. # 视频ID工作表,插入首行
  607. time.sleep(1)
  608. Feishu.insert_columns(log_type, "kuaishou", "fYdA8F", "ROWS", 1, 2)
  609. # 视频ID工作表,首行写入数据
  610. upload_time = int(time.time())
  611. values = [[our_video_id,
  612. time.strftime("%Y/%m/%d %H:%M:%S", time.localtime(upload_time)),
  613. "用户主页",
  614. str(download_video_id),
  615. str(download_video_title),
  616. our_video_link,
  617. download_video_play_cnt,
  618. download_video_comment_cnt,
  619. download_video_like_cnt,
  620. download_video_share_cnt,
  621. download_video_duration,
  622. str(download_video_resolution),
  623. str(download_video_send_time),
  624. str(download_user_name),
  625. str(download_user_id),
  626. str(download_head_url),
  627. str(download_cover_url),
  628. str(download_video_url)]]
  629. time.sleep(1)
  630. Feishu.update_values(log_type, "kuaishou", "fYdA8F", "E2:Z2", values)
  631. cls.get_all_video_count.append(download_video_id)
  632. Common.logger(log_type).info("保存视频ID至已下载云文档成功:{}", download_video_title)
  633. # 删除行或列,可选 ROWS、COLUMNS
  634. Feishu.dimension_range(log_type, "kuaishou", "wW5cyb", "ROWS", i + 1, i + 1)
  635. Common.logger(log_type).info("视频:{},下载/上传成功\n", download_video_title)
  636. return
  637. except Exception as e:
  638. Feishu.dimension_range(log_type, "kuaishou", "wW5cyb", "ROWS", 2, 2)
  639. Common.logger(log_type).error("download_publish异常,删除成功:{}\n", e)
  640. # 执行下载/上传
  641. @classmethod
  642. def run_download_publish(cls, log_type, env):
  643. try:
  644. while True:
  645. follow_feeds_sheet = Feishu.get_values_batch(log_type, "kuaishou", "wW5cyb")
  646. if len(follow_feeds_sheet) == 1:
  647. Common.logger(log_type).info("下载/上传完成\n")
  648. break
  649. else:
  650. cls.download_publish(log_type, env)
  651. except Exception as e:
  652. Common.logger(log_type).error("run_download_publish异常:{}\n", e)
  653. if __name__ == "__main__":
  654. Follow.get_user_videos('follow', '240529022')
  655. pass