最有效Freenom域名自动续期

Freenom 域名自动续期。Freenom domain name renews automatically.

实战

腾讯云函数python

SunYufei/freenom: Freenom 域名自动续期 Python 版本 (github.com)

GitHub Action用做CI工具,修改下用在腾讯云函数上。

创建腾讯云函数

直接访问腾讯云函数控制台创建云函数: https://console.cloud.tencent.com/scf/list-create

1
2
3
4
自定义创建
事件函数
代码部署
Python3.6

依赖安装

  1. 在“函数管理”页面中,选择函数代码 > 代码编辑,查看并编辑函数。
  2. 在 IDE 顶部的菜单栏终端中选择新终端,打开终端窗口。
  3. 在终端中执行如下命令,安装依赖库 :
1
2
3
4
5
cd src # 依赖库需要安装在与函数入口文件同一级的目录下,即需要进入`src`目录后再执行依赖安装操作。
pip3 install requests -t .
python -m pip install --upgrade requests pyaes -t .
pip install python-telegram-bot --upgrade -t .
pip3 install python-telegram-bot --upgrade -t .

configuration

env

1
2
3
4
FREENOM_USERNAME=username1,username2... 
FREENOM_PASSWORD=password1,password2...
BOT_API
CHAT_ID

cron

1
0 15 9 * * * *

index.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# -*- coding: utf8 -*-

import os
from freenom import FreeNom
import time
import re
import requests
from urllib import parse


class FreenomDomainNameRenewsAutomaticallys():

tg_text = ''
# 打印输出当前ip地址
def print_my_ip(self):
api_url = 'https://api.ipify.org/'
try:
res = requests.get(url=api_url)
res.raise_for_status()
res.encoding = 'utf-8'
self.tg_text = self.tg_text + '当前使用 ip 地址:' + res.text.replace('.', ',') + '\n'
print('当前使用 ip 地址:' + res.text)
except Exception as e:
self.tg_text = self.tg_text + '获取当前 ip 地址失败:' + str(e) + '\n'
print('获取当前 ip 地址失败:' + str(e))

# TG推送
def post(self, bot_api, chat_id, text):
print('开始推送')
headers = {
'user-agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.76 Mobile Safari/537.36'}
text = parse.quote(text)
# 修改为自己的bot api token
post_url = 'https://api.telegram.org/bot{}/sendMessage' \
'?parse_mode=MarkdownV2&chat_id={}&text={}'.format(bot_api, chat_id, text)
try:
requests.get(post_url, headers=headers)
print('推送成功')
except Exception:
print("推送失败")
time.sleep(3)
# 避免推送死循环
try:
requests.get(post_url, headers=headers)
except Exception:
pass

def domainNameRenewsAutomaticallys(self, usernames, passwords, bot_api, chat_id):
# 分割用户名和密码为列表
user_list = usernames.split(',')
passwd_list = passwords.split(',')
if not usernames or not passwords:
self.tg_text = self.tg_text + '未检测到用户名或密码,请检查环境变量是否设置正确!\n'
print('未检测到用户名或密码,请检查环境变量是否设置正确!')
elif len(user_list) != len(passwd_list):
self.tg_text = self.tg_text + '用户名与密码个数不匹配,请检查环境变量设置是否错漏!\n'
print('用户名与密码个数不匹配,请检查环境变量设置是否错漏!')
else:
self.print_my_ip()
self.tg_text = self.tg_text + '共检测到{}个帐户,开始域名自动续期\n'.format(len(user_list))
print('共检测到', len(user_list), '个帐户,开始域名自动续期')
print('*' * 30)
# 依次登录帐户获取积分,出现错误时不中断程序继续尝试下一个帐户
for i in range(len(user_list)):
try:
t=''
instance = FreeNom(user_list[i], passwd_list[i])
t=instance.renew()
self.tg_text=self.tg_text+t
# print(self.tg_text)
i=i+1
except Exception as e:
self.tg_text = self.tg_text + '程序执行异常:'
print('程序执行异常:' + str(e))
print('*' * 30)
continue
self.tg_text = self.tg_text.replace('.', ',') + '\n程序执行完毕,域名自动续期过程结束'
print('程序执行完毕,域名自动续期过程结束')
print(self.tg_text)
self.post(bot_api, chat_id, self.tg_text)

