freenom域名批量续期及信息播报

易雾君
发布于 2023-09-26 / 150 阅读
0
3

freenom域名批量续期及信息播报

前言

freenom域名越来越难申请了,且续期都是未知数,为防止自动续期失败导致域名丢失,特制作一个定期播报脚本,包含续期及到期信息监控,机器人消息支持企业微信和telegram,本文重点强调 telegram 播报的实现。

效果展示

Pasted image 20230924232240.png

Pasted image 20230924232216.png

telegram接收消息条件准备

机器人申请

搜索 BotFather 进入聊天页面,输入指令 /newbot 按照提示输入机器人名称及账号ID即可。

Pasted image 20230924232014.png

获取Token

将上图中马赛克部分保留下来,那就是机器人发送用的 token 。

频道准备

这里采用频道来接收机器人播报消息,专门新建一个家庭基建内部频道。

获取频道 chat id
chat_id 是接收消息的目标对象,必要条件,访问网址 https://api.telegram.org/bot<your_token>/getUpdates ,your_token 替换为上边保留的token即可,找到形如如下截图中类型为 channel 的 id 号码。

Screenshot 2023-09-24 at 23.27.07.png

脚本实现

封装一个类,接收多个 freenom 账号,遍历登录获取续期信息,同时判断到期时间是否为 2 周内,自动执行续期请求。按需进行机器人播报续期消息,未实现钉钉,仅实现了 telegram 和企业微信。请根据实际情况填充脚本最后那里的配置信息。考虑到 freenom 官方新增了验证码机制,脚本引入了休眠时间,可能执行时间较长,请耐心等待。

#!/usr/bin/env python3  
# -*- coding: utf-8 -*-  
# @Project : tools  
# @File : freenom_alert.py  
# @Software: PyCharm  
# @Author : 易雾君  
# @Email : [email protected]  
# @公众号 : 易雾山庄  
# @Site : https://www.evling.tech  
# @Describe : 家庭基建,生活乐享. # @Time : 2023/9/24 18:17  
  
import re  
import time  
import datetime  
import requests  
from telebot import TeleBot  
from requests.packages.urllib3.exceptions import InsecureRequestWarning  
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)  
  
