├── README.md └── freenom.py /README.md: -------------------------------------------------------------------------------- 1 | # 项目已停用!!!网站增加了图形验证。freenom-qinglong 域名自动续期-青龙面板 2 | Automatically Renew Freenom Domain for qinglong panle. 3 | # 请手动续期! 4 | 本人没有多号,无法测试。有bug请及时反馈,谢谢! 5 | # How to use食用方法: 6 | 本程序适用于青龙面板https://github.com/whyour/qinglong.git ;也支持独立运行,但没有通知推送。 7 | # 新版青龙: 8 | 订阅管理-新建订阅-名称:自定义,选择单个文件,链接:https://raw.githubusercontent.com/rpgrpg/freenom-qinglong/main/freenom.py ,定时规则:自定义,确定之后,点击运行按钮运行一次即可。 9 | # 旧版青龙: 10 | 无订阅管理,定时任务-新建任务-名称:自定义,命令:ql raw https://raw.githubusercontent.com/rpgrpg/freenom-qinglong/main/freenom.py ,定时规则:自定义,确定之后,点击运行按钮运行一次即可。 11 | # 修改配置文件config.sh,添加环境变量 12 | 点击面板左侧的“配置文件”,然后将文件拉到最后,添加如下两行:export freenom_usr="",""内为你自己的FREENOM的用户名,export freenom_psd="",""内为你自己的FREENOM密码,多号用 & 分隔 13 | # 示例: 14 | # export freenom_usr="123@qq.com&abc@163.com&one@gmail.com" 15 | # export freenom_psd="76543210&abcdefg&a1b2c3d4" 16 | # 密码带“&”的,改密码或添加变量export change_split="",把分隔符放""里 17 | 支持在freenom.py文件中直接添加username和password,适用crontab等其它定时任务。 18 | # freenom是目前全网唯一的免费顶级域名注册网站了,大家轻撸,避免滥用。 19 | -------------------------------------------------------------------------------- /freenom.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # _*_ coding:utf-8 _*_ 3 | 4 | # 觉得好用请点 *star*,作者仓库:https://github.com/rpgrpg/freenom-qinglong.git 5 | 6 | ''' 7 | cron: 33 7 * * 2,5 8 | new Env:('freenom多帐户续期'); 9 | ''' 10 | # 配置环境变量:export freenom_usr="",多号用&分割,示例:123@qq.com&abc@163.com 11 | # 配置环境变量:export freenom_psd="",账号对应密码同样用&分割,示例:miam1&mima2 12 | # 密码含&的,设置export change_split="",示例:export change_split=","代表用逗号分割 13 | # V20231a 14 | 15 | import requests 16 | import re,os,time,random 17 | try: 18 | from notify import send 19 | except: 20 | print("upload notify failed") 21 | 22 | 23 | # 没有设置环境变量可以在此处直接填写freenom用户名,多号用&分割,示例:'123@qq.com&abc@163.com' 24 | username = '' 25 | # 没有设置环境变量可以在此处直接填写freenom密码,账号对应密码同样用&分割,示例:'psd1&psd2' 26 | password = '' 27 | # 密码含&的,设置echa_split = '' ,示例:cha_split = ','代表用逗号分割 28 | cha_split = '' 29 | # 登录url 30 | LOGIN_URL = 'https://my.freenom.com/dologin.php' 31 | # 域名状态url 32 | DOMAIN_STATUS_URL = 'https://my.freenom.com/domains.php?a=renewals' 33 | # 续期url 34 | RENEW_DOMAIN_URL = 'https://my.freenom.com/domains.php?submitrenewals=true' 35 | # 登录匹配 36 | token_ptn = re.compile('name="token" value="(.*?)"', re.I) 37 | domain_info_ptn = re.compile( 38 | r'(.*?)[^<]+[^<]+.*?', 39 | re.I) 40 | login_status_ptn = re.compile('Logout', re.I) 41 | sess = requests.Session() 42 | sess.headers.update({ 43 | 'user-agent': 44 | 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/103.0.5060.134 Safari/537.36' 45 | }) 46 | sess.headers.update({ 47 | 'content-type': 'application/x-www-form-urlencoded', 48 | 'referer': 'https://my.freenom.com/clientarea.php' 49 | }) 50 | 51 | # 获取用户列表 52 | def get_usr(): 53 | # 先检测环境变量 54 | if "freenom_usr" in os.environ: 55 | # 配置环境变量:export FREENOM_USR="",多号用&分割 56 | usr_list = os.environ["freenom_usr"].split("&") 57 | return usr_list 58 | # 从脚本内获取 59 | elif username: 60 | usr_list = username.split('&') 61 | return usr_list 62 | # 都没有 63 | print('Pls config export OR fill in username.') 64 | send('未在环境变量或脚本中找到账号信息,请手动添加') 65 | exit(-1) 66 | 67 | # 获取密码 68 | def get_psd(): 69 | if "freenom_psd" in os.environ: 70 | if "change_split" in os.environ: 71 | psd_list = os.environ["freenom_psd"].split(os.environ["change_split"]) 72 | return psd_list 73 | else: 74 | # 配置环境变量:export FREENOM_PSD="",多号用&分割 75 | psd_list = os.environ["freenom_psd"].split("&") 76 | return psd_list 77 | # 从脚本内获取 78 | elif password: 79 | if cha_split: 80 | psd_list = password.split(cha_split) 81 | return psd_list 82 | else: 83 | psd_list = password.split('&') 84 | return psd_list 85 | # 都没有 86 | print('Pls config export OR fill in password.') 87 | send('未在环境变量或脚本中找到密码信息,请手动添加') 88 | exit(-1) 89 | 90 | # start 91 | def main(usr,psd): 92 | try: # 异常捕捉 93 | r = sess.post(LOGIN_URL, data={'username': usr, 'password': psd}) 94 | if r.status_code != 200: 95 | print('Can not login. Pls check network.') 96 | send('登录失败,', '请检查网络') 97 | return 98 | # 查看域名状态 99 | sess.headers.update({'referer': 'https://my.freenom.com/clientarea.php'}) 100 | r = sess.get(DOMAIN_STATUS_URL) 101 | except: 102 | print('Network failed.') 103 | send('连接中断,', '请检查网络是否正常') 104 | return 105 | # 确认登录状态 106 | if not re.search(login_status_ptn, r.text): 107 | print('login failed, retry') 108 | send('登录失败,', '请检查账号有效性') 109 | return 110 | # 获取token 111 | page_token = re.search(token_ptn, r.text) 112 | if not page_token: 113 | print('page_token missed') 114 | send('连接中断,', '请检查网络是否正常') 115 | return 116 | token = page_token.group(1) 117 | # 获取域名列表 118 | domains = re.findall(domain_info_ptn, r.text) 119 | domains_list = [] 120 | renew_domains_succeed = [] 121 | renew_domains_failed = [] 122 | # 域名续期 123 | for domain, days, renewal_id in domains: 124 | day_s = int(days) 125 | domains_list.append(f'域名:{domain}还有{day_s}天到期~') 126 | if day_s < 14: 127 | # 避免频繁操作 128 | time.sleep(6) 129 | sess.headers.update({ 130 | 'referer': 131 | f'https://my.freenom.com/domains.php?a=renewdomain&domain={renewal_id}', 132 | 'content-type': 'application/x-www-form-urlencoded' 133 | }) 134 | try: 135 | r = sess.post(RENEW_DOMAIN_URL, 136 | data={ 137 | 'token': token, 138 | 'renewalid': renewal_id, 139 | f'renewalperiod[{renewal_id}]': '12M', 140 | 'paymentmethod': 'credit' 141 | }) 142 | except: 143 | print('Network failed.') 144 | send('连接中断,', '请检查网络是否正常') 145 | renew_domains_failed.append(domain) 146 | continue 147 | if r.text.find('Order Confirmation') != -1: 148 | renew_domains_succeed.append(domain) 149 | else: 150 | renew_domains_failed.append(domain) 151 | 152 | # 输出结果并推送通知 153 | print(domains_list, renew_domains_succeed, renew_domains_failed) 154 | if renew_domains_failed: 155 | send(f'注意!!!您有{len(renew_domains_failed)}个域名续期失败,请及时手动操作确认!', f'续期失败的域名:{renew_domains_failed}') 156 | else: 157 | if renew_domains_succeed: 158 | send(f'账号{usr}共有{len(domains_list)}个域名:\n{domains_list}', f'域名: {renew_domains_succeed}续期成功!') 159 | else: 160 | send('恭喜,两周内没有需要续期的域名', f'账号{usr}共有{len(domains_list)}个域名:\n{domains_list}') 161 | return 162 | 163 | if __name__ == '__main__': 164 | usrs = get_usr() 165 | psds = get_psd() 166 | 167 | if len(usrs) != len(psds): 168 | print('Can not metch. Pls check export') 169 | send('账号密码数量不匹配,请检查变量, ' , '密码含&的添加change_split变量或更改密码') 170 | exit(-1) 171 | print(f'--------共{len(usrs)}个账号--------\n') 172 | for i in range(len(usrs)): 173 | print(f'***第{i + 1}个账号: {usrs[i]} ***\n') 174 | # 随机暂停几秒,错峰使用 175 | time.sleep(random.randint(1,30)) 176 | main(usrs[i], psds[i]) 177 | 178 | --------------------------------------------------------------------------------