├── .gitignore ├── README.md └── TuBi.py /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | Desktop.ini 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # T00ls 签到脚本 2 | t00ls 每日签到脚本 整合了钉钉和邮件通知,本脚本运行环境是 Python3.6 + 3 | 4 | **依赖安装**: 5 | 6 | ```bash 7 | pip install requests 8 | pip install beautifulsoup4 9 | ``` 10 | 11 | # 脚本详情 12 | 13 | [Python 实现 T00ls 自动签到脚本(邮件+钉钉通知)](https://www.sqlsec.com/2020/07/t00ls.html) 14 | 15 | # 定时任务 16 | 17 | 看了不少网友也使用了 **腾讯云函数**和 **Github 带的 Actions** 来实现自动触发脚本,的确也很不错,感兴趣的朋友也可研究看看。因为国光我有一台 Web 服务器,所以国光我就采用了在 Linux 下使用原生的 crontab 命令实现定时任务了: 18 | 19 | ```bash 20 | # 查看定时任务 21 | crontab -l 22 | 23 | # 编辑定时任务 24 | crontab -e 25 | ``` 26 | 27 | 编辑定时任务,一行一个任务,国光我本次填写的内容如下: 28 | 29 | ```bash 30 | 30 9 * * * /usr/bin/python3 /root/code/t00ls/TuBi.py>&1 31 | ``` 32 | 33 | 表示每天 9:30 自动运行下面的命令: 34 | 35 | ````bash 36 | /usr/bin/python3 /root/code/t00ls/TuBi.py 37 | ```` 38 | 39 | 这样看起来是不是很简单呢,如果语法没有问题的话,会得到如下提示: 40 | 41 | ``` 42 | crontab: installing new crontab 43 | ``` 44 | 45 | 这表示新建定时任务成功,后面就可以躺着赚去每天的 2 个 TuBi 了。 46 | 47 | -------------------------------------------------------------------------------- /TuBi.py: -------------------------------------------------------------------------------- 1 | import time 2 | import json 3 | import random 4 | import smtplib 5 | import requests 6 | from bs4 import BeautifulSoup 7 | from email.mime.text import MIMEText 8 | from email.utils import formataddr 9 | 10 | # t00ls 账号配置 11 | username = '国光' # 帐号 12 | password = '***' # 密码MD5 32位(小写) 13 | question_num = 7 # 安全提问 参考下面 14 | question_answer = '***' # 安全提问答案 15 | 16 | # 0 = 没有安全提问 17 | # 1 = 母亲的名字 18 | # 2 = 爷爷的名字 19 | # 3 = 父亲出生的城市 20 | # 4 = 您其中一位老师的名字 21 | # 5 = 您个人计算机的型号 22 | # 6 = 您最喜欢的餐馆名称 23 | # 7 = 驾驶执照的最后四位数字 24 | 25 | # 选择提醒方式 26 | notice = 2 # 0 = 钉钉 1 = 邮件 2 = 我全都要 27 | 28 | # 如果选择钉钉通知的话 请配置下方信息 29 | webhook = 'https://oapi.dingtalk.com/robot/send?access_token=***' # 钉钉机器人的 webhook 30 | 31 | # 如果选择邮件通知的话 请配置下方信息 32 | sender = 'admin@sqlsec.com' # 发件人邮箱账号 33 | sender_pass = '***********' # 发件人邮箱密码 34 | receiver = 'admin@sqlsec.com' # 收件人邮箱账号 35 | 36 | req_headers = { 37 | 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_5) AppleWebKit/537.36 (KHTML, like Gecko) Safari/537.36' 38 | } 39 | 40 | def t00ls_login(u_name, u_pass, q_num, q_ans): 41 | """ 42 | t00ls 登录函数 43 | :param u_name: 用户名 44 | :param u_pass: 密码的 md5 值 32 位小写 45 | :param q_num: 安全提问类型 46 | :param q_ans: 安全提问答案 47 | :return: 签到要用的 hash 和 登录后的 Cookies 48 | """ 49 | 50 | login_data = { 51 | 'action': 'login', 52 | 'username': u_name, 53 | 'password': u_pass, 54 | 'questionid': q_num, 55 | 'answer': q_ans 56 | } 57 | response_login = requests.post('https://www.t00ls.cc/login.json', data=login_data, headers=req_headers) 58 | response_login_json = json.loads(response_login.text) 59 | 60 | if response_login_json['status'] != 'success': 61 | return None 62 | else: 63 | print('用户:', username, '登入成功!') 64 | formhash = response_login_json['formhash'] 65 | t00ls_cookies = response_login.cookies 66 | return formhash, t00ls_cookies 67 | 68 | 69 | def t00ls_sign(t00ls_hash, t00ls_cookies): 70 | """ 71 | t00ls 签到函数 72 | :param t00ls_hash: 签到要用的 hash 73 | :param t00ls_cookies: 登录后的 Cookies 74 | :return: 签到后的 JSON 数据 75 | """ 76 | sign_data = { 77 | 'formhash': t00ls_hash, 78 | 'signsubmit': "true" 79 | } 80 | response_sign = requests.post('https://www.t00ls.cc/ajax-sign.json', data=sign_data, cookies=t00ls_cookies, 81 | headers=req_headers) 82 | return json.loads(response_sign.text) 83 | 84 | 85 | def t00ls_domain(t00ls_hash, t00ls_cookies): 86 | """ 87 | t00ls 域名查询函数 88 | :param t00ls_hash: 签到要用的 hash 89 | :param t00ls_cookies: 登录后的 Cookies 90 | :return: 查询相关的日志信息 91 | """ 92 | content = '' 93 | # 使用站长之家查询今天注册的域名 94 | start_time = time.time() 95 | 96 | china_url = 'https://whois.chinaz.com/suffix' 97 | search_data = 'ix=.com&suffix=.cn&c_suffix=&time=1&startDay=&endDay=' 98 | req_headers['Content-Type'] = 'application/x-www-form-urlencoded' 99 | response_domains = requests.post(url=china_url, headers=req_headers, data=search_data, timeout=10) 100 | 101 | # Bs4 解析器 简单规则过滤一下放入到 domains 的列表中 102 | soup = BeautifulSoup(response_domains.text, 'html.parser') 103 | domains = [] 104 | for i in soup.select('.listOther a'): 105 | if '.' in i.string and '*' not in i.string: 106 | domains.append(i.string) 107 | domain = random.sample(domains, 1)[0] # 随机抽取一个 幸运儿 108 | 109 | end_time = time.time() 110 | print(f'站长之家随机找域名耗时: {end_time - start_time:.4f}秒') 111 | content += f'\n站长之家随机找域名耗时: {end_time - start_time:.4f}秒\n\n' 112 | 113 | start_time = time.time() 114 | 115 | query_url = 'https://www.t00ls.cc/domain.html' 116 | query_data = f'domain={domain}&formhash={t00ls_hash}&querydomainsubmit=%E6%9F%A5%E8%AF%A2' 117 | query_status = False 118 | query_count = 1 # 查询重试次数 119 | 120 | # 如果 t00ls 查询没有成功的话 就一直查询 121 | while not query_status and query_count < 4: 122 | domain = random.sample(domains, 1)[0] # 随机抽取一个 幸运儿 123 | query_data = f'domain={domain}&formhash={t00ls_hash}&querydomainsubmit=%E6%9F%A5%E8%AF%A2' 124 | 125 | try: 126 | response_query = requests.post(url=query_url, headers=req_headers, data=query_data, cookies=t00ls_cookies) 127 | except Exception: 128 | pass 129 | 130 | if domain in response_query.text: 131 | response_tb = requests.get('https://www.t00ls.cc/members-tubilog.json', cookies=t00ls_cookies) 132 | if domain in response_tb.text: 133 | print('查询域名成功 TuBi + 1 \n') 134 | content += '查询域名成功 TuBi + 1\n' 135 | query_status = True 136 | else: 137 | print('糟糕 域名查询成功 但是 TuBi 没有增加 可能域名重复了') 138 | content += '糟糕 域名查询成功 但是 TuBi 没有增加 可能域名重复了\n' 139 | query_count += 1 140 | print(f'随机延时 5-10 秒,继续第 {query_count} 次查询') 141 | content += f'随机延时 5-10 秒,继续第 {query_count} 次查询\n\n' 142 | time.sleep(random.randint(5, 10)) 143 | else: 144 | print(f'查询失败?失败的域名是: {domain}') 145 | content += f'查询失败?失败的域名是: {domain}\n' 146 | query_count += 1 147 | print(f'随机延时 5-10 秒,继续第 {query_count} 次查询') 148 | content += f'随机延时 5-10 秒,继续第 {query_count} 次查询\n\n' 149 | time.sleep(random.randint(5, 10)) 150 | if query_count == 4: 151 | print('重试查询次数已达上限 终止查询') 152 | content += '重试查询次数已达上限 终止查询\n\n' 153 | 154 | end_time = time.time() 155 | print(f't00ls 域名查询耗时: {end_time - start_time:.4f}秒') 156 | content += f't00ls 域名查询耗时: {end_time - start_time:.4f}秒\n' 157 | return content 158 | 159 | 160 | def dingtalk(content): 161 | """ 162 | 钉钉通知函数 163 | :param content: 要通知的内容 164 | :return: none 165 | """ 166 | webhook_url = webhook 167 | dd_headers = { 168 | "Content-Type": "application/json", 169 | "Charset": "UTF-8" 170 | } 171 | dd_message = { 172 | "msgtype": "text", 173 | "text": { 174 | "content": f'T00ls 签到通知\n{content}' 175 | } 176 | } 177 | 178 | r = requests.post(url=webhook_url, headers=dd_headers, data=json.dumps(dd_message)) 179 | 180 | 181 | def mail(content): 182 | """ 183 | 邮件通知函数 184 | :param content: 要通知的内容 185 | :return: none 186 | """ 187 | msg = MIMEText(content, 'plain', 'utf-8') 188 | msg['From'] = formataddr(["T00ls 签到提醒", sender]) 189 | msg['To'] = formataddr(["", receiver]) 190 | msg['Subject'] = "T00ls 每日签到提醒" 191 | 192 | server = smtplib.SMTP_SSL("smtp.qq.com", 465) 193 | server.login(sender, sender_pass) 194 | server.sendmail(sender, [receiver, ], msg.as_string()) 195 | server.quit() 196 | 197 | 198 | def main(): 199 | content = '' 200 | response_login = t00ls_login(username, password, question_num, question_answer) 201 | if response_login: 202 | response_sign = t00ls_sign(response_login[0], response_login[1]) 203 | if response_sign['status'] == 'success': 204 | print('签到成功 TuBi + 1') 205 | content += '\n签到成功 TuBi + 1\n' 206 | 207 | verbose_log = t00ls_domain(response_login[0], response_login[1]) 208 | content += verbose_log 209 | 210 | if notice == 0: 211 | try: 212 | dingtalk(content) 213 | except Exception: 214 | print('请检查钉钉配置是否正确') 215 | elif notice == 1: 216 | try: 217 | mail(content) 218 | except Exception: 219 | print('请检查邮件配置是否正确') 220 | else: 221 | try: 222 | dingtalk(content) 223 | except Exception: 224 | print('请检查钉钉配置是否正确') 225 | try: 226 | mail(content) 227 | except Exception: 228 | print('请检查邮件配置是否正确') 229 | elif response_sign['message'] == 'alreadysign': 230 | print('已经签到过啦') 231 | content += '\n已经签到过啦\n' 232 | 233 | verbose_log = t00ls_domain(response_login[0], response_login[1]) 234 | content += verbose_log 235 | 236 | if notice == 0: 237 | try: 238 | dingtalk(content) 239 | except Exception: 240 | print('请检查钉钉配置是否正确') 241 | elif notice == 1: 242 | try: 243 | mail(content) 244 | except Exception: 245 | print('请检查邮件配置是否正确') 246 | else: 247 | try: 248 | dingtalk(content) 249 | except Exception: 250 | print('请检查钉钉配置是否正确') 251 | try: 252 | mail(content) 253 | except Exception: 254 | print('请检查邮件配置是否正确') 255 | else: 256 | print('出现玄学问题了 签到失败') 257 | else: 258 | print('登入失败 请检查输入资料是否正确') 259 | 260 | 261 | if __name__ == '__main__': 262 | main() 263 | --------------------------------------------------------------------------------