shipinhao_scheduling.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. import os
  2. import sys
  3. import datetime
  4. import time
  5. import uuid
  6. import requests
  7. sys.path.append(os.getcwd())
  8. from common import PiaoQuanPipeline, AliyunLogger
  9. from common.feishu import Feishu
  10. from common.db import MysqlHelper
  11. from common.mq import MQ
  12. def find_target_user(name, user_list):
  13. for obj in user_list:
  14. if obj["nickname"] == name:
  15. return obj
  16. else:
  17. continue
  18. return False
  19. class ShiPinHaoAccount:
  20. def __init__(self, platform, mode, rule_dict, user_dict, env):
  21. # self.token = token
  22. # self.cookie = cookie
  23. self.account_name = user_dict["name"]
  24. self.platform = platform
  25. self.mode = mode
  26. self.rule_dict = rule_dict
  27. self.user_dict = user_dict
  28. self.env = env
  29. self.mq = MQ(topic_name="topic_crawler_etl_" + self.env)
  30. def get_token_from_mysql(self):
  31. self.token = ""
  32. self.cookie = ""
  33. def get_history_id(self):
  34. """
  35. 从数据库表中读取 id
  36. """
  37. select_user_sql = f"""select name_id from accounts where name = "{self.account_name}" and platform = "{self.platform}" and useful = 1 limit 1"""
  38. name_id = MysqlHelper.get_values(
  39. log_type=self.mode,
  40. crawler=self.platform,
  41. sql=select_user_sql,
  42. env=self.env,
  43. machine="",
  44. )
  45. if name_id:
  46. return name_id[0]
  47. else:
  48. return False
  49. def get_account_id(self):
  50. # 读历史数据,如果存在 id,则直接返回 id
  51. history_id = self.get_history_id()
  52. if history_id:
  53. return history_id
  54. else:
  55. url = "https://mp.weixin.qq.com/cgi-bin/videosnap"
  56. params = {
  57. "action": "search",
  58. "scene": "1",
  59. "buffer": "",
  60. "query": self.account_name,
  61. "count": "21",
  62. "token": self.token,
  63. "lang": "zh_CN",
  64. "f": "json",
  65. "ajax": "1",
  66. }
  67. headers = {
  68. "authority": "mp.weixin.qq.com",
  69. "accept": "*/*",
  70. "accept-language": "en,zh-CN;q=0.9,zh;q=0.8",
  71. "cookie": self.cookie,
  72. "referer": "https://mp.weixin.qq.com/cgi-bin/appmsg?t=media/appmsg_edit_v2&action=edit&isNew=1&type=77&createType=0&token={}&lang=zh_CN".format(
  73. self.token
  74. ),
  75. "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36",
  76. "x-requested-with": "XMLHttpRequest",
  77. }
  78. response = requests.request("GET", url, headers=headers, params=params)
  79. user_list = response.json()["acct_list"]
  80. target_user = find_target_user(name=self.account_name, user_list=user_list)
  81. # 写入 MySql 数据库
  82. if target_user:
  83. update_sql = f"""INSERT INTO accounts (name, name_id, platform) values ("{self.account_name}", "{target_user['username']}", "{self.platform}")"""
  84. print(update_sql)
  85. MysqlHelper.update_values(
  86. log_type=self.mode,
  87. crawler=self.platform,
  88. sql=update_sql,
  89. env=self.env,
  90. machine="",
  91. )
  92. return target_user["username"]
  93. else:
  94. return False
  95. def get_account_videos(self):
  96. user_id = self.get_account_id()
  97. if user_id:
  98. url = "https://mp.weixin.qq.com/cgi-bin/videosnap"
  99. headers = {
  100. "authority": "mp.weixin.qq.com",
  101. "accept": "*/*",
  102. "accept-language": "en,zh-CN;q=0.9,zh;q=0.8",
  103. "cookie": self.cookie,
  104. "referer": "https://mp.weixin.qq.com/cgi-bin/appmsg?t=media/appmsg_edit_v2&action=edit&isNew=1&type=77&createType=0&token={}&lang=zh_CN".format(
  105. self.token
  106. ),
  107. "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36",
  108. "x-requested-with": "XMLHttpRequest",
  109. }
  110. buffer = "" # 翻页指示器
  111. while True:
  112. params = {
  113. "action": "get_feed_list",
  114. "username": user_id,
  115. "buffer": buffer,
  116. "count": "15",
  117. "scene": "1",
  118. "token": self.token,
  119. "lang": "zh_CN",
  120. "f": "json",
  121. "ajax": "1",
  122. }
  123. response = requests.request("GET", url, headers=headers, params=params)
  124. res_json = response.json()
  125. # 开始判断视频是否有信息,是否频控
  126. if res_json["base_resp"]["err_msg"] == "invalid session":
  127. AliyunLogger.logging(
  128. code="2000",
  129. platform=self.platform,
  130. mode=self.mode,
  131. env=self.env,
  132. message=f"status_code:{response.status_code}, get_videoList:{response.text}\n",
  133. )
  134. if 20 >= datetime.datetime.now().hour >= 10:
  135. Feishu.bot(
  136. log_type=self.mode,
  137. crawler=self.platform,
  138. text="视频号Token 过期啦"
  139. # text=f"{token_dict['title']}\n操作人:{token_dict['operator']}\n更换日期:{token_dict['update_time']} \n频控啦,请扫码更换其他公众号token\nhttps://mp.weixin.qq.com/"
  140. )
  141. time.sleep(60 * 15)
  142. continue
  143. if res_json["base_resp"]["err_msg"] == "freq control":
  144. AliyunLogger.logging(
  145. code="2000",
  146. platform=self.platform,
  147. mode=self.mode,
  148. env=self.env,
  149. message=f"status_code:{response.status_code}, get_videoList:{response.text}\n",
  150. )
  151. if 20 >= datetime.datetime.now().hour >= 10:
  152. Feishu.bot(
  153. log_type=self.mode,
  154. crawler=self.platform,
  155. text="视频号Token 过期啦"
  156. # text=f"{token_dict['title']}\n操作人:{token_dict['operator']}\n更换日期:{token_dict['update_time']} \n频控啦,请扫码更换其他公众号token\nhttps://mp.weixin.qq.com/"
  157. )
  158. time.sleep(60 * 15)
  159. continue
  160. if not res_json["list"]:
  161. AliyunLogger.logging(
  162. code="2000",
  163. platform=self.platform,
  164. mode=self.mode,
  165. env=self.env,
  166. message="没有更多视频了",
  167. )
  168. return
  169. else:
  170. buffer = res_json["last_buff"]
  171. for obj in res_json["list"]:
  172. try:
  173. AliyunLogger.logging(
  174. code="1001",
  175. platform=self.platform,
  176. mode=self.mode,
  177. message="扫描到一条视频",
  178. env=self.env,
  179. data=obj,
  180. )
  181. repeat_flag = self.process_video_obj(obj)
  182. if not repeat_flag:
  183. return
  184. except Exception as e:
  185. AliyunLogger.logging(
  186. code="3000",
  187. platform=self.platform,
  188. mode=self.mode,
  189. env=self.env,
  190. message=f"抓取单条视频异常:{e}\n",
  191. )
  192. else:
  193. AliyunLogger.logging(
  194. code="3000",
  195. platform=self.platform,
  196. mode=self.mode,
  197. env=self.env,
  198. message="{}\t获取 id 失败".format(self.account_name),
  199. )
  200. def process_video_obj(self, video_obj):
  201. trace_id = self.platform + str(uuid.uuid1())
  202. video_dict = {
  203. "video_id": video_obj["nonce_id"],
  204. "video_title": video_obj["desc"],
  205. "publish_time_stamp": int(time.time()),
  206. "publish_time_str": time.strftime(
  207. "%Y-%m-%d %H:%M:%S", time.localtime(int(time.time()))
  208. ),
  209. "play_cnt": 0,
  210. "comment_cnt": 0,
  211. "like_cnt": 0,
  212. "share_cnt": 0,
  213. "user_id": self.user_dict["user_id"],
  214. "cover_url": video_obj["media"]["cover_url"],
  215. "video_url": video_obj["media"]["video_url"],
  216. "avatar_url": video_obj["head_url"],
  217. "width": video_obj["media"]["width"],
  218. "height": video_obj["media"]["height"],
  219. "duration": video_obj["media"]["video_play_len_s"],
  220. "platform": self.platform,
  221. "strategy": self.mode,
  222. "crawler_rule": self.rule_dict,
  223. "session": f"shipinhao-author-{int(time.time())}",
  224. }
  225. # 无更新时间,去重即可
  226. pipeline = PiaoQuanPipeline(
  227. platform=self.platform,
  228. mode=self.mode,
  229. item=video_dict,
  230. rule_dict=self.rule_dict,
  231. env=self.env,
  232. trace_id=trace_id,
  233. )
  234. if not pipeline.repeat_video():
  235. return False
  236. else:
  237. video_dict["out_user_id"] = video_dict["user_id"]
  238. video_dict["user_id"] = self.user_dict["uid"]
  239. video_dict["publish_time"] = video_dict["publish_time_str"]
  240. self.mq.send_msg(video_dict)
  241. AliyunLogger.logging(
  242. code="1002",
  243. platform=self.platform,
  244. mode=self.mode,
  245. env=self.env,
  246. data=video_dict,
  247. trace_id=trace_id,
  248. message="成功发送 MQ 至 ETL",
  249. )
  250. return True
  251. if __name__ == "__main__":
  252. temp_token = "2080949641"
  253. temp_cookie = "ua_id=bw4VuFJr6fAuSkwdAAAAAClaW0m9Aua-6IfHaXU_zpo=; wxuin=95302180931488; mm_lang=zh_CN; RK=kreEMgtMMJ; ptcz=8fd1b267c98a1185bbe6455a081f1264048ee388363ca305d9ef4812892c7900; qq_domain_video_guid_verify=2ba78a5010233582; poc_sid=HOinP2Wj322Ex737kV651Zqy6y8fSprOUUvaegBg; _qimei_q36=; _qimei_h38=9eea33ea92afe8a922333fce03000001317916; pgv_pvid=9056371236; _clck=3930572231|1|fgk|0; uuid=6562bbd8859230ce4120dfa063c76997; rand_info=CAESIGAatjSIjvxVJVDxRDN7F/CNFWMifvAVqje98rd++8UY; slave_bizuin=3236647229; data_bizuin=3236647229; bizuin=3236647229; data_ticket=qm3i6jRhObs1yKHttGh0gVI02Mz7FTPfatn0RMLdaWyD7Ukcokm5Dc3mmYLQUZPg; slave_sid=UWxjZnhBREZRRTNKZ3dYZTlYRE9Db2lxQUhOM3lZUlRoMkV0MG1wdVVudGpQTWxnVkxzYW5pV2c3NjB3bnAyQ2lPaXBBVVRPazEybWtKSVEzTnUyazZ6WEJsdnFaWWVDaUFrM3pTTXRkeUNJS3RNVTc2NFRBWkZiVGQzYllacEFRalBBZ2tXZlltblJYS2VS; slave_user=gh_d284c09295eb; xid=cb96e6ba4b4960d74a22869b1bb21406; _clsk=z77guf|1699532621466|4|1|mp.weixin.qq.com/weheat-agent/payload/record"
  254. SP = ShiPinHaoAccount(
  255. token=temp_token,
  256. cookie=temp_cookie,
  257. account_name="心煤",
  258. platform="shipinhao",
  259. mode="author",
  260. rule_dict={},
  261. env="prod",
  262. )
  263. SP.get_account_videos()