itv_all.py 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  1. import time
  2. import concurrent.futures
  3. from selenium import webdriver
  4. from selenium.webdriver.chrome.options import Options
  5. import requests
  6. import re
  7. import os
  8. import threading
  9. from queue import Queue
  10. import eventlet
  11. eventlet.monkey_patch()
  12. urls = [
  13. "https://fofa.info/result?qbase64=ImlwdHYvbGl2ZS96aF9jbi5qcyIgJiYgY291bnRyeT0iQ04iICYmIHJlZ2lvbj0iSGViZWki", # Hebei (河北)
  14. "https://fofa.info/result?qbase64=ImlwdHYvbGl2ZS96aF9jbi5qcyIgJiYgY291bnRyeT0iQ04iICYmIHJlZ2lvbj0iYmVpamluZyI%3D", # Beijing (北京)
  15. "https://fofa.info/result?qbase64=ImlwdHYvbGl2ZS96aF9jbi5qcyIgJiYgY291bnRyeT0iQ04iICYmIHJlZ2lvbj0iZ3Vhbmdkb25nIg%3D%3D", # Guangdong (广东)
  16. "https://fofa.info/result?qbase64=ImlwdHYvbGl2ZS96aF9jbi5qcyIgJiYgY291bnRyeT0iQ04iICYmIHJlZ2lvbj0ic2hhbmdoYWki", # Shanghai (上海)
  17. "https://fofa.info/result?qbase64=ImlwdHYvbGl2ZS96aF9jbi5qcyIgJiYgY291bnRyeT0iQ04iICYmIHJlZ2lvbj0idGlhbmppbiI%3D", # Tianjin (天津)
  18. "https://fofa.info/result?qbase64=ImlwdHYvbGl2ZS96aF9jbi5qcyIgJiYgY291bnRyeT0iQ04iICYmIHJlZ2lvbj0iY2hvbmdxaW5nIg%3D%3D", # Chongqing (重庆)
  19. "https://fofa.info/result?qbase64=ImlwdHYvbGl2ZS96aF9jbi5qcyIgJiYgY291bnRyeT0iQ04iICYmIHJlZ2lvbj0ic2hhbnhpIg%3D%3D", # Shanxi (山西)
  20. "https://fofa.info/result?qbase64=ImlwdHYvbGl2ZS96aF9jbi5qcyIgJiYgY291bnRyeT0iQ04iICYmIHJlZ2lvbj0iU2hhYW54aSI%3D", # Shaanxi (陕西)
  21. "https://fofa.info/result?qbase64=ImlwdHYvbGl2ZS96aF9jbi5qcyIgJiYgY291bnRyeT0iQ04iICYmIHJlZ2lvbj0ibGlhb25pbmci", # Liaoning (辽宁)
  22. "https://fofa.info/result?qbase64=ImlwdHYvbGl2ZS96aF9jbi5qcyIgJiYgY291bnRyeT0iQ04iICYmIHJlZ2lvbj0iamlhbmdzdSI%3D", # Jiangsu (江苏)
  23. "https://fofa.info/result?qbase64=ImlwdHYvbGl2ZS96aF9jbi5qcyIgJiYgY291bnRyeT0iQ04iICYmIHJlZ2lvbj0iemhlamlhbmci", # Zhejiang (浙江)
  24. "https://fofa.info/result?qbase64=ImlwdHYvbGl2ZS96aF9jbi5qcyIgJiYgY291bnRyeT0iQ04iICYmIHJlZ2lvbj0i5a6J5b69Ig%3D%3D", # Anhui (安徽)
  25. "https://fofa.info/result?qbase64=ImlwdHYvbGl2ZS96aF9jbi5qcyIgJiYgY291bnRyeT0iQ04iICYmIHJlZ2lvbj0iRnVqaWFuIg%3D%3D", # 福建
  26. "https://fofa.info/result?qbase64=ImlwdHYvbGl2ZS96aF9jbi5qcyIgJiYgY291bnRyeT0iQ04iICYmIHJlZ2lvbj0i5rGf6KW%2FIg%3D%3D", # 江西
  27. "https://fofa.info/result?qbase64=ImlwdHYvbGl2ZS96aF9jbi5qcyIgJiYgY291bnRyeT0iQ04iICYmIHJlZ2lvbj0i5bGx5LicIg%3D%3D", # 山东
  28. "https://fofa.info/result?qbase64=ImlwdHYvbGl2ZS96aF9jbi5qcyIgJiYgY291bnRyeT0iQ04iICYmIHJlZ2lvbj0i5rKz5Y2XIg%3D%3D", # 河南
  29. "https://fofa.info/result?qbase64=ImlwdHYvbGl2ZS96aF9jbi5qcyIgJiYgY291bnRyeT0iQ04iICYmIHJlZ2lvbj0i5rmW5YyXIg%3D%3D", # 湖北
  30. "https://fofa.info/result?qbase64=ImlwdHYvbGl2ZS96aF9jbi5qcyIgJiYgY291bnRyeT0iQ04iICYmIHJlZ2lvbj0i5rmW5Y2XIg%3D%3D" # 湖南
  31. ]
  32. def modify_urls(url):
  33. modified_urls = []
  34. ip_start_index = url.find("//") + 2
  35. ip_end_index = url.find(":", ip_start_index)
  36. base_url = url[:ip_start_index] # http:// or https://
  37. ip_address = url[ip_start_index:ip_end_index]
  38. port = url[ip_end_index:]
  39. ip_end = "/iptv/live/1000.json?key=txiptv"
  40. for i in range(1, 256):
  41. modified_ip = f"{ip_address[:-1]}{i}"
  42. modified_url = f"{base_url}{modified_ip}{port}{ip_end}"
  43. modified_urls.append(modified_url)
  44. return modified_urls
  45. def is_url_accessible(url):
  46. try:
  47. response = requests.get(url, timeout=0.5)
  48. if response.status_code == 200:
  49. return url
  50. except requests.exceptions.RequestException:
  51. pass
  52. return None
  53. results = []
  54. for url in urls:
  55. # 创建一个Chrome WebDriver实例
  56. chrome_options = Options()
  57. chrome_options.add_argument('--headless')
  58. chrome_options.add_argument('--no-sandbox')
  59. chrome_options.add_argument('--disable-dev-shm-usage')
  60. driver = webdriver.Chrome(options=chrome_options)
  61. # 使用WebDriver访问网页
  62. driver.get(url) # 将网址替换为你要访问的网页地址
  63. time.sleep(10)
  64. # 获取网页内容
  65. page_content = driver.page_source
  66. # 关闭WebDriver
  67. driver.quit()
  68. # 查找所有符合指定格式的网址
  69. pattern = r"http://\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d+" # 设置匹配的格式,如http://8.8.8.8:8888
  70. urls_all = re.findall(pattern, page_content)
  71. # urls = list(set(urls_all)) # 去重得到唯一的URL列表
  72. urls = set(urls_all) # 去重得到唯一的URL列表
  73. x_urls = []
  74. for url in urls: # 对urls进行处理,ip第四位修改为1,并去重
  75. url = url.strip()
  76. ip_start_index = url.find("//") + 2
  77. ip_end_index = url.find(":", ip_start_index)
  78. ip_dot_start = url.find(".") + 1
  79. ip_dot_second = url.find(".", ip_dot_start) + 1
  80. ip_dot_three = url.find(".", ip_dot_second) + 1
  81. base_url = url[:ip_start_index] # http:// or https://
  82. ip_address = url[ip_start_index:ip_dot_three]
  83. port = url[ip_end_index:]
  84. ip_end = "1"
  85. modified_ip = f"{ip_address}{ip_end}"
  86. x_url = f"{base_url}{modified_ip}{port}"
  87. x_urls.append(x_url)
  88. urls = set(x_urls) # 去重得到唯一的URL列表
  89. valid_urls = []
  90. # 多线程获取可用url
  91. with concurrent.futures.ThreadPoolExecutor(max_workers=100) as executor:
  92. futures = []
  93. for url in urls:
  94. url = url.strip()
  95. modified_urls = modify_urls(url)
  96. for modified_url in modified_urls:
  97. futures.append(executor.submit(is_url_accessible, modified_url))
  98. for future in concurrent.futures.as_completed(futures):
  99. result = future.result()
  100. if result:
  101. valid_urls.append(result)
  102. for url in valid_urls:
  103. print(url)
  104. # 遍历网址列表,获取JSON文件并解析
  105. for url in valid_urls:
  106. try:
  107. # 发送GET请求获取JSON文件,设置超时时间为0.5秒
  108. ip_start_index = url.find("//") + 2
  109. ip_dot_start = url.find(".") + 1
  110. ip_index_second = url.find("/", ip_dot_start)
  111. base_url = url[:ip_start_index] # http:// or https://
  112. ip_address = url[ip_start_index:ip_index_second]
  113. url_x = f"{base_url}{ip_address}"
  114. json_url = f"{url}"
  115. response = requests.get(json_url, timeout=0.5)
  116. json_data = response.json()
  117. try:
  118. # 解析JSON文件,获取name和url字段
  119. for item in json_data['data']:
  120. if isinstance(item, dict):
  121. name = item.get('name')
  122. urlx = item.get('url')
  123. if ',' in urlx:
  124. urlx=f"aaaaaaaa"
  125. #if 'http' in urlx or 'udp' in urlx or 'rtp' in urlx:
  126. if 'http' in urlx:
  127. urld = f"{urlx}"
  128. else:
  129. urld = f"{url_x}{urlx}"
  130. if name and urlx:
  131. # 删除特定文字
  132. name = name.replace("cctv", "CCTV")
  133. name = name.replace("中央", "CCTV")
  134. name = name.replace("央视", "CCTV")
  135. name = name.replace("高清", "")
  136. name = name.replace("超高", "")
  137. name = name.replace("HD", "")
  138. name = name.replace("标清", "")
  139. name = name.replace("频道", "")
  140. name = name.replace("-", "")
  141. name = name.replace(" ", "")
  142. name = name.replace("PLUS", "+")
  143. name = name.replace("+", "+")
  144. name = name.replace("(", "")
  145. name = name.replace(")", "")
  146. name = re.sub(r"CCTV(\d+)台", r"CCTV\1", name)
  147. name = name.replace("CCTV1综合", "CCTV1")
  148. name = name.replace("CCTV2财经", "CCTV2")
  149. name = name.replace("CCTV3综艺", "CCTV3")
  150. name = name.replace("CCTV4国际", "CCTV4")
  151. name = name.replace("CCTV4中文国际", "CCTV4")
  152. name = name.replace("CCTV4欧洲", "CCTV4")
  153. name = name.replace("CCTV5体育", "CCTV5")
  154. name = name.replace("CCTV6电影", "CCTV6")
  155. name = name.replace("CCTV7军事", "CCTV7")
  156. name = name.replace("CCTV7军农", "CCTV7")
  157. name = name.replace("CCTV7农业", "CCTV7")
  158. name = name.replace("CCTV7国防军事", "CCTV7")
  159. name = name.replace("CCTV8电视剧", "CCTV8")
  160. name = name.replace("CCTV9记录", "CCTV9")
  161. name = name.replace("CCTV9纪录", "CCTV9")
  162. name = name.replace("CCTV10科教", "CCTV10")
  163. name = name.replace("CCTV11戏曲", "CCTV11")
  164. name = name.replace("CCTV12社会与法", "CCTV12")
  165. name = name.replace("CCTV13新闻", "CCTV13")
  166. name = name.replace("CCTV新闻", "CCTV13")
  167. name = name.replace("CCTV14少儿", "CCTV14")
  168. name = name.replace("CCTV15音乐", "CCTV15")
  169. name = name.replace("CCTV16奥林匹克", "CCTV16")
  170. name = name.replace("CCTV17农业农村", "CCTV17")
  171. name = name.replace("CCTV17农业", "CCTV17")
  172. name = name.replace("CCTV5+体育赛视", "CCTV5+")
  173. name = name.replace("CCTV5+体育赛事", "CCTV5+")
  174. name = name.replace("CCTV5+体育", "CCTV5+")
  175. results.append(f"{name},{urld}")
  176. except:
  177. continue
  178. except:
  179. continue
  180. channels = []
  181. for result in results:
  182. line = result.strip()
  183. if result:
  184. channel_name, channel_url = result.split(',')
  185. channels.append((channel_name, channel_url))
  186. # 线程安全的队列,用于存储下载任务
  187. task_queue = Queue()
  188. # 线程安全的列表,用于存储结果
  189. results = []
  190. error_channels = []
  191. # 定义工作线程函数
  192. def worker():
  193. while True:
  194. # 从队列中获取一个任务
  195. channel_name, channel_url = task_queue.get()
  196. try:
  197. channel_url_t = channel_url.rstrip(channel_url.split('/')[-1]) # m3u8链接前缀
  198. lines = requests.get(channel_url, timeout = 1).text.strip().split('\n') # 获取m3u8文件内容
  199. ts_lists = [line.split('/')[-1] for line in lines if line.startswith('#') == False] # 获取m3u8文件下视频流后缀
  200. ts_lists_0 = ts_lists[0].rstrip(ts_lists[0].split('.ts')[-1]) # m3u8链接前缀
  201. ts_url = channel_url_t + ts_lists[0] # 拼接单个视频片段下载链接
  202. # 多获取的视频数据进行5秒钟限制
  203. with eventlet.Timeout(5, False):
  204. start_time = time.time()
  205. content = requests.get(ts_url, timeout = 1).content
  206. end_time = time.time()
  207. response_time = (end_time - start_time) * 1
  208. if content:
  209. with open(ts_lists_0, 'ab') as f:
  210. f.write(content) # 写入文件
  211. file_size = len(content)
  212. # print(f"文件大小:{file_size} 字节")
  213. download_speed = file_size / response_time / 1024
  214. # print(f"下载速度:{download_speed:.3f} kB/s")
  215. normalized_speed = min(max(download_speed / 1024, 0.001), 100) # 将速率从kB/s转换为MB/s并限制在1~100之间
  216. #print(f"标准化后的速率:{normalized_speed:.3f} MB/s")
  217. # 删除下载的文件
  218. os.remove(ts_lists_0)
  219. result = channel_name, channel_url, f"{normalized_speed:.3f} MB/s"
  220. results.append(result)
  221. numberx = (len(results) + len(error_channels)) / len(channels) * 100
  222. print(f"可用频道:{len(results)} 个 , 不可用频道:{len(error_channels)} 个 , 总频道:{len(channels)} 个 ,总进度:{numberx:.2f} %。")
  223. except:
  224. error_channel = channel_name, channel_url
  225. error_channels.append(error_channel)
  226. numberx = (len(results) + len(error_channels)) / len(channels) * 100
  227. print(f"可用频道:{len(results)} 个 , 不可用频道:{len(error_channels)} 个 , 总频道:{len(channels)} 个 ,总进度:{numberx:.2f} %。")
  228. # 标记任务完成
  229. task_queue.task_done()
  230. # 创建多个工作线程
  231. num_threads = 10
  232. for _ in range(num_threads):
  233. t = threading.Thread(target=worker, daemon=True) # 将工作线程设置为守护线程
  234. t.start()
  235. # 添加下载任务到队列
  236. for channel in channels:
  237. task_queue.put(channel)
  238. # 等待所有任务完成
  239. task_queue.join()
  240. def channel_key(channel_name):
  241. match = re.search(r'\d+', channel_name)
  242. if match:
  243. return int(match.group())
  244. else:
  245. return float('inf') # 返回一个无穷大的数字作为关键字
  246. # 对频道进行排序
  247. results.sort(key=lambda x: (x[0], -float(x[2].split()[0])))
  248. results.sort(key=lambda x: channel_key(x[0]))
  249. result_counter = 8 # 每个频道需要的个数
  250. with open("itvlist.txt", 'w', encoding='utf-8') as file:
  251. channel_counters = {}
  252. file.write('央视频道,#genre#\n')
  253. for result in results:
  254. channel_name, channel_url, speed = result
  255. if 'CCTV' in channel_name:
  256. if channel_name in channel_counters:
  257. if channel_counters[channel_name] >= result_counter:
  258. continue
  259. else:
  260. file.write(f"{channel_name},{channel_url}\n")
  261. channel_counters[channel_name] += 1
  262. else:
  263. file.write(f"{channel_name},{channel_url}\n")
  264. channel_counters[channel_name] = 1
  265. channel_counters = {}
  266. file.write('卫视频道,#genre#\n')
  267. for result in results:
  268. channel_name, channel_url, speed = result
  269. if '卫视' in channel_name:
  270. if channel_name in channel_counters:
  271. if channel_counters[channel_name] >= result_counter:
  272. continue
  273. else:
  274. file.write(f"{channel_name},{channel_url}\n")
  275. channel_counters[channel_name] += 1
  276. else:
  277. file.write(f"{channel_name},{channel_url}\n")
  278. channel_counters[channel_name] = 1
  279. channel_counters = {}
  280. file.write('其他频道,#genre#\n')
  281. for result in results:
  282. channel_name, channel_url, speed = result
  283. if 'CCTV' not in channel_name and '卫视' not in channel_name and '测试' not in channel_name:
  284. if channel_name in channel_counters:
  285. if channel_counters[channel_name] >= result_counter:
  286. continue
  287. else:
  288. file.write(f"{channel_name},{channel_url}\n")
  289. channel_counters[channel_name] += 1
  290. else:
  291. file.write(f"{channel_name},{channel_url}\n")
  292. channel_counters[channel_name] = 1
  293. with open("itvlist.m3u", 'w', encoding='utf-8') as file:
  294. channel_counters = {}
  295. file.write('#EXTM3U\n')
  296. for result in results:
  297. channel_name, channel_url, speed = result
  298. if 'CCTV' in channel_name:
  299. if channel_name in channel_counters:
  300. if channel_counters[channel_name] >= result_counter:
  301. continue
  302. else:
  303. file.write(f"#EXTINF:-1 group-title=\"央视频道\",{channel_name}\n")
  304. file.write(f"{channel_url}\n")
  305. channel_counters[channel_name] += 1
  306. else:
  307. file.write(f"#EXTINF:-1 group-title=\"央视频道\",{channel_name}\n")
  308. file.write(f"{channel_url}\n")
  309. channel_counters[channel_name] = 1
  310. channel_counters = {}
  311. #file.write('卫视频道,#genre#\n')
  312. for result in results:
  313. channel_name, channel_url, speed = result
  314. if '卫视' in channel_name:
  315. if channel_name in channel_counters:
  316. if channel_counters[channel_name] >= result_counter:
  317. continue
  318. else:
  319. file.write(f"#EXTINF:-1 group-title=\"卫视频道\",{channel_name}\n")
  320. file.write(f"{channel_url}\n")
  321. channel_counters[channel_name] += 1
  322. else:
  323. file.write(f"#EXTINF:-1 group-title=\"卫视频道\",{channel_name}\n")
  324. file.write(f"{channel_url}\n")
  325. channel_counters[channel_name] = 1
  326. channel_counters = {}
  327. #file.write('其他频道,#genre#\n')
  328. for result in results:
  329. channel_name, channel_url, speed = result
  330. if 'CCTV' not in channel_name and '卫视' not in channel_name and '测试' not in channel_name:
  331. if channel_name in channel_counters:
  332. if channel_counters[channel_name] >= result_counter:
  333. continue
  334. else:
  335. file.write(f"#EXTINF:-1 group-title=\"其他频道\",{channel_name}\n")
  336. file.write(f"{channel_url}\n")
  337. channel_counters[channel_name] += 1
  338. else:
  339. file.write(f"#EXTINF:-1 group-title=\"其他频道\",{channel_name}\n")
  340. file.write(f"{channel_url}\n")
  341. channel_counters[channel_name] = 1