本文参考文献详见参考文献部分
sudo apt update && sudo apt upgrade
sudo apt install python3
sudo pip install requests beautifulsoup4
sudo pacman -Syu
sudo pacman -S python python-requests python-beautifulsoup4
这个脚本适用于即时获取隧道地址,可以在运行脚本后输入需要查询的隧道名称,也可以直接传入一个参数。记得把必要的(代码中的斜体内容)内容换成你自己的。嫌麻烦也可以看最后的注意事项。
import requests
from bs4 import BeautifulSoup
import sys
# 登录网站并获取页面内容
def fetch_info_from_website(login_url, info_url, credentials, tunnel_name):
with requests.Session() as session:
try:
# 获取登录页面以抓取csrf token
login_page = session.get(login_url)
login_page.raise_for_status() # 检查请求是否成功
login_page_soup = BeautifulSoup(login_page.text, 'html.parser')
# 提取csrf token
csrf_token = login_page_soup.find('input', {'name': 'csrf_token'})['value']
credentials['csrf_token'] = csrf_token
# 登录
print("登录中,请等待。")
login_response = session.post(login_url, data=credentials)
# 检查是否登录成功
if login_response.status_code != 200 or login_response.url == login_url:
print("登录失败,请检查您的凭据。")
return []
else:
print("登录成功。")
# 获取信息页面
response = session.get(info_url)
response.raise_for_status()
# 解析页面
soup = BeautifulSoup(response.text, 'html.parser')
table = soup.find('table')
if not table:
print("未找到隧道列表,请检查对应设备的cpolar服务和网络连接。")
return []
links = [] # 用于存储找到的链接
for row in table.find_all('tr')[1:]: # 跳过表头
cells = row.find_all('td')
if len(cells) > 1:
tunnel = cells[0].get_text().strip()
url_cell = row.find('a', href=True) # 直接在行中查找<a>标签
if tunnel == tunnel_name and url_cell:
links.append(url_cell['href']) # 添加匹配的链接
print(f"找到隧道 {tunnel} 的链接: {url_cell['href']}")
return links
except requests.RequestException as e:
print(f"请求异常: {e}")
except Exception as e:
print(f"发生错误: {e}")
if __name__ == '__main__':
login_url = "https://dashboard.cpolar.com/login"
info_url = "https://dashboard.cpolar.com/status"
credentials = {
'login': 'example@example.com',
'password': 'yourpassword‘
}
# 检查是否有命令行参数传入
if len(sys.argv) > 1:
tunnel_name = sys.argv[1] # 第一个命令行参数作为隧道名称
else:
print("请提供一个隧道名称作为参数,或者留空以自动提示输入。")
tunnel_name = input("请输入隧道名称: ")
if not tunnel_name:
print("隧道名称不能为空。")
sys.exit(1)
links = fetch_info_from_website(login_url, info_url, credentials, tunnel_name)
if links:
print()
else:
print(f"没有找到名为 {tunnel_name} 的隧道链接。")
python collectaddresswithoutsending.py
python collectaddresswithoutsending.py tunnel_name
这个脚本适用于定时获取隧道地址并发送至指定邮箱,一般在脚本中指定隧道名称。
import requests
from bs4 import BeautifulSoup
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.header import Header
import smtplib
# 登录网站并获取页面内容
def fetch_info_from_website(login_url, info_url, credentials, tunnel_name):
with requests.Session() as session:
try:
# 获取登录页面以抓取csrf token
login_page = session.get(login_url)
login_page.raise_for_status() # 检查请求是否成功
login_page_soup = BeautifulSoup(login_page.text, 'html.parser')
# 提取csrf token
csrf_token = login_page_soup.find('input', {'name': 'csrf_token'})['value']
credentials['csrf_token'] = csrf_token
# 登录
print("登录中,请等待。")
login_response = session.post(login_url, data=credentials)
# 检查是否登录成功
if login_response.status_code != 200 or login_response.url == login_url:
print("登录失败,请检查您的凭据。")
return []
else:
print("登录成功。")
# 获取信息页面
response = session.get(info_url)
response.raise_for_status()
# 解析页面
soup = BeautifulSoup(response.text, 'html.parser')
table = soup.find('table')
if not table:
print("未找到隧道列表,请检查对应设备的cpolar服务和网络连接。")
return []
links = [] # 用于存储找到的链接
for row in table.find_all('tr')[1:]: # 跳过表头
cells = row.find_all('td')
if len(cells) > 1:
tunnel = cells[0].get_text().strip()
url_cell = row.find('a', href=True) # 直接在行中查找<a>标签
if tunnel == tunnel_name and url_cell:
links.append(url_cell['href']) # 添加匹配的链接
print(f"找到隧道 {tunnel} 的链接: {url_cell['href']}")
return links
except requests.RequestException as e:
print(f"请求异常: {e}")
except Exception as e:
print(f"发生错误: {e}")
# 发送邮件
def send_email(subject, body, to_email):
from_email = 'from_email@example.com'
auth_password = 'yourauth_password'
msg = MIMEMultipart('alternative')
msg['From'] = Header(from_email)
msg['To'] = Header(to_email)
msg['Subject'] = Header(subject)
# 邮件正文的纯文本版本
text = "这是邮件的纯文本版本,用于不支持HTML的邮件客户端。\n" + body
msg.attach(MIMEText(text, 'plain', 'utf-8'))
# 邮件正文的HTML版本
msg.attach(MIMEText(body, 'html', 'utf-8'))
try:
with smtplib.SMTP('yourSMTPserver', 587) as server:
server.starttls()
server.login(from_email, auth_password)
server.sendmail(from_email, [to_email], msg.as_string())
print("邮件发送成功")
except smtplib.SMTPException as e:
print("邮件发送失败:", e)
except Exception as e:
print("发送邮件时发生未知错误:", e)
if __name__ == '__main__':
login_url = "https://dashboard.cpolar.com/login"
info_url = "https://dashboard.cpolar.com/status"
credentials = {
'login': 'example@example.com',
'password': 'yourpassword'
}
tunnel_name = "tunnel_name" # 指定的隧道名称
links = fetch_info_from_website(login_url, info_url, credentials, tunnel_name)
if links:
to_email = "to_email@example.com"
subject = "Tunnel Links Notification"
html_links = "<br>".join([f"<a href='{link}'>{link}</a>" for link in links])
html_body = "<html><body><p>以下是更新后的链接:</p>" + html_links + "</body></html>"
send_email(subject, html_body, to_email)
else:
print(f"没有找到名为 {tunnel_name} 的隧道链接。")
在 crontab 里添加计划任务即可,这里就不重复造轮子了。
作者最终使用的发件邮箱是 icloud邮箱。
使用 outlook 邮箱。发件第一次一切正常,之后却没法正常发送邮件了,原因是微软在逐步淘汰Basic Auth,故使用 outlook 邮箱并不理想。本人能力有限没法写出用 OAuth2 协议的发件函数,大佬请自便。
使用 网易邮箱。也许是本人的问题,一次都未成功。
使用 QQ邮箱。本人尝试了一下发送没有问题,只是邮件发送成功后会有一条莫名其妙的报错信息。网上资料很少只能推测是 python 的邮件模块收到了 QQ邮箱 服务器发来的无法理解的信息故而报错,但实际上邮件是成功发送了的。虽然可以忽略,但是不够完美。
使用 icloud邮箱。没有次数限制,写脚本测试时没有失败过一次,Basic Auth 依旧可以正常使用。本人建议开启双重认证后生成专属的应用密码。
将邮箱密码明文编写到脚本中是绝对不安全的。本人使用生成的应用密码依然存在风险,如有需要建议使用环境变量或钥匙串提高安全等级。
关于 cpolar 的账号密码。该账号泄漏会泄漏你的通道地址。即使是面板通道,增加访问后缀,开启防火墙和防暴力破解软件,限制登录错误次数等等手段对个人内用户基本足够。对于 docker 应用等等应尽量避免使用特权模式的容器暴露等等。
总之不建议把密码硬编写入脚本。安全方面各位见仁见智,评估风险后决定采取相应的安全措施。
cpolar 账号与密码
发件邮箱地址与密码和对应的服务器地址与端口
收件邮箱地址
https://blog.csdn.net/qq_28319843/article/details/140876888