├── 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 |
--------------------------------------------------------------------------------