class FreeNom:  
    def __init__(self):  
        self.session = requests.session()  
        self.session.headers.update({'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/79.0.3945.130 Safari/537.36'})  
        self.domain_info = dict()  
        self.timeout = 60  
        self.sleep = 20  
  
    def login(self, username:str, password:str, retry:int=10):  
        result = False  
        self.session.headers.update({  
            'content-type': 'application/x-www-form-urlencoded',  
            'referer': 'https://my.freenom.com/clientarea.php'  
        })  
        print(f'login: {username}')  
        url = 'https://my.freenom.com/dologin.php'  
        data = {'username': username, 'password': password}  
        for i in range(retry):  
            try:  
                res = self.session.post(url, data=data, timeout=self.timeout, verify=False)  
                if res.status_code == 200:  
                    res.content.decode()  
                    result = True  
                    break                
                print(f'retry {i+1}')  
                time.sleep(self.sleep)  
            except:  
                pass  
        return result  
  
    def run(self, accounts:dict):  
        for username,password in accounts.items():  
            self.domain_info[username] = dict()  
            if not self.login(username, password):  
                print('login failed')  
                continue  
            try:  
                url = 'https://my.freenom.com/domains.php?a=renewals'  
                self.session.headers.update({'referer': 'https://my.freenom.com/clientarea.php'})  
                res = self.session.get(url, timeout=self.timeout, verify=False)  
                login_status_ptn = re.compile('<a href="logout.php">Logout</a>', re.I)  
                if not re.search(login_status_ptn, res.text):  
                    print('get login status failed')  
                    continue  
                token_ptn = re.compile('name="token" value="(.*?)"', re.I)  
                match = re.search(token_ptn, res.text)  
                if not match:  
                    print('get page token failed')  
                    return  
                token = match.group(1)  
                domain_info_ptn = re.compile(  
                    r'<tr><td>(.*?)</td><td>[^<]+</td><td>[^<]+<span class="[^<]+>(\d+?).Days</span>[^&]+&domain=(\d+?)">.*?</tr>',  
                    re.I)  
                domains = re.findall(domain_info_ptn, res.text)  
                for domain, days, renewal_id in domains:  
                    days = int(days)  
                    if days <= 14:  
                        self.session.headers.update({  
                            'referer': f'https://my.freenom.com/domains.php?a=renewdomain&domain={renewal_id}',  
                            'content-type': 'application/x-www-form-urlencoded'  
                        })  
                        url = 'https://my.freenom.com/domains.php?submitrenewals=true'  
                        data = {  
                            'token': token,  
                            'renewalid': renewal_id,  
                            f'renewalperiod[{renewal_id}]': '12M',  
                            'paymentmethod': 'credit'  
                        }  
                        res = self.session.post(url, data=data, timeout=self.timeout, verify=False)  
                        print(domain, '续期成功' if res.text.find('Order Confirmation') != -1 else '续期失败')  
                    print(f'{domain} 还有 {days} 天续期')  
                    self.domain_info[username][domain] = f'还有 {days} 天续期'           
            except:  
                pass  
            time.sleep(self.sleep)  
  
    def send_wecom(self, token:str, title:str, msg_info:dict=None, retry:int=3):  
        if not msg_info:  
            msg_info = self.domain_info  
        url = f'https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key={token}'  
        self.session.headers.update({'Content-Type': 'application/json'})  
        t0 = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")  
        msg = ''  
        for account,item in msg_info.items():  
            msg += f'**{account}**\n'  
            for domain,days in item.items():  
                msg += f'- {domain}: {days}\n'  
            msg += '\n'  
        data = {  
            'msgtype': 'markdown',  
            'markdown': {  
                "content": f"#### **{title}**\n"  
                    f"> **检查时间:**\n{t0}\n\n"  
                    f"> **续期信息:**\n\n{msg}"  
            }  
        }  
        for i in range(retry):  
            try:  
                self.session.post(url, json=data, timeout=self.timeout, verify=False)  
                break  
            except:  
                pass  
  
    def send_telegram(self, token:str, chat_id:str, title:str, msg_info:dict=None, tags:list=None, bot_author='evling', foot='[易雾山庄](https://www.evling.tech)'):  
        if not msg_info:  
            msg_info = self.domain_info  
        bot = TeleBot(token)  
        msg = f'*【{title}】*\n'  
        if tags:  
            msg += ' '.join([f'#{x}' for x in tags]) + '\n\n'  
        else:  
            msg += '\n'  
        msg += f'*检查时间*: {datetime.datetime.now().strftime("%Y-%m-%d %X")}\n*续期详情*: \n\n'  
        for account, item in msg_info.items():  
            msg += f'*{account}*\n'  
            for domain, days in item.items():  
                msg += f'{domain}: {days}\n'  
            msg += '\n'  
        if bot_author:  
            msg += f'*BotAuthor*: @{bot_author}\n'  
        if foot:  
            msg += foot  
        bot.send_message(chat_id, msg, parse_mode='Markdown')  
  
if __name__ == '__main__':  
    accounts =  {'user1': 'pass1',  
                 'user2': 'pass2',  
                 'user3': 'pass3'}  
    freenom = FreeNom()  
    freenom.run(accounts)  
    # freenom.send_wecom(token='your_wecom_bot_token', title='域名续期播报')  
    freenom.send_telegram(token='your_telegram_bot_token', chat_id='your_telegram_tunnel_id', title='域名续期播报', tags=['家庭基建', '域名续期', '免费域名', 'freenom'])

配置 crontab 定时任务,每天早上 9 点进行播报。

# freenom auto monitor
59 8 * * *      /usr/bin/python3 /data/tools/telegram-bots/freenom_alert.py

总结

telegram 机器人的功能还很丰富,后边有机会继续分享。


评论