itv_all.py 22 KB

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