修改通知时间为晚上10点,添加cookie保存功能,按用户和域名区分保存
This commit is contained in:
+12
-4
@@ -9,7 +9,8 @@
|
||||
},
|
||||
"notification": {
|
||||
"iyuu_token": "IYUU37629Tc1d371c7ce99a49ff9778e196286b7e4592be191",
|
||||
"max_fail_count": 3
|
||||
"max_fail_count": 3,
|
||||
"notify_on_success": true
|
||||
},
|
||||
"browser": {
|
||||
"type": "edge",
|
||||
@@ -33,7 +34,8 @@
|
||||
},
|
||||
"notification": {
|
||||
"iyuu_token": "IYUU37629Tc1d371c7ce99a49ff9778e196286b7e4592be191",
|
||||
"max_fail_count": 3
|
||||
"max_fail_count": 3,
|
||||
"notify_on_success": true
|
||||
},
|
||||
"browser": {
|
||||
"type": "edge",
|
||||
@@ -44,9 +46,15 @@
|
||||
"name": "网站A",
|
||||
"url": "https://lmkbi.95155.com/bi-system/#/carUnpetrifiedComAll",
|
||||
"login_check_selector": "",
|
||||
"success_text": ""
|
||||
"success_text": "彭峰"
|
||||
},
|
||||
{
|
||||
"name": "网站B",
|
||||
"url": "https://192.168.1.200:8006/",
|
||||
"login_check_selector": "",
|
||||
"success_text": "彭峰"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
+50
-157
@@ -1,160 +1,53 @@
|
||||
{
|
||||
"cookies": [
|
||||
{
|
||||
"name": "JSESSIONID",
|
||||
"value": "DD8A9B4F6E06DF35AE1EC2339DF0FA36",
|
||||
"domain": "10.190.1.205"
|
||||
},
|
||||
{
|
||||
"name": "__rubyUX",
|
||||
"value": "false",
|
||||
"domain": "ntp.msn.cn"
|
||||
},
|
||||
{
|
||||
"name": "pglt-edgeChromium-dhp",
|
||||
"value": "2083",
|
||||
"domain": ".msn.cn"
|
||||
},
|
||||
{
|
||||
"name": "pglt-edgeChromium-ntp",
|
||||
"value": "2083",
|
||||
"domain": ".msn.cn"
|
||||
},
|
||||
{
|
||||
"name": "_C_Auth",
|
||||
"value": "",
|
||||
"domain": "ntp.msn.cn"
|
||||
},
|
||||
{
|
||||
"name": "MicrosoftApplicationsTelemetryDeviceId",
|
||||
"value": "da0bf04e-2115-4952-a012-fc29b4954ec0",
|
||||
"domain": "ntp.msn.cn"
|
||||
},
|
||||
{
|
||||
"name": "USRLOC",
|
||||
"value": "",
|
||||
"domain": ".msn.cn"
|
||||
},
|
||||
{
|
||||
"name": "MUID",
|
||||
"value": "15CB8BCF863F643B03449CDE8778658F",
|
||||
"domain": ".msn.cn"
|
||||
},
|
||||
{
|
||||
"name": "v1",
|
||||
"value": "ExJ_flr=b!>Rb_?o_sb/",
|
||||
"domain": ".mediav.com"
|
||||
},
|
||||
{
|
||||
"name": "MUID",
|
||||
"value": "15CB8BCF863F643B03449CDE8778658F",
|
||||
"domain": ".bing.com"
|
||||
},
|
||||
{
|
||||
"name": "MR",
|
||||
"value": "0",
|
||||
"domain": ".c.bing.com"
|
||||
},
|
||||
{
|
||||
"name": "SRM_B",
|
||||
"value": "15CB8BCF863F643B03449CDE8778658F",
|
||||
"domain": ".c.bing.com"
|
||||
},
|
||||
{
|
||||
"name": "MR",
|
||||
"value": "0",
|
||||
"domain": ".c.msn.cn"
|
||||
},
|
||||
{
|
||||
"name": "MUIDB",
|
||||
"value": "15CB8BCF863F643B03449CDE8778658F",
|
||||
"domain": "ntp.msn.cn"
|
||||
},
|
||||
{
|
||||
"name": ".ASPXANONYMOUS",
|
||||
"value": "21JPwTAtPyn84bHA6aNjbcWhPsVrLyiIZ-4mnJ6_dMtvLzgXbw3J9nyy0dxCZj0b8vOEHXZpgfYoPylWhp5s3AY2GwcwdYg9JI6VqZ6YK3uRkwMf0",
|
||||
"domain": "i3.sinopec.com"
|
||||
},
|
||||
{
|
||||
"name": "x",
|
||||
"value": "x",
|
||||
"domain": "auth.siam.sinopec.com"
|
||||
},
|
||||
{
|
||||
"name": "msnup",
|
||||
"value": "%7B%22cnex%22%3A%22no%22%7D",
|
||||
"domain": ".msn.cn"
|
||||
},
|
||||
{
|
||||
"name": "msaoptout",
|
||||
"value": "0",
|
||||
"domain": "ntp.msn.cn"
|
||||
},
|
||||
{
|
||||
"name": "OptanonAlertBoxClosed",
|
||||
"value": "2026-03-04T08:18:01.713Z",
|
||||
"domain": ".msn.cn"
|
||||
},
|
||||
{
|
||||
"name": "eupubconsent-v2",
|
||||
"value": "CQghjcAQghjcAAcABBZHBfFsAP_gAELgACiQK4tX_G__bXlr8X73aftkeY1f99h77sQxBhaJk-4FzJvW_JwX32E7NAz6tqYKmRIAu3TBAQNlHJDURVCgaIgVqSDMaEyUoTNKJ6BkiFMRY2dYCFxvm4tjeQCY5vr991d52B-t7dr83dzyy4hHv3a5_0S1WAAAAYCNDfv9bROb-9IO9_x8v4v4_F7pE2_eS1l_tWvp7D9-cts_9XW99_bbff9Pn_-uF_-_X_vf_H37v9oK5AACAAAARgkCAAAgAAAAABAAAAAQAAAAAQBgAAARBAEAAgAQGEgAEAAAAIAAAAAgSAAAAAJAAgAAAABQAAAIBAAAAwAIBgAAGAAACABACAAAAgEgYJgQQCBAABCYBAAgQgAAAACwECAABAgiACEQcAQAAAAAAAAEAAoAAEAgDAQkkBCxIIAuIJoAACAAAIIAChFJ2YAggDNlqrwZNoytMCwfMFzymAZAEQRk5JsQmsAoJA1AAQAAuACgAKgAcAA8ACCAGQAagA8ACIAEwAKoAbwA9AB-AEJAIYAiQBHACWAE0AK0AYYAywBsgDvgHsAfEA-wD9AIBARcBGACNAFBAKgAVcAuYBigDaAG4AOIAkQBOwChwFHgKRAWwAuQBd4DDQGSAMnAZcAzmBrAGsgNvAeOEAMAAOAHOAQcAn4CPQEigJWATaAsIBeQDEAGLQMhAyMBowDUwG0ANuAboA8oB8gD9wICAQMAgiOATgAIgAcAB4AFwAfgBoAHOAO4AgEBBwEIAJ-AVAAvQB0gEegJFASsAmIBMoCbQFIAKTAWoAvoBiADFgGQgMmAaMA00BqYDXgG0ANuAeUA-IB9sD9gP3AgeBBEdBAAAXABQAFQAOAAgABdADIANQAeABEACYAFWALgAugBiADeAHoAP0AhgCJAEsAJoAUYArQBhgDKAGiANkAd4A9oB9gH7ARYBGACggFXALEAXMAvIBigDaAG4AOIAdQBF4CRAEyAJ2AUOAo8BTQCxQFsALgAXIAu0Bd4DDQGPAMkAZOAyqBlgGXAM5AaqA1gBt4DxwH1gQBIAHAAEABoAHOAWIBB4CPQE2gKTAVKAvIBqYDbAG3APKAfEA_YCB4EGAINgQrAimBGkCN8EkQSSAqmBWkCtsFcQVyIQIwAFgAUABcAFUALgAYgA3gB6AEcAO8AigBKQCggFXALmAYoA2gB1IFNAU2AqwBYoC0QFwALkAZOAzkBqoDxwH9gQtAh6BIoCSAFSgKvkoD4ACAAFgAUAA4ADwAIgATAAqgBcADFAIYAiQBHACjAFaANkAd4A_ACrgGKAOoAi8BIgCjwFigLYAZOAywBnIDWAG3gQPJADQALgDuAIAAVABHoCRQErAJtAUmAxYB5QD9wIIlIFwAC4AKAAqABwAEEAMgA0AB4AEQAJgAVQAxAB-gEMARIAowBWgDKAGiANkAd8A-wD9AIsARgAoIBVwC5gF5AMUAbQA3ACLwEiAJ2AUOApoBYoC2AFwALkAXaAw0BkgDJwGXAM5gawBrIDbwHjlADYAFwBHADnAHcAQAAkQBYgDXgHbAP-Aj0BIoCYgE2gKQAU-AvIBfQDFgGTANTAa8A8oB8UD9gP3AgYBA8.f_wACFwAAAAA",
|
||||
"domain": ".msn.cn"
|
||||
},
|
||||
{
|
||||
"name": "MSFPC",
|
||||
"value": "GUID=139384d4545d4f4583ff3ef161faee39&HASH=1393&LV=202603&V=4&LU=1772612281994",
|
||||
"domain": "ntp.msn.cn"
|
||||
},
|
||||
{
|
||||
"name": "UID",
|
||||
"value": "1862498edfbe5a24e12c8d21772613043",
|
||||
"domain": ".scorecardresearch.com"
|
||||
},
|
||||
{
|
||||
"name": "XID",
|
||||
"value": "1862498edfbe5a24e12c8d21772613043",
|
||||
"domain": ".scorecardresearch.com"
|
||||
},
|
||||
{
|
||||
"name": "SM",
|
||||
"value": "C",
|
||||
"domain": ".c.msn.cn"
|
||||
},
|
||||
{
|
||||
"name": "JSESSIONID",
|
||||
"value": "DD8A9B4F6E06DF35AE1EC2339DF0FA36",
|
||||
"domain": "10.190.1.205"
|
||||
},
|
||||
{
|
||||
"name": "language",
|
||||
"value": "zh-CN",
|
||||
"domain": "192.168.8.147"
|
||||
},
|
||||
{
|
||||
"name": "fnos-token",
|
||||
"value": "n4fYErf2p2lHSucAt8uYAo+M+JDy354smCjF98dHtJM=",
|
||||
"domain": "192.168.8.147"
|
||||
},
|
||||
{
|
||||
"name": "fnos-long-token",
|
||||
"value": "07MRUOgDAAC3g89pAAAAAMrPwB8hdcC8nqwi0bqBWfNDO0uPBM7fPQ==",
|
||||
"domain": "192.168.8.147"
|
||||
},
|
||||
{
|
||||
"name": "_C_ETH",
|
||||
"value": "1",
|
||||
"domain": ".msn.cn"
|
||||
},
|
||||
{
|
||||
"name": "_EDGE_S",
|
||||
"value": "\"SID=217608637BE1667B39501F717A966764\"",
|
||||
"domain": ".msn.cn"
|
||||
},
|
||||
{
|
||||
"name": "OptanonConsent",
|
||||
"value": "isGpcEnabled=0&datestamp=Wed+Mar+04+2026+17%3A09%3A17+GMT%2B0800+(%E4%B8%AD%E5%9B%BD%E6%A0%87%E5%87%86%E6%97%B6%E9%97%B4)&version=202501.2.0&browserGpcFlag=0&isIABGlobal=false&hosts=&consentId=3599d387-f02a-409c-910d-0a6caea03c05&interactionCount=1&isAnonUser=1&landingPath=NotLandingPage&groups=C0001%3A1%2CC0002%3A1%2CC0004%3A1%2CC0008%3A1%2CV2STACK42%3A1&AwaitingReconsent=false&intType=1&geolocation=%3B",
|
||||
"domain": ".msn.cn"
|
||||
"用户A": {
|
||||
"lmkbi.95155.com": {
|
||||
"cookies": [],
|
||||
"url": "https://lmkbi.95155.com/bi-system/#/carUnpetrifiedComAll",
|
||||
"website_name": "网站A"
|
||||
}
|
||||
],
|
||||
"url": "http://192.168.8.147:5666/login"
|
||||
},
|
||||
"用户B": {
|
||||
"lmkbi.95155.com": {
|
||||
"cookies": [
|
||||
{
|
||||
"name": "_qimei_uuid42",
|
||||
"value": "1a302130f16100ca18af370a47cb8afce807c4a076",
|
||||
"domain": ".95155.com"
|
||||
},
|
||||
{
|
||||
"name": "_qimei_fingerprint",
|
||||
"value": "50aa79f919511142818459f44ac38dee",
|
||||
"domain": ".95155.com"
|
||||
},
|
||||
{
|
||||
"name": "_qimei_i_3",
|
||||
"value": "64c844d0c35e05dc9796fc355d8470e5a3eba5f0410e00d3e78c2d0e2f95293d306031943c89e29eb6a6",
|
||||
"domain": ".95155.com"
|
||||
},
|
||||
{
|
||||
"name": "_qimei_h38",
|
||||
"value": "f8e0750618af370a47cb8afc0200000c91a302",
|
||||
"domain": ".95155.com"
|
||||
},
|
||||
{
|
||||
"name": "_qimei_i_1",
|
||||
"value": "42d946d49d0f50dcc497f83153d525e3f0eef5f51508518ae5d97b582493206c6163649c39d8e1dcd4a9dffb",
|
||||
"domain": ".95155.com"
|
||||
}
|
||||
],
|
||||
"url": "https://lmkbi.95155.com/bi-system/#/carUnpetrifiedComAll",
|
||||
"website_name": "网站A"
|
||||
},
|
||||
"192.168.1.200:8006": {
|
||||
"cookies": [
|
||||
{
|
||||
"name": "PVELangCookie",
|
||||
"value": "zh_CN",
|
||||
"domain": "192.168.1.200"
|
||||
}
|
||||
],
|
||||
"url": "https://192.168.1.200:8006/",
|
||||
"website_name": "网站B"
|
||||
}
|
||||
}
|
||||
}
|
||||
+73
-49
@@ -4,7 +4,7 @@ from tkinter import ttk, messagebox
|
||||
import json
|
||||
import os
|
||||
import logging
|
||||
from DrissionPage import Chromium, ChromiumOptions
|
||||
from DrissionPage import ChromiumPage, ChromiumOptions
|
||||
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
@@ -25,8 +25,7 @@ class CookieExtractorApp:
|
||||
self.root.geometry("600x250")
|
||||
self.root.resizable(True, True)
|
||||
|
||||
self.browser = None
|
||||
self.tab = None
|
||||
self.page = None
|
||||
|
||||
self._create_widgets()
|
||||
|
||||
@@ -64,6 +63,18 @@ class CookieExtractorApp:
|
||||
ttk.Label(status_frame, text="状态:").pack(side=tk.LEFT, padx=5)
|
||||
ttk.Label(status_frame, textvariable=self.status_var, foreground="blue").pack(side=tk.LEFT, padx=5)
|
||||
|
||||
def _init_browser(self):
|
||||
"""初始化浏览器"""
|
||||
co = ChromiumOptions()
|
||||
co.set_browser_path(r"C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe")
|
||||
self.page = ChromiumPage(addr_or_opts=co)
|
||||
|
||||
def _wait_page_loaded(self, timeout=30):
|
||||
"""等待页面加载完成"""
|
||||
if self.page:
|
||||
self.page.wait.doc_loaded(timeout=timeout)
|
||||
self.page.ele('tag:body', timeout=timeout)
|
||||
|
||||
def open_website(self):
|
||||
"""打开指定网站"""
|
||||
url = self.url_var.get().strip()
|
||||
@@ -82,24 +93,13 @@ class CookieExtractorApp:
|
||||
self.status_var.set("正在打开浏览器...")
|
||||
self.root.update()
|
||||
|
||||
co = ChromiumOptions()
|
||||
co.set_browser_path(r"C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe")
|
||||
co.set_argument('--no-sandbox')
|
||||
co.set_argument('--disable-dev-shm-usage')
|
||||
|
||||
self.browser = Chromium(co)
|
||||
self.tab = self.browser.new_tab()
|
||||
self._init_browser()
|
||||
|
||||
self.status_var.set(f"正在访问: {url}")
|
||||
self.root.update()
|
||||
|
||||
self.tab.get(url)
|
||||
|
||||
self.status_var.set("等待页面加载...")
|
||||
self.root.update()
|
||||
|
||||
self.tab.wait.load_start()
|
||||
self.tab.wait.doc_loaded()
|
||||
self.page.get(url)
|
||||
self._wait_page_loaded()
|
||||
|
||||
self.status_var.set(f"已打开: {url}")
|
||||
self.save_button.config(state=tk.NORMAL)
|
||||
@@ -113,16 +113,15 @@ class CookieExtractorApp:
|
||||
|
||||
def save_cookies(self):
|
||||
"""保存当前的cookie信息,并强制关闭浏览器"""
|
||||
if not self.browser or not self.tab:
|
||||
if not self.page:
|
||||
messagebox.showerror("错误", "请先打开网站")
|
||||
return
|
||||
|
||||
try:
|
||||
self.status_var.set("正在提取cookies...")
|
||||
self.status_var.set("正在保存Cookies...")
|
||||
self.root.update()
|
||||
|
||||
cookies = self.browser.cookies()
|
||||
logger.info(f"成功提取 {len(cookies)} 个 cookies")
|
||||
cookies = self.page.cookies()
|
||||
|
||||
data = {
|
||||
"cookies": cookies,
|
||||
@@ -133,13 +132,12 @@ class CookieExtractorApp:
|
||||
with open(output_file, 'w', encoding='utf-8') as f:
|
||||
json.dump(data, f, indent=2, ensure_ascii=False)
|
||||
|
||||
self.status_var.set("正在关闭浏览器...")
|
||||
self.root.update()
|
||||
self.page.quit()
|
||||
self.page = None
|
||||
self.save_button.config(state=tk.DISABLED)
|
||||
|
||||
self._cleanup_browser()
|
||||
|
||||
self.status_var.set(f"数据已保存到: {output_file}")
|
||||
messagebox.showinfo("成功", f"已成功保存 {len(cookies)} 个cookie到: {output_file}\n\n浏览器已关闭")
|
||||
self.status_var.set(f"Cookies已保存到 {output_file}")
|
||||
messagebox.showinfo('成功', 'Cookies保存成功,浏览器已关闭')
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"保存cookies失败: {e}")
|
||||
@@ -148,7 +146,8 @@ class CookieExtractorApp:
|
||||
self._cleanup_browser()
|
||||
|
||||
def import_cookies(self):
|
||||
"""打开浏览器,导入cookie信息,然后打开指定网站"""
|
||||
"""打开浏览器,导入cookie和localStorage信息,然后打开指定网站"""
|
||||
import time
|
||||
try:
|
||||
output_file = "cookie_data.json"
|
||||
if not os.path.exists(output_file):
|
||||
@@ -163,6 +162,7 @@ class CookieExtractorApp:
|
||||
|
||||
url = data.get("url", "")
|
||||
cookies = data.get("cookies", [])
|
||||
local_storage = data.get("local_storage", {})
|
||||
|
||||
if not url:
|
||||
url = self.url_var.get().strip()
|
||||
@@ -179,17 +179,16 @@ class CookieExtractorApp:
|
||||
self.status_var.set("正在打开浏览器...")
|
||||
self.root.update()
|
||||
|
||||
co = ChromiumOptions()
|
||||
co.set_browser_path(r"C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe")
|
||||
co.set_argument('--no-sandbox')
|
||||
co.set_argument('--disable-dev-shm-usage')
|
||||
self._init_browser()
|
||||
|
||||
self.browser = Chromium(co)
|
||||
self.tab = self.browser.new_tab()
|
||||
|
||||
self.status_var.set("正在准备环境...")
|
||||
self.status_var.set("等待浏览器就绪...")
|
||||
self.root.update()
|
||||
self.tab.get("about:blank")
|
||||
self.page.get("about:blank")
|
||||
time.sleep(1)
|
||||
|
||||
from urllib.parse import urlparse
|
||||
parsed = urlparse(url)
|
||||
domain = parsed.netloc
|
||||
|
||||
if cookies:
|
||||
self.status_var.set("正在导入cookies...")
|
||||
@@ -201,25 +200,51 @@ class CookieExtractorApp:
|
||||
if not cookie.get('name') or not cookie.get('value'):
|
||||
continue
|
||||
|
||||
cookie.setdefault('path', '/')
|
||||
cookie.setdefault('httpOnly', False)
|
||||
cookie.setdefault('secure', False)
|
||||
cookie_dict = {
|
||||
'name': cookie.get('name'),
|
||||
'value': cookie.get('value'),
|
||||
'domain': cookie.get('domain', domain),
|
||||
'path': cookie.get('path', '/')
|
||||
}
|
||||
|
||||
self.browser.set.cookies([cookie])
|
||||
self.page.set.cookies(cookie_dict)
|
||||
success_count += 1
|
||||
except Exception as e:
|
||||
logger.error(f"导入cookie失败: {cookie.get('name')} - {e}")
|
||||
|
||||
logger.info(f"成功导入 {success_count} 个 cookies")
|
||||
|
||||
if local_storage:
|
||||
self.status_var.set("正在导入localStorage...")
|
||||
self.root.update()
|
||||
|
||||
ls_count = 0
|
||||
for ls_domain, items in local_storage.items():
|
||||
try:
|
||||
for key, value in items.items():
|
||||
try:
|
||||
self.page.set.local_storage(key, value)
|
||||
ls_count += 1
|
||||
except Exception as e:
|
||||
logger.error(f"导入localStorage失败: {key} - {e}")
|
||||
except Exception as e:
|
||||
logger.error(f"导入localStorage域失败: {ls_domain} - {e}")
|
||||
|
||||
logger.info(f"成功导入 {ls_count} 个 localStorage")
|
||||
|
||||
self.status_var.set(f"正在访问: {url}")
|
||||
self.root.update()
|
||||
self.tab.get(url)
|
||||
self.page.get(url)
|
||||
self._wait_page_loaded()
|
||||
|
||||
self.status_var.set("等待页面加载...")
|
||||
self.status_var.set("刷新页面验证登录状态...")
|
||||
self.root.update()
|
||||
self.tab.wait.load_start()
|
||||
self.tab.wait.doc_loaded()
|
||||
for i in range(3):
|
||||
self.page.refresh()
|
||||
self._wait_page_loaded()
|
||||
time.sleep(1)
|
||||
self.status_var.set(f"刷新第 {i+1} 次...")
|
||||
self.root.update()
|
||||
|
||||
self.url_var.set(url)
|
||||
self.status_var.set(f"已导入并打开: {url}")
|
||||
@@ -237,14 +262,13 @@ class CookieExtractorApp:
|
||||
self.root.destroy()
|
||||
|
||||
def _cleanup_browser(self):
|
||||
if self.browser:
|
||||
if self.page:
|
||||
try:
|
||||
self.browser.quit()
|
||||
self.page.quit()
|
||||
except Exception as e:
|
||||
logger.error(f"关闭浏览器失败: {e}")
|
||||
finally:
|
||||
self.browser = None
|
||||
self.tab = None
|
||||
self.page = None
|
||||
self.save_button.config(state=tk.DISABLED)
|
||||
self.status_var.set("就绪")
|
||||
|
||||
|
||||
+300
-52
@@ -1,13 +1,166 @@
|
||||
"""Cookie 监控主程序"""
|
||||
import json
|
||||
from datetime import datetime
|
||||
import time
|
||||
import os
|
||||
from datetime import datetime, time as dt_time
|
||||
from urllib.parse import urlparse
|
||||
from cookie_cloud import CookieCloud
|
||||
from notifier import IYUUNotifier, FailureTracker
|
||||
from browser_login import BrowserLogin, CookieManager
|
||||
from notifier import IYUUNotifier
|
||||
from applogger import setup_logging, get_logger
|
||||
from DrissionPage import ChromiumPage, ChromiumOptions
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
NOTIFY_TIMES = [6, 22]
|
||||
STATE_FILE = "notify_state.json"
|
||||
|
||||
|
||||
def load_notify_state() -> dict:
|
||||
if os.path.exists(STATE_FILE):
|
||||
try:
|
||||
with open(STATE_FILE, 'r', encoding='utf-8') as f:
|
||||
return json.load(f)
|
||||
except:
|
||||
pass
|
||||
return {}
|
||||
|
||||
|
||||
def save_notify_state(state: dict):
|
||||
try:
|
||||
with open(STATE_FILE, 'w', encoding='utf-8') as f:
|
||||
json.dump(state, f, indent=2, ensure_ascii=False)
|
||||
except Exception as e:
|
||||
logger.error(f"保存通知状态失败: {e}")
|
||||
|
||||
|
||||
def should_send_notification(user_name: str) -> bool:
|
||||
return False
|
||||
|
||||
|
||||
def mark_notification_sent(user_name: str):
|
||||
now = datetime.now()
|
||||
state = load_notify_state()
|
||||
|
||||
if user_name not in state:
|
||||
state[user_name] = {}
|
||||
|
||||
state[user_name]['date'] = now.strftime('%Y-%m-%d')
|
||||
state[user_name]['hour'] = now.hour
|
||||
|
||||
save_notify_state(state)
|
||||
|
||||
|
||||
class BrowserManager:
|
||||
"""浏览器管理器"""
|
||||
|
||||
def __init__(self, browser_type: str = 'edge', headless: bool = False):
|
||||
self.browser_type = browser_type
|
||||
self.headless = headless
|
||||
self.page = None
|
||||
|
||||
def init_browser(self):
|
||||
"""初始化浏览器"""
|
||||
co = ChromiumOptions()
|
||||
if self.browser_type == 'edge':
|
||||
co.set_browser_path(r"C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe")
|
||||
co.set_argument('--no-sandbox')
|
||||
co.set_argument('--disable-dev-shm-usage')
|
||||
if self.headless:
|
||||
co.set_argument('--headless')
|
||||
self.page = ChromiumPage(addr_or_opts=co)
|
||||
|
||||
def wait_page_loaded(self, timeout=30):
|
||||
"""等待页面加载完成"""
|
||||
if self.page:
|
||||
self.page.wait.doc_loaded(timeout=timeout)
|
||||
self.page.ele('tag:body', timeout=timeout)
|
||||
|
||||
def ensure_connection(self):
|
||||
"""确保浏览器连接正常"""
|
||||
try:
|
||||
if self.page:
|
||||
self.page.get("about:blank")
|
||||
return True
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
self.init_browser()
|
||||
self.page.get("about:blank")
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"无法建立浏览器连接: {e}")
|
||||
return False
|
||||
|
||||
def import_cookies(self, cookies: list, domain: str):
|
||||
"""导入cookies"""
|
||||
if not self.ensure_connection():
|
||||
return 0
|
||||
|
||||
success_count = 0
|
||||
for cookie in cookies:
|
||||
try:
|
||||
if not cookie.get('name') or not cookie.get('value'):
|
||||
continue
|
||||
|
||||
cookie_dict = {
|
||||
'name': cookie.get('name'),
|
||||
'value': cookie.get('value'),
|
||||
'domain': cookie.get('domain', domain),
|
||||
'path': cookie.get('path', '/')
|
||||
}
|
||||
|
||||
self.page.set.cookies(cookie_dict)
|
||||
success_count += 1
|
||||
except Exception as e:
|
||||
pass
|
||||
|
||||
return success_count
|
||||
|
||||
def verify_login(self, url: str, check_selector: str = "", success_text: str = "") -> bool:
|
||||
"""验证登录状态"""
|
||||
if not self.ensure_connection():
|
||||
return False
|
||||
|
||||
try:
|
||||
self.page.get(url)
|
||||
self.wait_page_loaded()
|
||||
|
||||
for i in range(3):
|
||||
time.sleep(1)
|
||||
self.page.refresh()
|
||||
self.wait_page_loaded()
|
||||
|
||||
if not check_selector:
|
||||
return True
|
||||
|
||||
try:
|
||||
element = self.page.ele(check_selector, timeout=10)
|
||||
if element:
|
||||
element_text = element.text or ""
|
||||
if not success_text:
|
||||
return True
|
||||
if success_text in element_text:
|
||||
return True
|
||||
except:
|
||||
pass
|
||||
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"验证登录状态失败: {e}")
|
||||
return False
|
||||
|
||||
def close(self):
|
||||
"""关闭浏览器"""
|
||||
if self.page:
|
||||
try:
|
||||
self.page.quit()
|
||||
except:
|
||||
pass
|
||||
finally:
|
||||
self.page = None
|
||||
|
||||
|
||||
class CookieMonitor:
|
||||
"""Cookie 监控器"""
|
||||
@@ -15,8 +168,7 @@ class CookieMonitor:
|
||||
def __init__(self, config_file: str = "config.json"):
|
||||
self.config_file = config_file
|
||||
self.config = self._load_config()
|
||||
self.cookie_manager = CookieManager("cookies.json")
|
||||
self.failure_tracker = FailureTracker("state.json")
|
||||
self.all_results = []
|
||||
|
||||
def _load_config(self) -> dict:
|
||||
try:
|
||||
@@ -26,14 +178,8 @@ class CookieMonitor:
|
||||
logger.error(f"加载配置文件失败: {e}")
|
||||
return {}
|
||||
|
||||
def _get_domain_from_url(self, url: str) -> str:
|
||||
from urllib.parse import urlparse
|
||||
return urlparse(url).netloc
|
||||
|
||||
def process_user(self, user_config: dict):
|
||||
"""
|
||||
处理单个用户:一次性导入所有cookies,然后验证各网站登录状态
|
||||
"""
|
||||
"""处理单个用户:依次验证各网站登录状态"""
|
||||
user_name = user_config.get('name', '未知用户')
|
||||
logger.info(f"{'='*20} 开始处理用户: {user_name} {'='*20}")
|
||||
|
||||
@@ -46,10 +192,6 @@ class CookieMonitor:
|
||||
logger.info(f"用户 {user_name} 没有配置网站,跳过")
|
||||
return
|
||||
|
||||
iyuu_token = notification_config.get('iyuu_token', '')
|
||||
max_fail_count = notification_config.get('max_fail_count', 3)
|
||||
notifier = IYUUNotifier(iyuu_token) if iyuu_token else None
|
||||
|
||||
cookie_cloud = CookieCloud(
|
||||
api_url=cookie_cloud_config.get('api_url', ''),
|
||||
uuid=cookie_cloud_config.get('uuid', ''),
|
||||
@@ -62,46 +204,44 @@ class CookieMonitor:
|
||||
total_cookies = sum(len(c) for c in all_cookies.values())
|
||||
logger.info(f"获取到 {total_domains} 个域名,共 {total_cookies} 个 cookie")
|
||||
|
||||
browser = BrowserLogin(
|
||||
browser = BrowserManager(
|
||||
browser_type=browser_config.get('type', 'edge'),
|
||||
headless=browser_config.get('headless', False)
|
||||
)
|
||||
|
||||
results = []
|
||||
user_results = {
|
||||
'user_name': user_name,
|
||||
'notification_config': notification_config,
|
||||
'websites': [],
|
||||
'success_count': 0,
|
||||
'fail_count': 0
|
||||
}
|
||||
|
||||
try:
|
||||
logger.info(f"步骤2: 一次性导入所有 cookies 到浏览器")
|
||||
all_cookies_list = []
|
||||
for cookies in all_cookies.values():
|
||||
all_cookies_list.extend(cookies)
|
||||
|
||||
import_success = browser.import_all_cookies(all_cookies_list)
|
||||
if import_success:
|
||||
logger.info(f"成功导入 {len(all_cookies_list)} 个 cookie")
|
||||
else:
|
||||
logger.warning(f"部分 cookie 导入失败")
|
||||
logger.info(f"步骤2: 初始化浏览器")
|
||||
browser.init_browser()
|
||||
|
||||
logger.info(f"步骤3: 依次验证各网站登录状态")
|
||||
for website in websites:
|
||||
result = self.process_website(
|
||||
user_name=user_name,
|
||||
website_config=website,
|
||||
browser=browser
|
||||
browser=browser,
|
||||
all_cookies=all_cookies
|
||||
)
|
||||
results.append(result)
|
||||
|
||||
if not result['success']:
|
||||
self.failure_tracker.check_and_notify(
|
||||
user_name=user_name,
|
||||
website_name=result['name'],
|
||||
max_fail_count=max_fail_count,
|
||||
notifier=notifier,
|
||||
error_msg=result['error']
|
||||
)
|
||||
user_results['websites'].append(result)
|
||||
|
||||
if result['success']:
|
||||
user_results['success_count'] += 1
|
||||
else:
|
||||
self.failure_tracker.reset_fail_count(user_name, result['name'])
|
||||
user_results['fail_count'] += 1
|
||||
|
||||
self._print_summary(user_name, results)
|
||||
self.all_results.append(user_results)
|
||||
self._print_summary(user_name, user_results['websites'])
|
||||
|
||||
logger.info(f"\n检查用户 {user_name} 是否需要发送通知")
|
||||
if should_send_notification(user_name):
|
||||
self._send_user_notification(user_results)
|
||||
|
||||
finally:
|
||||
browser.close()
|
||||
@@ -110,14 +250,10 @@ class CookieMonitor:
|
||||
self,
|
||||
user_name: str,
|
||||
website_config: dict,
|
||||
browser: BrowserLogin
|
||||
browser: BrowserManager,
|
||||
all_cookies: dict
|
||||
) -> dict:
|
||||
"""
|
||||
验证网站登录状态(cookies已预先导入)
|
||||
|
||||
Returns:
|
||||
dict: {'name': 网站名, 'url': URL, 'success': 是否成功, 'error': 错误信息}
|
||||
"""
|
||||
"""验证网站登录状态"""
|
||||
website_name = website_config.get('name', '未知网站')
|
||||
url = website_config.get('url', '')
|
||||
check_selector = website_config.get('login_check_selector', '')
|
||||
@@ -139,6 +275,22 @@ class CookieMonitor:
|
||||
return result
|
||||
|
||||
try:
|
||||
parsed = urlparse(url)
|
||||
domain = parsed.netloc
|
||||
|
||||
domain_cookies = []
|
||||
for cookie_domain, cookies in all_cookies.items():
|
||||
clean_domain = cookie_domain.lstrip('.')
|
||||
if domain in clean_domain or clean_domain in domain:
|
||||
domain_cookies.extend(cookies)
|
||||
|
||||
if domain_cookies:
|
||||
logger.info(f" 找到 {len(domain_cookies)} 个相关 cookie")
|
||||
success_count = browser.import_cookies(domain_cookies, domain)
|
||||
logger.info(f" 成功导入 {success_count} 个 cookie")
|
||||
else:
|
||||
logger.warning(f" 未找到相关 cookie")
|
||||
|
||||
login_success = browser.verify_login(
|
||||
url=url,
|
||||
check_selector=check_selector,
|
||||
@@ -149,10 +301,7 @@ class CookieMonitor:
|
||||
result['success'] = True
|
||||
logger.info(f" ✓ 登录验证成功")
|
||||
|
||||
new_cookies = browser.refresh_and_save_cookies(url)
|
||||
if new_cookies:
|
||||
self.cookie_manager.save_cookies(user_name, website_name, new_cookies)
|
||||
logger.info(f" 已保存 {len(new_cookies)} 个新 cookie")
|
||||
self._save_cookies_to_file(domain_cookies, url, website_name, user_name)
|
||||
else:
|
||||
result['error'] = '登录状态验证失败(cookies可能已过期或选择器配置错误)'
|
||||
logger.warning(f" ✗ {result['error']}")
|
||||
@@ -163,6 +312,49 @@ class CookieMonitor:
|
||||
|
||||
return result
|
||||
|
||||
def _save_cookies_to_file(self, cookies: list, url: str, website_name: str, user_name: str):
|
||||
"""保存 cookies 到文件(按用户和域名区分)"""
|
||||
try:
|
||||
parsed = urlparse(url)
|
||||
domain = parsed.netloc
|
||||
|
||||
cookie_entry = {
|
||||
"cookies": [],
|
||||
"url": url,
|
||||
"website_name": website_name
|
||||
}
|
||||
|
||||
for cookie in cookies:
|
||||
if cookie.get('name') and cookie.get('value'):
|
||||
cookie_entry["cookies"].append({
|
||||
"name": cookie.get('name'),
|
||||
"value": cookie.get('value'),
|
||||
"domain": cookie.get('domain', domain)
|
||||
})
|
||||
|
||||
filename = "cookie_data.json"
|
||||
|
||||
cookie_data = {}
|
||||
if os.path.exists(filename):
|
||||
with open(filename, 'r', encoding='utf-8') as f:
|
||||
try:
|
||||
cookie_data = json.load(f)
|
||||
except:
|
||||
cookie_data = {}
|
||||
|
||||
if user_name not in cookie_data:
|
||||
cookie_data[user_name] = {}
|
||||
|
||||
cookie_data[user_name][domain] = cookie_entry
|
||||
|
||||
with open(filename, 'w', encoding='utf-8') as f:
|
||||
json.dump(cookie_data, f, indent=2, ensure_ascii=False)
|
||||
|
||||
logger.info(f" 已保存 {len(cookie_entry['cookies'])} 个 cookie 到 {filename} ({user_name} -> {domain})")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f" 保存 cookie 失败: {e}")
|
||||
|
||||
def _print_summary(self, user_name: str, results: list):
|
||||
"""打印处理结果汇总"""
|
||||
success_count = sum(1 for r in results if r['success'])
|
||||
@@ -178,6 +370,59 @@ class CookieMonitor:
|
||||
if not r['success']:
|
||||
logger.info(f" - {r['name']}: {r['error']}")
|
||||
|
||||
def _send_user_notification(self, user_result: dict):
|
||||
"""发送单个用户的通知"""
|
||||
user_name = user_result['user_name']
|
||||
notification_config = user_result.get('notification_config', {})
|
||||
iyuu_token = notification_config.get('iyuu_token', '')
|
||||
|
||||
if not iyuu_token:
|
||||
return
|
||||
|
||||
notifier = IYUUNotifier(iyuu_token)
|
||||
|
||||
success_count = user_result['success_count']
|
||||
fail_count = user_result['fail_count']
|
||||
|
||||
title = f"【Cookie监控】{user_name} - 成功{success_count} 失败{fail_count}"
|
||||
|
||||
content_lines = [
|
||||
f"**{user_name} Cookie监控报告**",
|
||||
f"",
|
||||
f"监控时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}",
|
||||
f"成功: {success_count} 个网站",
|
||||
f"失败: {fail_count} 个网站",
|
||||
f"",
|
||||
]
|
||||
|
||||
for website in user_result['websites']:
|
||||
status = "✓ 成功" if website['success'] else f"✗ 失败: {website['error']}"
|
||||
content_lines.append(f" {website['name']}: {status}")
|
||||
|
||||
content = "\n".join(content_lines)
|
||||
|
||||
print(f"\n{'='*60}")
|
||||
print(f"发送用户通知: {user_name}")
|
||||
print(f"{'='*60}")
|
||||
print(f"\n发送内容:")
|
||||
print(f"Title: {title}")
|
||||
print(f"Content:\n{content}")
|
||||
print(f"\n发送方式: 爱语飞飞 API (GET 请求)")
|
||||
print(f"API URL: https://iyuu.cn/{iyuu_token}.send")
|
||||
print(f"参数: text={title}, desp={content[:50]}...")
|
||||
print(f"\n正在发送...")
|
||||
|
||||
logger.info(f"\n发送用户通知: {user_name}")
|
||||
logger.info(f"Title: {title}")
|
||||
|
||||
if notifier.send(title, content):
|
||||
print(f"\n发送结果: ✓ 成功")
|
||||
logger.info(f"✓ 用户 {user_name} 通知发送成功")
|
||||
mark_notification_sent(user_name)
|
||||
else:
|
||||
print(f"\n发送结果: ✗ 失败")
|
||||
logger.error(f"✗ 用户 {user_name} 通知发送失败")
|
||||
|
||||
def run(self):
|
||||
"""运行监控"""
|
||||
logger.info("="*50)
|
||||
@@ -197,6 +442,9 @@ class CookieMonitor:
|
||||
except Exception as e:
|
||||
logger.error(f"处理用户失败: {e}")
|
||||
|
||||
for user_result in self.all_results:
|
||||
pass
|
||||
|
||||
logger.info("\n" + "="*50)
|
||||
logger.info("Cookie 监控结束")
|
||||
logger.info("="*50)
|
||||
|
||||
+15
-150
@@ -1,6 +1,5 @@
|
||||
"""消息通知模块 - 通过爱语飞飞发送通知"""
|
||||
import requests
|
||||
from typing import Optional
|
||||
from applogger import get_logger
|
||||
|
||||
logger = get_logger(__name__)
|
||||
@@ -10,26 +9,17 @@ class IYUUNotifier:
|
||||
"""爱语飞飞通知客户端"""
|
||||
|
||||
def __init__(self, token: str):
|
||||
"""
|
||||
初始化爱语飞飞通知客户端
|
||||
|
||||
Args:
|
||||
token: 爱语飞飞令牌
|
||||
"""
|
||||
self.token = token
|
||||
self.api_url = f"https://iyuu.cn/{token}.send"
|
||||
|
||||
def send(self, title: str, content: str) -> bool:
|
||||
"""
|
||||
发送通知
|
||||
|
||||
Args:
|
||||
title: 通知标题
|
||||
content: 通知内容
|
||||
|
||||
Returns:
|
||||
是否发送成功
|
||||
"""
|
||||
print(f"\n{'='*50}")
|
||||
print(f"[测试] 准备发送通知")
|
||||
print(f"[测试] API URL: {self.api_url}")
|
||||
print(f"[测试] Title: {title}")
|
||||
print(f"[测试] Content: {content[:100]}...")
|
||||
print(f"{'='*50}\n")
|
||||
|
||||
try:
|
||||
response = requests.get(
|
||||
self.api_url,
|
||||
@@ -39,12 +29,20 @@ class IYUUNotifier:
|
||||
},
|
||||
timeout=10
|
||||
)
|
||||
|
||||
print(f"[测试] 响应状态码: {response.status_code}")
|
||||
print(f"[测试] 响应内容: {response.text}")
|
||||
|
||||
response.raise_for_status()
|
||||
result = response.json()
|
||||
|
||||
print(f"[测试] 解析结果: {result}")
|
||||
|
||||
if result.get('errcode') == 0:
|
||||
print(f"[测试] ✓ 发送成功!")
|
||||
return True
|
||||
else:
|
||||
print(f"[测试] ✗ 发送失败: {result.get('errmsg')}")
|
||||
logger.error(f"发送通知失败: {result.get('errmsg')}")
|
||||
return False
|
||||
|
||||
@@ -54,136 +52,3 @@ class IYUUNotifier:
|
||||
except Exception as e:
|
||||
logger.error(f"发送通知异常: {e}")
|
||||
return False
|
||||
|
||||
|
||||
class FailureTracker:
|
||||
"""失败次数追踪器"""
|
||||
|
||||
def __init__(self, state_file: str):
|
||||
"""
|
||||
初始化失败次数追踪器
|
||||
|
||||
Args:
|
||||
state_file: 状态文件路径
|
||||
"""
|
||||
self.state_file = state_file
|
||||
self.state = self._load_state()
|
||||
|
||||
def _load_state(self) -> dict:
|
||||
"""加载状态文件"""
|
||||
import json
|
||||
import os
|
||||
|
||||
if os.path.exists(self.state_file):
|
||||
try:
|
||||
with open(self.state_file, 'r', encoding='utf-8') as f:
|
||||
return json.load(f)
|
||||
except Exception as e:
|
||||
logger.error(f"加载状态文件失败: {e}")
|
||||
|
||||
return {}
|
||||
|
||||
def _save_state(self):
|
||||
"""保存状态文件"""
|
||||
import json
|
||||
|
||||
try:
|
||||
with open(self.state_file, 'w', encoding='utf-8') as f:
|
||||
json.dump(self.state, f, indent=2, ensure_ascii=False)
|
||||
except Exception as e:
|
||||
logger.error(f"保存状态文件失败: {e}")
|
||||
|
||||
def get_fail_count(self, user_name: str, website_name: str) -> int:
|
||||
"""
|
||||
获取指定网站的失败次数
|
||||
|
||||
Args:
|
||||
user_name: 用户名
|
||||
website_name: 网站名
|
||||
|
||||
Returns:
|
||||
失败次数
|
||||
"""
|
||||
key = f"{user_name}_{website_name}"
|
||||
return self.state.get(key, 0)
|
||||
|
||||
def increment_fail_count(self, user_name: str, website_name: str) -> int:
|
||||
"""
|
||||
增加失败次数
|
||||
|
||||
Args:
|
||||
user_name: 用户名
|
||||
website_name: 网站名
|
||||
|
||||
Returns:
|
||||
增加后的失败次数
|
||||
"""
|
||||
key = f"{user_name}_{website_name}"
|
||||
self.state[key] = self.state.get(key, 0) + 1
|
||||
self._save_state()
|
||||
return self.state[key]
|
||||
|
||||
def reset_fail_count(self, user_name: str, website_name: str):
|
||||
"""
|
||||
重置失败次数
|
||||
|
||||
Args:
|
||||
user_name: 用户名
|
||||
website_name: 网站名
|
||||
"""
|
||||
key = f"{user_name}_{website_name}"
|
||||
self.state[key] = 0
|
||||
self._save_state()
|
||||
|
||||
def check_and_notify(
|
||||
self,
|
||||
user_name: str,
|
||||
website_name: str,
|
||||
max_fail_count: int,
|
||||
notifier: Optional[IYUUNotifier],
|
||||
error_msg: str
|
||||
) -> bool:
|
||||
"""
|
||||
检查失败次数并在达到阈值时发送通知
|
||||
|
||||
Args:
|
||||
user_name: 用户名
|
||||
website_name: 网站名
|
||||
max_fail_count: 最大失败次数
|
||||
notifier: 爱语飞飞通知客户端
|
||||
error_msg: 错误信息
|
||||
|
||||
Returns:
|
||||
是否应该停止重试
|
||||
"""
|
||||
fail_count = self.increment_fail_count(user_name, website_name)
|
||||
|
||||
if fail_count >= max_fail_count:
|
||||
# 发送通知
|
||||
if notifier:
|
||||
title = f"【Cookie监控】{user_name} - {website_name} 登录失败"
|
||||
content = f"网站: {website_name}\n用户: {user_name}\n连续失败次数: {fail_count}\n错误信息: {error_msg}"
|
||||
|
||||
if notifier.send(title, content):
|
||||
logger.info(f"已发送失败通知: {user_name} - {website_name}")
|
||||
else:
|
||||
logger.error(f"发送失败通知失败: {user_name} - {website_name}")
|
||||
|
||||
# 重置失败计数
|
||||
self.reset_fail_count(user_name, website_name)
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# 测试代码
|
||||
tracker = FailureTracker("state.json")
|
||||
|
||||
# 增加失败次数
|
||||
count = tracker.increment_fail_count("测试用户", "测试网站")
|
||||
logger.info(f"当前失败次数: {count}")
|
||||
|
||||
# 检查并发送通知(需要真实的爱语飞飞令牌)
|
||||
# notifier = IYUUNotifier("您的爱语飞飞令牌")
|
||||
# tracker.check_and_notify("测试用户", "测试网站", 3, notifier, "测试错误信息")
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"用户A": {
|
||||
"date": "2026-03-04",
|
||||
"hour": 22
|
||||
},
|
||||
"用户B": {
|
||||
"date": "2026-03-04",
|
||||
"hour": 22
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
"""直接发送测试消息给两个用户"""
|
||||
from notifier import IYUUNotifier
|
||||
from datetime import datetime
|
||||
|
||||
iyuu_token = "IYUU37629Tc1d371c7ce99a49ff9778e196286b7e4592be191"
|
||||
notifier = IYUUNotifier(iyuu_token)
|
||||
|
||||
print("="*60)
|
||||
print("发送测试消息给用户A")
|
||||
print("="*60)
|
||||
|
||||
title_a = "【测试】用户A - Cookie监控测试"
|
||||
content_a = f"""**用户A Cookie监控测试报告**
|
||||
|
||||
测试时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
|
||||
测试类型: 直接发送测试消息
|
||||
|
||||
这是一条测试消息,用于验证爱语飞飞通知功能是否正常工作。
|
||||
|
||||
如果您收到此消息,说明通知功能正常。"""
|
||||
|
||||
print(f"\n发送内容:")
|
||||
print(f"Title: {title_a}")
|
||||
print(f"Content:\n{content_a}")
|
||||
print(f"\n发送方式: 爱语飞飞 API (GET 请求)")
|
||||
print(f"API URL: https://iyuu.cn/{iyuu_token}.send")
|
||||
print(f"参数: text={title_a}, desp={content_a}")
|
||||
print("\n正在发送...")
|
||||
|
||||
result_a = notifier.send(title_a, content_a)
|
||||
print(f"\n发送结果: {'✓ 成功' if result_a else '✗ 失败'}")
|
||||
|
||||
print("\n" + "="*60)
|
||||
print("发送测试消息给用户B")
|
||||
print("="*60)
|
||||
|
||||
title_b = "【测试】用户B - Cookie监控测试"
|
||||
content_b = f"""**用户B Cookie监控测试报告**
|
||||
|
||||
测试时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
|
||||
测试类型: 直接发送测试消息
|
||||
|
||||
这是一条测试消息,用于验证爱语飞飞通知功能是否正常工作。
|
||||
|
||||
如果您收到此消息,说明通知功能正常。"""
|
||||
|
||||
print(f"\n发送内容:")
|
||||
print(f"Title: {title_b}")
|
||||
print(f"Content:\n{content_b}")
|
||||
print(f"\n发送方式: 爱语飞飞 API (GET 请求)")
|
||||
print(f"API URL: https://iyuu.cn/{iyuu_token}.send")
|
||||
print(f"参数: text={title_b}, desp={content_b}")
|
||||
print("\n正在发送...")
|
||||
|
||||
result_b = notifier.send(title_b, content_b)
|
||||
print(f"\n发送结果: {'✓ 成功' if result_b else '✗ 失败'}")
|
||||
|
||||
print("\n" + "="*60)
|
||||
print("测试完成")
|
||||
print("="*60)
|
||||
print(f"用户A: {'✓ 发送成功' if result_a else '✗ 发送失败'}")
|
||||
print(f"用户B: {'✓ 发送成功' if result_b else '✗ 发送失败'}")
|
||||
@@ -0,0 +1,42 @@
|
||||
"""测试爱语飞飞通知"""
|
||||
import requests
|
||||
|
||||
iyuu_token = "IYUU37629Tc1d371c7ce99a49ff9778e196286b7e4592be191"
|
||||
api_url = f"https://iyuu.cn/{iyuu_token}.send"
|
||||
|
||||
title = "【测试】Cookie监控通知测试"
|
||||
content = """这是一条测试消息。
|
||||
|
||||
测试时间: 2026-03-04
|
||||
测试内容: 验证爱语飞飞通知是否正常工作
|
||||
|
||||
如果您收到此消息,说明通知功能正常。"""
|
||||
|
||||
print(f"API URL: {api_url}")
|
||||
print(f"Title: {title}")
|
||||
print(f"Content: {content}")
|
||||
print("\n正在发送请求...")
|
||||
|
||||
try:
|
||||
response = requests.get(
|
||||
api_url,
|
||||
params={
|
||||
'text': title,
|
||||
'desp': content
|
||||
},
|
||||
timeout=10
|
||||
)
|
||||
|
||||
print(f"状态码: {response.status_code}")
|
||||
print(f"响应内容: {response.text}")
|
||||
|
||||
result = response.json()
|
||||
print(f"\n解析结果: {result}")
|
||||
|
||||
if result.get('errcode') == 0:
|
||||
print("\n✓ 发送成功!")
|
||||
else:
|
||||
print(f"\n✗ 发送失败: {result.get('errmsg')}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"\n✗ 请求异常: {e}")
|
||||
Reference in New Issue
Block a user