telegram 群组监控 / 群组功能
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

370 lines
15 KiB

8 months ago
  1. import random
  2. from pymysql.converters import escape_string
  3. import json, os
  4. import sys
  5. from telethon.tl.functions.messages import GetFullChatRequest, ImportChatInviteRequest
  6. from tg_utils.tg_api import send_messages
  7. root_path = os.path.abspath(os.path.dirname(__file__)).split('telegram-crawler')[0] + "telegram-crawler"
  8. sys.path.append(root_path)
  9. from tg_utils.tg_model import GroupFunc
  10. from utils.tools import get_group_hash, get_data_from_sql, get_data_from_sql1
  11. from telethon.tl.types import ChannelParticipantsAdmins, Updates, PeerChannel, Channel, Message
  12. from config import PROXY, logger, CRAWLER_DB_CONF, TG_ROBOT_ACCOUNT_TABLE, TG_ROBOT_ACCOUNT_GROUP_TABLE
  13. import asyncio
  14. from telethon.tl.functions.channels import JoinChannelRequest
  15. from utils.MysqlData import MysqlPoolClient
  16. """
  17. """
  18. async def get_groups(client, api_hash):
  19. """
  20. :param client:
  21. :return:
  22. """
  23. group_list = []
  24. client_mysql = MysqlPoolClient(CRAWLER_DB_CONF)
  25. dialogs = await client.get_dialogs() # 获取所有群组的 ID 和名称
  26. groups = [dialog for dialog in dialogs if dialog.is_channel] # 获取 `Chat` 、`Channel`
  27. for group in groups:
  28. group_ids = {
  29. "group_id": group.id, # 监听的群组或者频道id
  30. "group_name": group.name, # 群组或者频道名称
  31. "participants_count": group.entity.participants_count, # 群人数
  32. "group_owner": "", # 群组拥有人 可能没有
  33. "is_group": group.is_group, # 为群还是频道
  34. "description": "", # 描述
  35. "discussion": {} # 相关的讨论组信息
  36. }
  37. # res = await client.get_participants(group, filter=ChannelParticipantsAdmins) # 管理员
  38. # print(len(res), res[0])
  39. if group.entity.username:
  40. group_ids["group_owner"] = group.entity.username
  41. elif group.entity.usernames:
  42. group_ids["group_owner"] = group.entity.usernames[0].username
  43. if group_ids["group_owner"]:
  44. detail = await GroupFunc.get_related_group(client, group_ids["group_owner"])
  45. group_ids.update(detail)
  46. pass
  47. if not group_ids["group_owner"]:
  48. logger.error(f"不存在username: {group_ids}")
  49. continue
  50. group_list.append(group_ids)
  51. logger.info(f"Group: {group_ids}")
  52. telegram_link = f"https://t.me/{group_ids['group_owner']}"
  53. sql = f"INSERT INTO {TG_ROBOT_ACCOUNT_GROUP_TABLE}(`api_hash`, `group_id`, `group_link`, `group_hash`, `group_title`, `group_status`, `create_time`, `update_time`) " \
  54. "VALUES('%s','%s', '%s', '%s', '%s', '%s', NOW(), NOW()) on duplicate key update update_time=Now(), group_title=values(group_title), group_id=values(group_id)" \
  55. % (api_hash, group.id, telegram_link, get_group_hash(f"{api_hash+telegram_link}"), escape_string(group.name), 1)
  56. logger.info(sql)
  57. client_mysql.getOne(sql)
  58. # break
  59. sql_robot = f"update {TG_ROBOT_ACCOUNT_TABLE} set total_group=%d where api_hash='%s'" % (len(group_list), api_hash)
  60. client_mysql.getOne(sql_robot)
  61. logger.info(f"get group lengths is {len(group_list)}")
  62. async def join_channel(client, channel, is_private=False):
  63. """
  64. :param client:
  65. :param channel:
  66. :param is_private: joinchat
  67. :return:
  68. """
  69. if is_private:
  70. res = await client(ImportChatInviteRequest(channel))
  71. else:
  72. res = await client(JoinChannelRequest(channel=channel))
  73. logger.info(res) # Updates.chats[0].username
  74. if res and isinstance(res, Updates):
  75. chat = res.chats[0]
  76. # res = await get_group(client, res.chats[0])
  77. if isinstance(chat, Channel):
  78. res = {"title": chat.title, "group_id": -1000000000000 - res.chats[0].id, "allow_sending": None}
  79. is_banned = await GroupFunc.is_banned(client, chat) # 查看是否被禁
  80. if not is_banned:
  81. allow_status = await GroupFunc.get_group_rights(client, chat)
  82. res["allow_sending"] = allow_status if allow_status else None
  83. logger.info(f"返回的权限信息 ! => {res}")
  84. return res
  85. return False
  86. async def leave_channel(client, channel):
  87. """
  88. 退
  89. This method can be used as a user and as a bot. However,
  90. bots will only be able to use it to leave groups and channels
  91. (trying to delete a private conversation will do nothing).
  92. :param client:
  93. :param channel:
  94. :return:
  95. """
  96. res = await client.delete_dialog(channel) # leave groups and channels
  97. logger.info(res) # Updates.chats[0].username
  98. if res and isinstance(res, Updates):
  99. res = {"title": res.chats[0].title, "group_id": -1000000000000 - res.chats[0].id}
  100. return res
  101. return False
  102. async def main(session_string, api_id, api_hash, channel="", is_private=False, is_leave=False):
  103. """
  104. Telethon
  105. :param session_string:
  106. :param api_id:
  107. :param api_hash:
  108. :param channel:
  109. :param is_private:
  110. :param is_private: 退
  111. :return:
  112. """
  113. client = await GroupFunc.login(session_string, api_id, api_hash)
  114. # print(StringSession.save(client.session)) # 把session保存为字符串形式
  115. try:
  116. if is_leave:
  117. res = await leave_channel(client, channel) # 退群
  118. else:
  119. res = await join_channel(client, channel, is_private=is_private) # 加群
  120. except Exception as e:
  121. logger.error(f"join error: {e}")
  122. res = str(e)
  123. # 断开连接
  124. await client.disconnect()
  125. return res
  126. async def init_group(session_string, api_id, api_hash):
  127. """
  128. :param session_string:
  129. :param api_id:
  130. :param api_hash:
  131. :return:
  132. """
  133. # 创建 Telethon 客户端对象并进行身份验证
  134. client = await GroupFunc.login(session_string, api_id, api_hash)
  135. await get_groups(client, api_hash) # 获取群组信息
  136. await client.disconnect()
  137. async def mul_account():
  138. """
  139. :return:
  140. """
  141. client_mysql = MysqlPoolClient(CRAWLER_DB_CONF)
  142. sql = f"select * from {TG_ROBOT_ACCOUNT_TABLE} order by update_time"
  143. results = client_mysql.getAll(sql)
  144. tasks = []
  145. for i in results:
  146. api_id = i["api_id"]
  147. api_hash = i["api_hash"]
  148. session_string = i["session_string"]
  149. print(i)
  150. await init_group(session_string, api_id, api_hash)
  151. # tasks.append(init_group(session_string, api_id, api_hash))
  152. # await get_login(api_id, api_hash, client_mysql)
  153. # break
  154. # await asyncio.gather(*tasks)
  155. def update_sql(res, telegram_link, group, client_mysql):
  156. """
  157. sql
  158. :param res:
  159. :param telegram_link:
  160. :param group:
  161. :param client_mysql:
  162. :return:
  163. """
  164. state_203 = "You have successfully requested to join this chat or channel"
  165. if isinstance(res, dict) or state_203 in res: # 成功加群和203表示更新
  166. flag = True if isinstance(res, dict) else False
  167. group_status = 1 if flag else 0
  168. group_id = res["group_id"] if flag else ""
  169. group_title = escape_string(res["title"]) if flag else ""
  170. sql = f"INSERT INTO {TG_ROBOT_ACCOUNT_GROUP_TABLE}(`api_hash`, `group_id`, `group_link`, `group_hash`, `group_title`, `group_status`, `create_time`, `update_time`) " \
  171. "VALUES('%s','%s', '%s', '%s', '%s', '%s', NOW(), NOW()) on duplicate key update update_time=Now(), group_title=values(group_title), group_id=values(group_id) " \
  172. % (group["api_hash"], group_id, telegram_link,
  173. get_group_hash(f"{group['api_hash'] + telegram_link}"),
  174. group_title, group_status)
  175. client_mysql.getOne(sql)
  176. if flag: # 成功加群再加1
  177. sql_robot = f"update {TG_ROBOT_ACCOUNT_TABLE} set total_group=%d where api_hash='%s'" % (
  178. group["total_group"] + 1, group["api_hash"])
  179. client_mysql.getOne(sql_robot)
  180. else:
  181. sql_robot = f"update {TG_ROBOT_ACCOUNT_TABLE} set update_time=NOW() where api_hash='%s'" % (group["api_hash"])
  182. client_mysql.getOne(sql_robot)
  183. def update_sql1(res, telegram_link, group, client_mysql):
  184. """
  185. 退sql
  186. :param res:
  187. :param telegram_link:
  188. :param group:
  189. :param client_mysql:
  190. :return:
  191. """
  192. if isinstance(res, dict): # 成功退群
  193. # 修改task状态
  194. sql = f"UPDATE {TG_ROBOT_ACCOUNT_GROUP_TABLE} set group_status=0 where group_link='%s'" % (telegram_link)
  195. client_mysql.getOne(sql)
  196. # account表状态
  197. sql_robot = f"update {TG_ROBOT_ACCOUNT_TABLE} set total_group=%d where api_hash='%s'" % (
  198. group["total_group"] - 1, group["api_hash"])
  199. client_mysql.getOne(sql_robot)
  200. else:
  201. sql_robot = f"update {TG_ROBOT_ACCOUNT_TABLE} set update_time=NOW() where api_hash='%s'" % (group["api_hash"])
  202. client_mysql.getOne(sql_robot)
  203. async def run(telegram_link, channel, is_private=False, is_leave=False):
  204. """
  205. sql
  206. :param telegram_link:
  207. :param channel:
  208. :param is_private:
  209. :param is_leave: 退
  210. :return:
  211. """
  212. client_mysql = MysqlPoolClient(CRAWLER_DB_CONF)
  213. # sql_group = f"select * from {TG_ROBOT_ACCOUNT_GROUP_TABLE} where group_link='%s'" % telegram_link
  214. sql_group = f"select a.*, b.api_id, b.session_string, b.total_group from {TG_ROBOT_ACCOUNT_GROUP_TABLE} a, {TG_ROBOT_ACCOUNT_TABLE} b where group_link='%s' and a.api_hash=b.api_hash" % telegram_link
  215. count, group = client_mysql.getOne(sql_group)
  216. if is_leave: # 退群
  217. if group: # 以前加过
  218. state = group["group_status"]
  219. if state == 0: return "退群成功" # 没加成功/已经退过群
  220. else: # 走退群流程 退群+更新sql
  221. res = await main(group["session_string"], group["api_id"], group["api_hash"], channel, is_leave=True)
  222. logger.info(f"退群,账号信息:{group['api_id']}")
  223. update_sql1(res, telegram_link, group, client_mysql)
  224. return "退群成功"
  225. else:
  226. return "该群不存在"
  227. if group:
  228. state = group["group_status"]
  229. if state == 0: # 状态为0 表示需要同意
  230. res = await main(group["session_string"], group["api_id"], group["api_hash"], channel, is_private)
  231. logger.info(f"重新加群,账号信息:{group['api_id']}")
  232. update_sql(res, telegram_link, group, client_mysql)
  233. return res
  234. return {"title": group["group_title"], "group_id": group["group_id"]}
  235. else:
  236. sql_robot = f"select * from {TG_ROBOT_ACCOUNT_TABLE} order by total_group, update_time"
  237. count, group = client_mysql.getOne(sql_robot)
  238. logger.info(f"获取账号:{group['api_id']}")
  239. res = await main(group["session_string"], group["api_id"], group["api_hash"], channel, is_private)
  240. update_sql(res, telegram_link, group, client_mysql)
  241. return res
  242. async def _replay(telegram_link, channel, message_list):
  243. """
  244. :param telegram_link:
  245. :param channel:
  246. :param message_list:
  247. :return:
  248. """
  249. # 先查询这个群是否加群成功
  250. sql_group = f"select a.*, b.api_id, b.session_string, b.total_group from {TG_ROBOT_ACCOUNT_GROUP_TABLE} a, {TG_ROBOT_ACCOUNT_TABLE} b where group_link='%s' and a.api_hash=b.api_hash" % telegram_link
  251. group = get_data_from_sql(sql_group)
  252. result = {
  253. "send_message_status": "", # 发送成功 视为成功
  254. "allow_sending": None
  255. }
  256. # # TODO 测试账号
  257. # group = {
  258. # "group_status": 1,
  259. # "api_id": "22955009",
  260. # "api_hash": "c5581d1ed5880f6e0b1734dad1d4a10d",
  261. # "session_string": "1BVtsOIEBuwG1-0k5xGzlopl4G7ghAhBPorz1HcaSkfcuDEsYKSJKQ0nCLYbMTT7yplnfJHEYXR-rGY5FoEyrAYsW86obngGwxLDpl9b9IuGhxCDlFSo_O2AIPw3Duf8tc5DewfNGqZ7U8CbpEjFcpEaRRy23Z93DVZtcYHBLp6vLh5iLndKXanW4vxArJODjVklAKwxqDD5LGixvoeP5p9W1VJAeihJxqEl0UHL12dF4T7MYcdhW-ylA4NvCtgeIaqiVwZ1VuVyiyLNYaMrpZZfdmfOGkYapp-1ubYE8XKAQ8jau3XnWCLvk50w6L9DaWp8PSdQ7RRZf5G2swSyurHCK6quAVfA="
  262. # }
  263. if group and group["group_status"]: # 群组存在 且加群成功
  264. client = await GroupFunc.login(group["session_string"], group["api_id"], group["api_hash"])
  265. group_entity = await client.get_entity(channel) # 获取群组类型
  266. is_banned = await GroupFunc.is_banned(client, group_entity) # 查看是否被禁
  267. if not is_banned:
  268. allow_status = await GroupFunc.get_group_rights(client, group_entity)
  269. result["allow_sending"] = allow_status if allow_status else None
  270. if allow_status: # 成功则返回消息对象 不成功则返回
  271. mess_status = await send_messages(client, group_entity, message_list, allow_status)
  272. logger.info(mess_status)
  273. result["send_message_status"] = "发送成功" if isinstance(mess_status, Message) else mess_status
  274. else:
  275. result["send_message_status"] = "当前群组不支持发送消息"
  276. else:
  277. result["send_message_status"] = "群组管理员禁止发送消息"
  278. await client.disconnect()
  279. else:
  280. result["send_message_status"] = "群组并未添加,检查群组状态"
  281. return result
  282. async def _detail(telegram_link, file="profile"):
  283. """
  284. :param telegram_link:
  285. :return:
  286. """
  287. sql_group = f"select api_id, session_string, api_hash from {TG_ROBOT_ACCOUNT_TABLE}"
  288. group_list = get_data_from_sql1(sql_group)
  289. group = random.choice(group_list) # 随机选择一个账号
  290. # 测试账号
  291. # group = {
  292. # "group_status": 1,
  293. # "api_id": "22955009",
  294. # "api_hash": "c5581d1ed5880f6e0b1734dad1d4a10d",
  295. # "session_string": "1BVtsOIEBuwG1-0k5xGzlopl4G7ghAhBPorz1HcaSkfcuDEsYKSJKQ0nCLYbMTT7yplnfJHEYXR-rGY5FoEyrAYsW86obngGwxLDpl9b9IuGhxCDlFSo_O2AIPw3Duf8tc5DewfNGqZ7U8CbpEjFcpEaRRy23Z93DVZtcYHBLp6vLh5iLndKXanW4vxArJODjVklAKwxqDD5LGixvoeP5p9W1VJAeihJxqEl0UHL12dF4T7MYcdhW-ylA4NvCtgeIaqiVwZ1VuVyiyLNYaMrpZZfdmfOGkYapp-1ubYE8XKAQ8jau3XnWCLvk50w6L9DaWp8PSdQ7RRZf5G2swSyurHCK6quAVfA="
  296. # }
  297. client = await GroupFunc.login(group["session_string"], group["api_id"], group["api_hash"])
  298. group_detail = await GroupFunc.get_group(client, telegram_link, file=file) # 会自动上传头像
  299. await client.disconnect() # 断开链接
  300. logger.info(f"当前使用账号: {group['api_id']} => {telegram_link} => {group_detail}")
  301. return group_detail
  302. if __name__ == "__main__":
  303. # 运行主循环
  304. loop = asyncio.get_event_loop()
  305. try:
  306. loop.run_until_complete(_detail("rtnoticias"))
  307. except Exception as e:
  308. print(f"An error occurred: {e}")