def main_handler(event, context):
usernames = os.environ['username']
passwords = os.environ['password']
bot_api = os.environ['BOT_API']
chat_id = os.environ['CHAT_ID']
f = FreenomDomainNameRenewsAutomaticallys()
f.domainNameRenewsAutomaticallys(usernames, passwords, bot_api, chat_id)
return("Hello World")

if __name__ == '__main__':
main_handler("","")

freedom.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
import re

import requests

# 登录地址
LOGIN_URL = 'https://my.freenom.com/dologin.php'

# 域名状态地址
DOMAIN_STATUS_URL = 'https://my.freenom.com/domains.php?a=renewals'

# 域名续期地址
RENEW_DOMAIN_URL = 'https://my.freenom.com/domains.php?submitrenewals=true'

# token 正则
token_ptn = re.compile('name="token" value="(.*?)"', re.I)

# 域名信息正则
domain_info_ptn = re.compile(
r'<tr><td>(.*?)</td><td>[^<]+</td><td>[^<]+<span class="[^<]+>(\d+?).Days</span>[^&]+&domain=(\d+?)">.*?</tr>',
re.I)

# 登录状态正则
login_status_ptn = re.compile('<a href="logout.php">Logout</a>', re.I)


class FreeNom:
def __init__(self, username: str, password: str):
self._u = username
self._p = password

self._s = requests.Session()
self._s.headers.update({
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/79.0.3945.130 Safari/537.36'
})

def _login(self) -> bool:
self._s.headers.update({
'content-type': 'application/x-www-form-urlencoded',
'referer': 'https://my.freenom.com/clientarea.php'
})
r = self._s.post(LOGIN_URL, data={'username': self._u, 'password': self._p})
return r.status_code == 200

def renew(self):
# login
ok = self._login()
if not ok:
print('login failed')
return

# check domain status
self._s.headers.update({'referer': 'https://my.freenom.com/clientarea.php'})
r = self._s.get(DOMAIN_STATUS_URL)

# login status check
if not re.search(login_status_ptn, r.text):
print('get login status failed')
return

# page token
match = re.search(token_ptn, r.text)
if not match:
print('get page token failed')
return
token = match.group(1)

# domains
domains = re.findall(domain_info_ptn, r.text)

# renew domains
text=''
for domain, days, renewal_id in domains:
days = int(days)
if days < 14:
self._s.headers.update({
'referer': f'https://my.freenom.com/domains.php?a=renewdomain&domain={renewal_id}',
'content-type': 'application/x-www-form-urlencoded'
})
r = self._s.post(RENEW_DOMAIN_URL, data={
'token': token,
'renewalid': renewal_id,
f'renewalperiod[{renewal_id}]': '12M',
'paymentmethod': 'credit'
})
print(domain, '续期成功' if r.text.find('Order Confirmation') != -1 else '续期失败')
# domain=domain.replace(",", ".");
# print(f'{domain} 还有 {days} 天续期')
text+=f'{domain} 还有 {days} 天续期\n'
# print(text)
return text

结果

image-20211027105113815

通过腾讯云函数(SCF)部署php版

使用腾讯云函数

luolongfei/freenom: Freenom 域名自动续期。Freenom domain name renews automatically. (github.com)

1、下载 SCF 版本的压缩包

此版本为特别版,支持通过腾讯云函数部署,并且将与主分支同步维护更新,推荐没有自己 VPS 服务器的用户使用,最新版本号为v0.3.1_scf。下载地址: https://github.com/luolongfei/freenom/releases/download/v0.3.1_scf/freenom-0.3.1_scf.zip

下载后你将得到一个 zip 文件,将 zip 文件放到你能找到的任意目录,后面我们将以 zip 文件的形式上传到腾讯云函数。

2、创建腾讯云函数

直接访问腾讯云函数控制台创建云函数: https://console.cloud.tencent.com/scf/list-create , 按照下图所示的说明进行创建。如果无法看清图片,可访问: https://github.com/luolongfei/freenom/blob/main/resources/screenshot/scf.png 或者 https://z3.ax1x.com/2021/10/14/5lMweU.png 查看原图。

scf01

按照上图所示部署完成后,可以点击云函数的名称进入云函数管理画面,管理画面点击函数代码,然后往下翻可看到部署测试按钮,点击测试,稍等几秒钟,即可看到输出日志, 根据输出日志判断配置以及部署是否正确。

scf02

有关腾讯云函数部署的内容结束。