From 756cb1e7d8dba363001cd09c68f695627484791b Mon Sep 17 00:00:00 2001 From: jack Date: Wed, 12 Nov 2025 16:36:38 +0800 Subject: [PATCH] first commit --- .gitignore | 65 ++++++++ clash/clash_check_now_node.py | 80 ++++++++++ clash/clash_set_global.py | 39 +++++ message/message_dlt.py | 180 ++++++++++++++++++++++ message/no_message_dlt.py | 171 +++++++++++++++++++++ requirements.txt | 247 +++++++++++++++++++++++++++++++ siliconflow-api/main.py | 33 +++++ utils/utils_create_rss_record.py | 98 ++++++++++++ utils/utils_get_current_ip.py | 25 ++++ utils/utils_get_public_ip.py | 15 ++ utils/utils_ql_create_tasks.py | 236 +++++++++++++++++++++++++++++ utils/utils_send_gotify.py | 58 ++++++++ web3/faucet.py | 109 ++++++++++++++ 13 files changed, 1356 insertions(+) create mode 100644 .gitignore create mode 100644 clash/clash_check_now_node.py create mode 100644 clash/clash_set_global.py create mode 100644 message/message_dlt.py create mode 100644 message/no_message_dlt.py create mode 100644 requirements.txt create mode 100644 siliconflow-api/main.py create mode 100644 utils/utils_create_rss_record.py create mode 100644 utils/utils_get_current_ip.py create mode 100644 utils/utils_get_public_ip.py create mode 100644 utils/utils_ql_create_tasks.py create mode 100644 utils/utils_send_gotify.py create mode 100644 web3/faucet.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..cf7c11e --- /dev/null +++ b/.gitignore @@ -0,0 +1,65 @@ +.DS_Store +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +env/ +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +*.egg-info/ +.installed.cfg +*.egg +.idea/* +xml_files/ + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*,cover + +# Translations +*.mo +*.pot + +# Django stuff: +*.log + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +other/split_clash_config/split_config +ai_news/save_data +daily/*.txt diff --git a/clash/clash_check_now_node.py b/clash/clash_check_now_node.py new file mode 100644 index 0000000..7b17ece --- /dev/null +++ b/clash/clash_check_now_node.py @@ -0,0 +1,80 @@ +# -*- coding: utf-8 -*- +# 检查所有节点是否有重复 +import asyncio +import httpx +from typing import Optional, Dict, Any, List, Tuple + +async def check_now_node(url_and_port: str) -> Optional[str]: + """检测当前节点并设置全局代理""" + + async with httpx.AsyncClient(timeout=10.0) as client: + try: + # 设置全局模式 + set_url = f"http://{url_and_port}/api/configs" + set_data = {"mode": "Global"} + set_response = await client.patch(set_url, json=set_data) + set_response.raise_for_status() + + # 获取代理信息 + get_url = f"http://{url_and_port}/api/proxies" + get_response = await client.get(get_url) + get_response.raise_for_status() + + json_data = get_response.json() + proxies: Dict[str, Any] = json_data.get("proxies", {}) + proxy_global: Dict[str, Any] = proxies.get("GLOBAL", {}) + now_proxy: Optional[str] = proxy_global.get("now") + + return now_proxy + + except httpx.HTTPError as exc: + print(f"请求失败 {url_and_port}: {exc}") + return None + +async def batch_check_nodes(ip: str, ports: List[str]) -> Dict[str, Optional[str]]: + """批量检测节点""" + tasks = [check_now_node(f"{ip}:{port}") for port in ports] + results = await asyncio.gather(*tasks) + + return { + f"{ip}:{port}": result + for port, result in zip(ports, results) + } + +def find_duplicate_nodes(results: Dict[str, Optional[str]]) -> List[Tuple[str, str]]: + """查找重复的节点""" + node_to_urls = {} + for url, node in results.items(): + if node: # 只处理成功检测的节点 + if node not in node_to_urls: + node_to_urls[node] = [] + node_to_urls[node].append(url) + + # 找出有重复的节点 + duplicates = [] + for node, urls in node_to_urls.items(): + if len(urls) > 1: + for i in range(len(urls)): + for j in range(i + 1, len(urls)): + duplicates.append((urls[i], urls[j])) + + return duplicates + +if __name__ == "__main__": + ip = '192.168.31.201' + ports = [f'{58000 + i}' for i in range(1, 11)] + + results = asyncio.run(batch_check_nodes(ip, ports)) + + # 输出所有节点信息 + for url, node in results.items(): + print(f"{url}: {node or '检测失败'}") + + # 检查并输出重复节点 + duplicates = find_duplicate_nodes(results) + if duplicates: + print("\n发现重复节点:") + for url1, url2 in duplicates: + print(f"{url1} 和 {url2} 重复") + else: + print("\n没有发现重复节点") \ No newline at end of file diff --git a/clash/clash_set_global.py b/clash/clash_set_global.py new file mode 100644 index 0000000..72df3c2 --- /dev/null +++ b/clash/clash_set_global.py @@ -0,0 +1,39 @@ +# -*- coding: utf-8 -*- +# 所有节点切换为全局 +import asyncio +import httpx + +async def set_global(url_and_port): + url = f"http://{url_and_port}" + key = "/api/configs" + full_url = url + key + + data = {"mode": "Global"} + headers = {"Content-Type": "application/json"} + + async with httpx.AsyncClient(timeout=10.0) as client: + try: + response = await client.patch(full_url, json=data, headers=headers) + response.raise_for_status() # 自动抛出4xx/5xx异常 + print(f"成功设置 {url_and_port}") + return True + except httpx.HTTPError as exc: + print(f"请求失败 {url_and_port}: {exc}") + return False + +async def main(): + ip = '192.168.31.201' + port_list = [f'{58000 + i}' for i in range(1, 11)] # 生成端口列表 + + # 创建任务列表 + tasks = [set_global(f"{ip}:{port}") for port in port_list] + + # 并发执行所有任务 + results = await asyncio.gather(*tasks) + + # 统计结果 + success_count = sum(results) + print(f"\n完成设置: {success_count}/{len(port_list)} 个代理成功") + +if __name__ == "__main__": + asyncio.run(main()) \ No newline at end of file diff --git a/message/message_dlt.py b/message/message_dlt.py new file mode 100644 index 0000000..2574621 --- /dev/null +++ b/message/message_dlt.py @@ -0,0 +1,180 @@ +# -*- coding: utf-8 -*- +""" +获取超级大乐透结果, 并匹配自己购买的号码, 配合定时执行使用 +""" + +import sys +import os +import asyncio +import httpx + +sys.path.append(os.path.join(os.path.abspath(__file__).split('manual')[0] + 'manual')) + +from utils.utils_send_gotify import GotifyNotifier + + +class CheckDlt: + def __init__(self): + self.url = 'https://webapi.sporttery.cn/gateway/lottery/getHistoryPageListV1.qry?gameNo=85&provinceId=0&pageSize=1&isVerify=1&pageNo=1' + self.headers = { + "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", + "Accept-Encoding": "gzip, deflate, br, zstd", + "Accept-Language": "zh-CN,zh;q=0.9", + "Cache-Control": "max-age=0", + "Priority": "u=0, i", + "Sec-CH-UA": '"Not;A=Brand";v="99", "Google Chrome";v="139", "Chromium";v="139"', + "Sec-CH-UA-Mobile": "?0", + "Sec-CH-UA-Platform": '"macOS"', + "Sec-Fetch-Dest": "document", + "Sec-Fetch-Mode": "navigate", + "Sec-Fetch-Site": "none", + "Sec-Fetch-User": "?1", + "Upgrade-Insecure-Requests": "1", + "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36" + } + self.my_dlt = [ + ['10', '11', '16', '17', '18', '11', '12'], + ['02', '03', '11', '12', '23', '05', '06'], + ['07', '09', '15', '17', '22', '09', '11'], + ['05', '06', '07', '34', '35', '02', '09'], + ['09', '10', '11', '21', '22', '04', '05'] + ] + + async def req(self): + async with httpx.AsyncClient() as client: + try: + resp = await client.get(self.url, timeout=5) + if resp.status_code != 200: + print('state code: {}'.format(resp.status_code)) + log_detail = '访问失败, 状态码:{},url:{}'.format(resp.status_code, self.url) + print(log_detail) + return None + except Exception as e: + print(f'请求失败 {e}') + return None + + return resp.json() + + def data_handle(self, data): + if not data: + print('获取数据为空') + return None + + value = data.get('value') + data_list = value.get('list') + + if not data_list: + print('获取数据为空') + return None + + result_data = [] + + for d in data_list: + numbers = d.get('lotteryUnsortDrawresult') + try: + if len(numbers.split(' ')) < 7: + continue + except Exception as e: + print('numbers: {}, err: {}'.format(numbers, e)) + continue + + red_list = numbers.split(' ')[:5] + blue_list = numbers.split(' ')[5:] + + red_list.sort() + blue_list.sort() + + try: + # 切开红球,蓝球数组 + red1 = red_list[0] + red2 = red_list[1] + red3 = red_list[2] + red4 = red_list[3] + red5 = red_list[4] + blue1 = blue_list[0] + blue2 = blue_list[1] + except Exception as e: + print('红球或蓝球数据丢失') + continue + + result_data.append({ + 'serial': d.get('lotteryDrawNum'), + 'red1': red1 or '', + 'red2': red2 or '', + 'red3': red3 or '', + 'red4': red4 or '', + 'red5': red5 or '', + 'blue1': blue1 or '', + 'blue2': blue2 or '', + 'drawPdfUrl': d.get('drawPdfUrl'), + 'date': d.get('lotteryDrawTime'), + 'pool': d.get('poolBalanceAfterdraw') + }) + + if result_data: + return result_data + else: + print('返回的数据为空, 获取数据失败') + return None + + def data_compare(self, all_data): + if not all_data: + return '', '' + + data = all_data[0] + + red_list = [data['red1'], data['red2'], data['red3'], data['red4'], data['red5']] + blue_list = [data['blue1'], data['blue2']] + + # 期号 + subject = '{}'.format(data['serial']) + + # 组成每期数据的text + serial_text = 'serial: {}\t\tlottery draw date: {}\nbonus pool: {} RMB\n{}\nlottery draw num: {} + {}\n\n'.format( + data['serial'], data['date'], data['pool'], '*' * 90, + red_list, blue_list) + + for my_num in self.my_dlt: + my_red_list = my_num[:5] + my_blue_list = my_num[5:] + + # 使用列表推导式找出两个列表中都存在的元素 + red_common_elements = [element for element in red_list if element in my_red_list] + blue_common_elements = [element for element in blue_list if element in my_blue_list] + + # 计算相等元素的数量 + red_equal_count = len(red_common_elements) + blue_equal_count = len(blue_common_elements) + + serial_text += 'my nums: {} + {}\nred hit: {}\nblue hit: {}\n\n'.format(my_red_list, my_blue_list, + red_equal_count, + blue_equal_count) + + serial_text += '{}\n\n\n\n'.format('*' * 90) + + return serial_text, subject + + def send_message(self, text, subject): + if not text: + return + + title = f'dlt {subject}' + + # 推送到 message + GotifyNotifier(title, text, 'dlt').send_message() + + # 发送到邮件 + # SendEmail(title, title, text).send() + + async def main(self): + data = await self.req() + result_data = self.data_handle(data) + if not result_data: + return + + text, subject = self.data_compare(result_data) + self.send_message(text, subject) + + +if __name__ == '__main__': + asyncio.run(CheckDlt().main()) diff --git a/message/no_message_dlt.py b/message/no_message_dlt.py new file mode 100644 index 0000000..7f543a6 --- /dev/null +++ b/message/no_message_dlt.py @@ -0,0 +1,171 @@ +# -*- coding: utf-8 -*- +""" +获取超级大乐透结果, 并匹配自己购买的号码, 配合定时执行使用 +""" + +import sys +import os +import asyncio +import httpx + +sys.path.append(os.path.join(os.path.abspath(__file__).split('manual')[0] + 'manual')) + +from utils.utils_send_gotify import GotifyNotifier + + +class CheckDlt: + def __init__(self): + self.headers = { + "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", + "Accept-Encoding": "gzip, deflate, br, zstd", + "Accept-Language": "zh-CN,zh;q=0.9", + "Cache-Control": "max-age=0", + "Priority": "u=0, i", + "Sec-CH-UA": '"Not;A=Brand";v="99", "Google Chrome";v="139", "Chromium";v="139"', + "Sec-CH-UA-Mobile": "?0", + "Sec-CH-UA-Platform": '"macOS"', + "Sec-Fetch-Dest": "document", + "Sec-Fetch-Mode": "navigate", + "Sec-Fetch-Site": "none", + "Sec-Fetch-User": "?1", + "Upgrade-Insecure-Requests": "1", + "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36" + } + self.my_dlt = [ + ['10', '11', '16', '17', '18', '11', '12'], + ['02', '03', '11', '12', '23', '05', '06'], + ['07', '09', '15', '17', '22', '09', '11'], + ['05', '06', '07', '34', '35', '02', '09'], + ['09', '10', '11', '21', '22', '04', '05'] + ] + + async def req(self, url): + async with httpx.AsyncClient() as client: + try: + resp = await client.get(url, timeout=5) + if resp.status_code != 200: + print('state code: {}'.format(resp.status_code)) + log_detail = '访问失败, 状态码:{},url:{}'.format(resp.status_code, url) + print(log_detail) + return None + except Exception as e: + print(f'请求失败 {e}') + return None + + return resp.json() + + def data_handle(self, data): + if not data: + print('获取数据为空') + return None + + value = data.get('value') + if not value: + print('获取数据为空') + return None + data_list = value.get('list') + + if not data_list: + print('获取数据为空') + return None + + result_data = [] + + for d in data_list: + numbers = d.get('lotteryUnsortDrawresult') + try: + if len(numbers.split(' ')) < 7: + continue + except Exception as e: + print('numbers: {}, err: {}'.format(numbers, e)) + continue + + red_list = numbers.split(' ')[:5] + blue_list = numbers.split(' ')[5:] + + red_list.sort() + blue_list.sort() + + try: + red1 = red_list[0] + red2 = red_list[1] + red3 = red_list[2] + red4 = red_list[3] + red5 = red_list[4] + blue1 = blue_list[0] + blue2 = blue_list[1] + except Exception as e: + print('红球或蓝球数据丢失') + continue + + result_data.append({ + 'serial': d.get('lotteryDrawNum'), + 'red1': red1 or '', + 'red2': red2 or '', + 'red3': red3 or '', + 'red4': red4 or '', + 'red5': red5 or '', + 'blue1': blue1 or '', + 'blue2': blue2 or '', + 'drawPdfUrl': d.get('drawPdfUrl'), + 'date': d.get('lotteryDrawTime'), + 'pool': d.get('poolBalanceAfterdraw') + }) + + if result_data: + return result_data + else: + print('返回的数据为空, 获取数据失败') + return None + + def data_compare(self, all_data): + if not all_data: + return '', '' + + data = all_data[0] + + red_list = [data['red1'], data['red2'], data['red3'], data['red4'], data['red5']] + blue_list = [data['blue1'], data['blue2']] + + # 期号 + subject = '{}'.format(data['serial']) + + # 组成每期数据的text + serial_text = 'serial: {}\t\tlottery draw date: {}\nbonus pool: {} RMB\n{}\nlottery draw num: {} + {}\n\n'.format( + data['serial'], data['date'], data['pool'], '*' * 90, + red_list, blue_list) + + for my_num in self.my_dlt: + my_red_list = my_num[:5] + my_blue_list = my_num[5:] + + # 使用列表推导式找出两个列表中都存在的元素 + red_common_elements = [element for element in red_list if element in my_red_list] + blue_common_elements = [element for element in blue_list if element in my_blue_list] + + # 计算相等元素的数量 + red_equal_count = len(red_common_elements) + blue_equal_count = len(blue_common_elements) + + serial_text += 'my nums: {} + {}\nred hit: {}\nblue hit: {}\n\n'.format(my_red_list, my_blue_list, + red_equal_count, + blue_equal_count) + + serial_text += '{}\n\n\n\n'.format('*' * 90) + + return serial_text, subject + + async def main(self): + for no in range(3, 0, -1): + url = f'https://webapi.sporttery.cn/gateway/lottery/getHistoryPageListV1.qry?gameNo=85&provinceId=0&pageSize=1&isVerify=1&pageNo={no}' + data_list = await self.req(url) + result_data = self.data_handle(data_list) + if not result_data: + continue + + text, subject = self.data_compare(result_data) + print(text) + + +if __name__ == '__main__': + asyncio.run(CheckDlt().main()) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..a09f6be --- /dev/null +++ b/requirements.txt @@ -0,0 +1,247 @@ +aiodns==3.2.0 +aiofiles==24.1.0 +aiogram==3.18.0 +aiohappyeyeballs==2.4.6 +aiohttp==3.9.5 +aiohttp-socks==0.8.4 +aioquic==1.2.0 +aiosignal==1.3.2 +annotated-types==0.7.0 +anyio==4.1.0 +appdirs==1.4.4 +APScheduler==3.10.4 +asgiref==3.8.1 +async-timeout==4.0.3 +atomicwrites==1.4.1 +attrs==25.1.0 +base58==2.1.1 +beautifulsoup4==4.12.2 +bech32==1.2.0 +better-proxy==1.1.5 +bidict==0.23.1 +bitarray==3.1.0 +blessed==1.20.0 +blinker==1.9.0 +Brotli==1.1.0 +bs4==0.0.1 +cairocffi==1.7.1 +CairoSVG==2.7.1 +captchatools==1.5.0 +ccxt==4.4.75 +certifi==2025.1.31 +cffi==1.16.0 +charset-normalizer==3.4.1 +ckzg==2.0.1 +click==8.1.7 +colorama==0.4.6 +coloredlogs==15.0.1 +cryptography==36.0.1 +cssselect2==0.8.0 +curl_cffi==0.10.0 +customtkinter==5.2.2 +Cython==3.1.2 +cytoolz==1.0.1 +darkdetect==0.8.0 +dateparser==1.1.3 +ddddocr==1.5.6 +defusedxml==0.7.1 +distro==1.9.0 +dnspython==2.4.2 +docutils==0.21.2 +dukpy==0.4.0 +easy-clash-tool==0.0.3 +easy-spider-tool==1.0.16 +editor==1.6.6 +et_xmlfile==2.0.0 +eth-account==0.13.5 +eth-hash==0.7.1 +eth-keyfile==0.8.1 +eth-keys==0.6.1 +eth-rlp==2.2.0 +eth-typing==5.2.0 +eth-utils==5.2.0 +eth_abi==5.2.0 +exceptiongroup==1.2.0 +fake-useragent==1.5.1 +Faker==23.2.1 +fastapi==0.115.12 +Flask==3.1.0 +flatbuffers==25.2.10 +frozenlist==1.5.0 +greenlet==3.1.1 +h11==0.14.0 +h2==4.1.0 +hexbytes==1.3.0 +hpack==4.0.0 +httpcore==1.0.2 +httptools==0.6.4 +httpx==0.27.2 +humanfriendly==10.0 +hyperframe==6.0.1 +idna==3.10 +ifaddr==0.2.0 +importlib-metadata==7.0.0 +inquirer==3.4.0 +itsdangerous==2.2.0 +jieba==0.42.1 +Jinja2==3.1.6 +jiter==0.5.0 +jsonpath==0.82 +jsonschema==4.23.0 +jsonschema-specifications==2023.12.1 +kaitaistruct==0.10 +ldap3==2.9.1 +loguru==0.7.3 +lxml==5.3.0 +magic-filter==1.0.12 +markdown-it-py==3.0.0 +markdown2==2.5.3 +MarkupSafe==3.0.2 +matrix-client==0.4.0 +matrix-nio==0.25.0 +mdurl==0.1.2 +mitmproxy==11.0.2 +mitmproxy-macos==0.10.7 +mitmproxy_rs==0.10.7 +mnemonic==0.21 +MouseInfo==0.1.3 +mpmath==1.3.0 +msgpack==1.1.0 +multidict==6.1.0 +mutf8==1.0.6 +names==0.3.0 +nicegui==2.14.1 +numpy==1.26.4 +ollama==0.4.6 +onnxruntime==1.16.3 +openai==1.42.0 +opencv-python-headless==4.11.0.86 +openpyxl==3.1.5 +orjson==3.10.16 +outcome==1.3.0.post0 +packaging==23.2 +paho-mqtt==2.1.0 +pandas==2.2.3 +parsimonious==0.10.0 +passlib==1.7.4 +patchright==1.50.0 +pillow==11.1.0 +ping3==4.0.4 +playwright==1.46.0 +primp==0.14.0 +prompt_toolkit==3.0.50 +propcache==0.3.0 +protobuf==5.29.3 +pscript==0.7.7 +psycopg2==2.9.9 +publicsuffix2==2.20191221 +py-solc-x==2.0.3 +pyasn1==0.5.1 +pyasn1_modules==0.4.1 +PyAutoGUI==0.9.54 +pycares==4.6.0 +pycparser==2.21 +pycryptodome==3.21.0 +pydantic==2.10.6 +pydantic_core==2.27.2 +pydivert==2.1.0 +pyee==12.1.1 +PyExecJS==1.5.1 +PyGetWindow==0.0.9 +Pygments==2.19.1 +pygpt4all==1.1.0 +pygptj==2.0.3 +pyhttpx==2.10.9 +pyllamacpp==2.4.2 +pylsqpack==0.3.19 +pymongo==4.6.1 +PyMsgBox==1.0.9 +PyNaCl==1.5.0 +pynocaptcha==2.0.52 +pyobjc-core==11.0 +pyobjc-framework-Cocoa==11.0 +pyobjc-framework-Quartz==11.0 +pyOpenSSL==21.0.0 +pyparsing==3.1.1 +pyperclip==1.9.0 +pyppeteer==2.0.0 +PyRect==0.2.0 +PyRSS2Gen==1.1 +PyScreeze==1.0.1 +pyshark==0.6 +PySocks==1.7.1 +python-dateutil==2.9.0.post0 +python-dotenv==1.1.0 +python-engineio==4.12.0 +python-multipart==0.0.20 +python-socketio==5.13.0 +python-socks==2.5.1 +pytweening==1.2.0 +pytz==2025.1 +pyunormalize==16.0.0 +PyYAML==6.0.2 +questionary==2.1.0 +RandomWords==0.4.0 +readchar==4.2.1 +redis==5.0.1 +referencing==0.35.1 +regex==2024.11.6 +requests==2.32.3 +retrying==1.3.4 +rich==13.9.4 +rlp==4.1.0 +rpds-py==0.20.0 +rsa==4.8 +ruamel.yaml==0.18.6 +ruamel.yaml.clib==0.2.12 +rubicon-objc==0.5.0 +runs==1.2.2 +scapy==2.5.0 +schedule==1.2.1 +screeninfo==0.8.1 +selenium==4.16.0 +selenium-wire==5.1.0 +service-identity==24.2.0 +simple-websocket==1.1.0 +six==1.16.0 +sniffio==1.3.0 +sortedcontainers==2.4.0 +soupsieve==2.5 +SQLAlchemy==2.0.36 +starlette==0.46.2 +sui-brownie==1.2.4 +sympy==1.13.3 +tabulate==0.9.0 +tenacity==8.2.3 +termcolor==2.4.0 +tinycss2==1.4.0 +toml==0.10.2 +toolz==1.0.0 +tornado==6.4.2 +tqdm==4.66.1 +trio==0.23.1 +trio-websocket==0.11.1 +types-requests==2.32.0.20250301 +typing_extensions==4.12.2 +tzdata==2025.2 +tzlocal==5.2 +unpaddedbase64==2.1.0 +urllib3==2.3.0 +urwid==2.6.16 +uvicorn==0.29.0 +uvloop==0.21.0 +vbuild==0.8.2 +watchfiles==1.0.5 +wcwidth==0.2.13 +web3==7.8.0 +webencodings==0.5.1 +websockets==13.1 +Werkzeug==3.1.3 +win32_setctime==1.2.0 +wsproto==1.2.0 +xmltodict==0.13.0 +xmod==1.8.1 +yarl==1.18.3 +you-get==0.4.1730 +zipp==3.17.0 +zstandard==0.22.0 diff --git a/siliconflow-api/main.py b/siliconflow-api/main.py new file mode 100644 index 0000000..2a362b5 --- /dev/null +++ b/siliconflow-api/main.py @@ -0,0 +1,33 @@ +import httpx + +content = "简单讲解一下mvc模型上下文" +key = "sk-mepewzmlykchrjosberepdvvbnrjbhoamewefnckokitveqf" +model = "THUDM/GLM-4.1V-9B-Thinking" +url = "https://api.siliconflow.cn/v1/chat/completions" + +headers = { + "Authorization": f"Bearer {key}", + "Content-Type": "application/json" +} +payload = { + "model": model, + "messages": [{"role": "user", "content": content}] +} + +with httpx.Client(timeout=999) as client: + response = client.post(url, headers=headers, json=payload) + if response.json()["choices"][0]["message"]["content"]: + content = response.json()["choices"][0]["message"]["content"] + content = content.split("\n") + for i in content: + print(i) + else: + print(response.json()) + + + + + + + + \ No newline at end of file diff --git a/utils/utils_create_rss_record.py b/utils/utils_create_rss_record.py new file mode 100644 index 0000000..ac15ffb --- /dev/null +++ b/utils/utils_create_rss_record.py @@ -0,0 +1,98 @@ +import time + +import psycopg2 +from psycopg2 import Error + + +class CreateRssRecord(object): + def __init__(self): + self.hostname = 'erhe.top' + self.port = 20788 + self.database = 'freshrss' + self.user = 'freshrss' + self.password = 'freshrss' + self.conn = None + + def connect(self): + """连接到 PostgreSQL 数据库""" + try: + self.conn = psycopg2.connect( + dbname=self.database, + user=self.user, + password=self.password, + host=self.hostname, + port=self.port + ) + except Error as e: + print(f"Error connecting to the database: {e}") + else: + print("Connected to the database successfully.") + + if not self.conn: + raise Exception("Database connection failed") + + def check_and_insert(self, data): + """检查 URL 是否存在,如果不存在则插入整个数据字典""" + try: + with self.conn.cursor() as cursor: + # 检查 URL 是否存在 + select_sql = "SELECT COUNT(*) FROM freshrsstoor_feed WHERE url = %s" + cursor.execute(select_sql, (data['url'],)) + result = cursor.fetchone() + if result[0] == 0: + # URL 不存在,插入新记录 + columns = ', '.join(data.keys()) + values = ', '.join(['%s'] * len(data)) + insert_sql = """INSERT INTO freshrsstoor_feed + (url, kind, category, "name", website, description, "lastUpdate", priority, "pathEntries", "httpAuth", "error", "ttl", attributes, "cache_nbEntries", "cache_nbUnreads") + VALUES ('{}', {}, {}, '{}', '{}', '{}', {}, {}, '{}', '{}', {}, {}, '{}', {}, {});""".format( + data['url'], + data['kind'], + data['category'], + data['name'], + data['website'], + data['description'], + data['lastUpdate'], + data['priority'], + data['pathEntries'], + data['httpAuth'], + data['error'], + data['ttl'], + data['attributes'], + data['cache_nbEntries'], + data['cache_nbUnreads'] + ) + cursor.execute(insert_sql, tuple(data.values())) + self.conn.commit() + print("Data inserted successfully.") + else: + print("URL already exists.") + except Error as e: + print(f"Error: {e}") + finally: + if self.conn is not None: + self.conn.close() + + +# 使用示例 +if __name__ == "__main__": + cr = CreateRssRecord() + cr.connect() + insert_data = { + 'url': 'https://rsshub.app/jike/topic/556688fae4b00c57d9dd46ee', + 'category': 7, + 'name': '今日份的摄影 - 即刻圈子', + 'website': 'http://finance.sina.com.cn/china/', + 'description': '爱摄影的即友都在这里~分享原创摄影作品,感受照片背后的共鸣吧! - Powered by RSSHub', + 'kind': 0, + 'lastUpdate': int(time.time()), + 'priority': 10, + 'pathEntries': '', + 'httpAuth': '', + 'error': 0, + 'ttl': 0, + 'attributes': '{"curl_params":null,"ssl_verify":null,"timeout":null}', + 'cache_nbEntries': 0, + 'cache_nbUnreads': 0 + } + cr.check_and_insert(insert_data) diff --git a/utils/utils_get_current_ip.py b/utils/utils_get_current_ip.py new file mode 100644 index 0000000..f5291f6 --- /dev/null +++ b/utils/utils_get_current_ip.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +import aiohttp +import asyncio + + +async def fetch(url): + async with aiohttp.ClientSession() as session: + async with session.get(url) as response: + return await response.text() + + +async def main(): + url = 'http://api.ip.cc' + content = await fetch(url) + print(content) + + +asyncio.run(main()) + +''' +Proxy server: 175.99.17.215 +port: 6011 +username: lumi-jiege0210 +password: aaaAAA111 +''' \ No newline at end of file diff --git a/utils/utils_get_public_ip.py b/utils/utils_get_public_ip.py new file mode 100644 index 0000000..39c62f0 --- /dev/null +++ b/utils/utils_get_public_ip.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- +import httpx + + +def get_public_ip(): + try: + # 使用 httpx 发起请求 + response = httpx.get("https://httpbin.org/ip", timeout=10) + response.raise_for_status() # 检查请求是否成功 + ip_data = response.json() + return ip_data["origin"] + except httpx.RequestError as e: + print(f"An error occurred while obtaining the public IP address.:{e}") + exit(1) + diff --git a/utils/utils_ql_create_tasks.py b/utils/utils_ql_create_tasks.py new file mode 100644 index 0000000..bc89cb1 --- /dev/null +++ b/utils/utils_ql_create_tasks.py @@ -0,0 +1,236 @@ +# -*- coding: utf-8 -*- +import os + +import requests + +# 青龙面板的地址 +url = "https://auto.erhe.top" + + +# 登录青龙面板 +def login(): + response = requests.post(f"{url}/api/user/login", json={"username": "toor", "password": "!QAZ2wsx+0913"}) + print(response) + if response.status_code != 200: + print(response.status_code) + print(response.text) + exit(0) + return response.json()['data']['token'] + + +# 获取任务列表 +def get_tasks(token): + response = requests.get(f"{url}/api/crons", headers={"Authorization": f"Bearer {token}"}) + return response.json()['data']['data'] + + +# 创建任务 +def create_task(task_template, token): + payload = { + "name": task_template["name"], + "command": task_template["command"], + "schedule": task_template["schedule"], + "labels": task_template["labels"] + } + headers = { + "Authorization": f"Bearer {token}", + "Content-Type": "application/json" + } + response = requests.post(f"{url}/api/crons", headers=headers, json=payload) + return response.json() + + +# 创建视图分类 +def create_view_type(token): + view_type_list = ['base', 'spider_common'] + for view_type in view_type_list: + payload = { + "name": view_type, + "filters": { + 'property': 'labels', + 'operation': 'Reg', + 'value': view_type + }, + 'filterRelation': 'and' + } + headers = { + "Authorization": f"Bearer {token}", + "Content-Type": "application/json" + } + response = requests.post(f"{url}/api/crons", headers=headers, json=payload) + + +# 主逻辑 +def main(): + while True: + try: + token = login() + print(f"已连接到 {url}") + tasks = get_tasks(token) + tasks_names = [task['name'] for task in tasks] + if tasks: + print("Current tasks name: \n{}, \ntotal: {}".format('\n'.join(tasks_names), str(len(tasks_names)))) + else: + print("Tasks list is empty") + + project_path = '/ql/data/scripts/auto/' + base_path = os.path.join(project_path, 'base') + spider_path = os.path.join(project_path, 'spider') + message_path = os.path.join(project_path, 'message') + manual_path = os.path.join(project_path, 'manual') + daily_path = os.path.join(project_path, 'daily') + tasks_template = [{ + 'base_tasks': [ + { + "name": "每天开始自动创建日志", + "command": "python3 {}/base_daily_logs_generate.py".format(base_path), + "schedule": "0 0 * * *", + "labels": ["base"] + }, + { + "name": "每天结束自动发送日志", + "command": "python3 {}/base_daily_logs_send.py".format(base_path), + "schedule": "58 23 * * *", + "labels": ["base"] + }, + { + "name": "每天自动删除旧数据", + "command": "python3 {}/base_timing_remove_data.py".format(base_path), + "schedule": "1 0 * * *", + "labels": ["base"] + }, + { + "name": "每天新闻汇总,发送到邮箱", + "command": "python3 {}/base_news_data_collation.py".format(base_path), + "schedule": "0 10 6,12,18 * * *", + "labels": ["base"] + }, + { + "name": "定时刷新 freshrss 订阅源", + "command": "python3 {}/update_feed.py".format(base_path), + "schedule": "0 6,22 * * *", + "labels": ["base"] + } + ], + 'spider': [ + { + "name": "自动执行反斗限免爬虫", + "command": "python3 {}/news_get_apprcn.py".format(spider_path), + "schedule": "0 0 3,6,9,12,15,18,21 * * *", + "labels": ["spider"] + }, + { + "name": "自动执行chiphell爬虫", + "command": "python3 {}/news_get_chiphell.py".format(spider_path), + "schedule": "0 0 3,6,9,12,15,18,21 * * *", + "labels": ["spider"] + }, + { + "name": "自动执行hello_github爬虫", + "command": "python3 {}/news_get_hello_github.py".format(spider_path), + "schedule": "0 0 3,6,9,12,15,18,21 * * *", + "labels": ["spider"] + }, + { + "name": "自动执行Anyknew爬虫", + "command": "python3 {}/news_get_news.py".format(spider_path), + "schedule": "0 0 3,6,9,12,15,18,21 * * *", + "labels": ["spider"] + }, + { + "name": "自动执行币界网文章爬虫", + "command": "python3 {}/spider_web3_coin_world.py".format(spider_path), + "schedule": "0 0 3,6,9,12,15,18,21 * * *", + "labels": ["spider"] + }, + { + "name": "获取 web3 新闻", + "command": "python3 {}/spider_web3_news.py".format(spider_path), + "schedule": "0 0 3,6,9,12,15,18,21 * * *", + "labels": ["spider"] + }, + { + "name": "自动执行dlt爬虫", + "command": "python3 {}/spider_get_and_check_dlt.py".format(spider_path), + "schedule": "30 22 * * 1,3,6", + "labels": ["spider"] + } + ], + 'message_tasks': [ + { + "name": "获取coin实时数据", + "command": "python3 {}/message_coin_detail.py".format(message_path), + "schedule": "0 * * * *", + "labels": ["message"] + }, + { + "name": "对比大乐透最新一期数据,匹配已购买号码,发送消息", + "command": "python3 {}/message_dlt.py".format(message_path), + "schedule": "30 22 * * 1,3,6", + "labels": ["message"] + }, + { + "name": "获取未来 7 天的天气预报", + "command": "python3 {}/message_get_one_week_weather.py".format(message_path), + "schedule": "0 0 6,22 * * *", + "labels": ["message"] + }, + { + "name": "从 freshrss-psql 数据库中读取数据并发送", + "command": "python3 {}/message_rss_data_handel.py".format(message_path), + "schedule": "30 6,9,12,18,22 * * *", + "labels": ["message"] + }, + { + "name": "空投任务消息", + "command": "python3 {}/message_airdrop_tasks.py".format(message_path), + "schedule": "0 8,20 * * *", + "labels": ["message"] + }, + { + "name": "链捕手快讯消息推送", + "command": "python3 {}/message_chaincatcher.py".format(message_path), + "schedule": "0 */2 * * *", + "labels": ["message"] + } + ], + 'manual': [ + { + "name": "手动读取rss订阅新闻", + "command": "python3 {}/read_news.py".format(manual_path), + "schedule": "0 0 1 1 *", + "labels": ["manual"] + } + ], + 'daily': [ + { + "name": "3dos自动签到", + "command": "python3 {}/daily_3dos.py".format(daily_path), + "schedule": "*/5 * * * *", + "labels": ["daily"] + } + ], + }] + + for task_template in tasks_template: + for task_type, task_list in task_template.items(): + for task in task_list: + task_name = task["name"] + if task_name in tasks_names: + print("Task {} already exists.".format(task_name)) + else: + result = create_task(task, token) + print("Task creation result:", result) + + # 创建所有任务之后, 创建视图分类 + # create_view_type(token) + break # 正常执行完成后退出循环 + + except Exception as e: + print("An error occurred: ", e) + print("Retrying...") + + +if __name__ == "__main__": + main() + print('done!') diff --git a/utils/utils_send_gotify.py b/utils/utils_send_gotify.py new file mode 100644 index 0000000..927c7d9 --- /dev/null +++ b/utils/utils_send_gotify.py @@ -0,0 +1,58 @@ +# -*- coding: utf-8 -*- + +import httpx + + +class GotifyNotifier: + def __init__(self, title, message, token_name=''): + self.gotify_url = 'https://gotify.erhe.top' + self.app_token = self.match_token_name(token_name) + self.title = title + self.message = message + + def match_token_name(self, name): + token_name_dict = { + 'base': 'A8EVb0Cmxnb2vfk', + 'coin': 'AgfOJESqDKftBTQ', + 'dlt': 'A3bqt9Dlbs.fPUb', + 'AirdropTasksNews': 'Aoe0VKt-kkZnm8d', + 'weather': 'A9KF--mx_12PjSu', + 'news': 'AT2QGp_vyCX4akW', + 'CheckAndRemind': 'Aw7XKE2Ppk7Dgwk', + 'test': 'A0Xg6ZE5946iBYg', + } + + token = token_name_dict.get(name) + if token: + return token + else: + return token_name_dict['base'] + + def send_message(self): + # 构建POST请求的headers + headers = { + 'Content-Type': 'application/json' + } + + # 构建POST请求的body + body = { + 'title': self.title, + 'message': self.message + } + + # 发送POST请求 + with httpx.Client() as client: + response = client.post( + url=f"{self.gotify_url}/message?token={self.app_token}", + headers=headers, + json=body + ) + + # 或者可以使用 curl + # curl -k "https://gotify.erhe.top/message?token=A0Xg6ZE5946iBYg" -F "title=测试发送信息" -F "message=假装有信息,测试发送" -F "priority=5" + + # 检查响应状态码 + if response.status_code == 200: + print('Gotify Message sent successfully!') + else: + print('Failed to send message:', response.text) diff --git a/web3/faucet.py b/web3/faucet.py new file mode 100644 index 0000000..ed6911f --- /dev/null +++ b/web3/faucet.py @@ -0,0 +1,109 @@ +# -*- coding: utf-8 -*- +import re + +import httpx +import asyncio +import json +import random +import logging +from typing import List +from fake_useragent import UserAgent # 导入 fake_useragent 模块 + +# 配置日志 +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(levelname)s - %(message)s' +) +logger = logging.getLogger(__name__) + +# 初始化 fake_useragent +ua = UserAgent() + + +async def send_post_request(wallet: str, timeout: float = 10.0) -> None: + """ + 向目标网站发送 POST 请求以领取水。 + + Args: + wallet: 钱包地址 + timeout: 请求超时时间(秒) + """ + url = "https://faucet.nerzo.xyz/monad" + + headers = { + "accept": "text/x-component", + "accept-encoding": "gzip, deflate, br, zstd", + "accept-language": "zh-CN,zh;q=0.9", + "content-type": "text/plain;charset=UTF-8", + "next-action": "405d6e23437f844564e65cdd65851724c449d7f778", + "next-router-state-tree": '["",{"children":["(faucet)",{"children":["monad",{"children":["__PAGE__",{},"/monad","refresh"]}]}]},null,null,true]', + "origin": "https://faucet.nerzo.xyz", + "priority": "u=1, i", + "referer": "https://faucet.nerzo.xyz/monad", + "sec-ch-ua": '"Chromium";v="130", "Google Chrome";v="130", "Not?A_Brand";v="99"', + "sec-ch-ua-mobile": "?0", + "sec-ch-ua-platform": '"Windows"', + "sec-fetch-dest": "empty", + "sec-fetch-mode": "cors", + "sec-fetch-site": "same-origin", + "user-agent": ua.random, + "x-deployment-id": "dpl_DWgqqeB8V4ASD1aCKUqWZwcPwnVd" + } + payload = json.dumps([wallet]) + + async with httpx.AsyncClient(timeout=timeout, proxy={'http://': 'http://127.0.0.1:7890'}) as client: + retry = 3 + while retry > 0: # 修复了 retry 的逻辑错误 + try: + response = await client.post(url, headers=headers, content=payload) + # logger.info(f"Wallet: {wallet} | Status Code: {response.status_code} | Response: {response.text}") + logger.info(f"Wallet: {wallet} | Status Code: {response.status_code}") + if 'message' in response.text: + message = re.findall(r'"message":"(.*?)"', response.text)[0] + logger.info(f"Wallet: {wallet} | Message: {message}") + return response + except httpx.RequestError as e: + logger.error(f"Wallet: {wallet} | Request failed: {e}") + retry -= 1 + + if retry <= 0: + return None + + +async def main(wallet_list: List[str], min_delay: float = 5.0, max_delay: float = 8.0) -> None: + """ + 批量处理钱包地址,发送 POST 请求,并添加随机延时。 + + Args: + wallet_list: 钱包地址列表 + min_delay: 最小延时(秒) + max_delay: 最大延时(秒) + """ + for i, wallet in enumerate(wallet_list, 1): + logger.info(f"Processing wallet {i}/{len(wallet_list)}: {wallet}") + await send_post_request(wallet) + # 在最后一个钱包之前添加随机延时 + if i < len(wallet_list): + delay = random.uniform(min_delay, max_delay) + logger.info(f"Waiting for {delay:.2f} seconds before next request") + await asyncio.sleep(delay) + + +if __name__ == "__main__": + wallet_list = [ + '0xe50B77Cd771243b8Ae1d6ce33b4E13ECC5Fa28a6', + '0x9ea2ECAD4090E32916e03b77d7C75CbF6C8E0A55', + '0xE8A4b0C04300154DC9B1D0e565Ba70F996614690', + '0x1b623c5d70c93b437d93c305bf2cfa389095f636', + '0x06D25c3e0E1F753ac0486a3f8aaD7259149656cB', + '0x15cFEE34Ca4541CAc9a1c4B6F6aB47A65877E240', + '0x7aBF0dA8Ac07B6dE7206e467988455E1AD0b60B5', + '0xF736f45d4663a8D8DfF7EFA55b1Cf6Fe38D026c8', + '0x83173eECf3a6d9ABB79682568e16c2eAd361620e', + '0xa401b85B4849Fc7610Bd180cc937859C78528F47', + '0x10A43E7Fe77E2D84adBeC26cF0bFc6f403841266', + '0x70D5EE1DfddD3726f0D71F4CD5a8Ef43aC651a75' + ] + random.shuffle(wallet_list) + asyncio.run(main(wallet_list)) + print("done")