diff --git a/apps/common/sites_sign.py b/apps/common/sites_sign.py index 91dff73..f0f24dc 100644 --- a/apps/common/sites_sign.py +++ b/apps/common/sites_sign.py @@ -12,6 +12,7 @@ from .utils import getSiteUrl from paddleocr import PaddleOCR from thefuzz import fuzz from thefuzz import process +import random logger = logging.getLogger('sign') user_agent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36' @@ -75,7 +76,9 @@ def signIngress(site_name, site_name_cn, site_url, site_cookie, sign_type): elif sign_type == 'ptsbao': flag, data = ptsbao(site_name, site_name_cn, site_url, site_cookie) elif sign_type == 'ssd': - flag, data = ssd(site_name, site_name_cn, site_url, site_cookie) + flag, data = ssd(site_name, site_name_cn, site_url, site_cookie) + elif sign_type == 'u2': + flag, data = u2(site_name, site_name_cn, site_url, site_cookie) else: flag, data = (False,'%s 未匹配站点' % site_name) @@ -1564,6 +1567,90 @@ def ssd(site_name, site_name_cn, site_url, site_cookie): return False, msg + except Exception as e: + msg = "%s(%s) %s" % (site_name, site_name_cn, msg_err_url) + logger.error('--------------%s----------------' % site_name) + logger.error(str(e)) + + return False, msg + +def u2(site_name, site_name_cn, site_url, site_cookie): + """ + 签到 动漫花园 + """ + + headers = { + 'user-agent': user_agent, + 'cookie': site_cookie + } + + #获取网站url,不带/结尾 + sign_url = getSiteUrl(site_url) + '/showup.php' + + logger.info('--------------%s开始签到----------------' % site_name) + + try: + session = requests.session() + response = session.get(sign_url, headers=headers, timeout=10) + + if response.status_code == 200: + #需要安装pip install lxml + soup = BeautifulSoup(response.text, "lxml") + + tables = soup.findAll('table', {'class':'captcha'}) + #print(tables) + data = {} + captcha = [] + data['message'] = '我就是来签到看看:)!!!' + if len(tables) != 0: + + #获取所有input + info = tables[0].findAll('input') + for i in info: + #print(i) + #获取input的名称,用于post使用 + name = i.attrs['name'] + if name == 'req': + data['req'] = i.attrs['value'] + elif name == 'hash': + data['hash'] = i.attrs['value'] + elif name == 'form': + data['form'] = i.attrs['value'] + elif 'captcha' in name: + captcha.append(i.attrs['value']) + + #随机选择一个作为答案 + data['captcha'] = random.choice(captcha) + #不返回任何消息 + response = session.post("https://u2.dmhy.org/showup.php?action=show", headers=headers, data=data, timeout=10) + logger.info(data) + #确认是否签到成功 + response = session.get(sign_url, headers=headers, timeout=10) + soup = BeautifulSoup(response.text, "lxml") + h3 = soup.findAll('h3', {'align':'center'}) + if '今天已签到' in h3[0].get_text(): + msg = "%s(%s) %s" % (site_name,site_name_cn, msg_ok) + return True, msg + else: + msg = "%s(%s) %s" % (site_name,site_name_cn, msg_unknow) + return False, msg + + else: + h3 = soup.findAll('h3', {'align':'center'}) + if '今天已签到' in h3[0].get_text(): + msg = "%s(%s) %s" % (site_name, site_name_cn, msg_reok) + return True, msg + else: + msg = "%s(%s) %s" % (site_name, site_name_cn, msg_err_cookie) + return False, msg + + else: + msg = "%s(%s) %s" % (site_name, site_name_cn, msg_err_url) + logger.error('--------------%s----------------' % site_name) + logger.error(msg) + + return False, msg + except Exception as e: msg = "%s(%s) %s" % (site_name, site_name_cn, msg_err_url) logger.error('--------------%s----------------' % site_name) diff --git a/apps/common/sites_user.py b/apps/common/sites_user.py new file mode 100644 index 0000000..6bb448e --- /dev/null +++ b/apps/common/sites_user.py @@ -0,0 +1,280 @@ +# -*- coding:utf-8 -*- +from django.conf import settings +import logging +import os +from bs4 import BeautifulSoup +import requests +import simplejson as json +import re +import time +from .utils import getSiteUrl, parseUrl + + +logger = logging.getLogger('user') +user_agent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36 Edg/105.0.1343.27' + + +def userIngress(site_name, site_name_cn, site_url, site_cookie, sign_type): + """ + 站点用户匹配入口 + """ + if sign_type in ['general','opencd','nosign']: + flag, data = general(site_name, site_name_cn, site_url, site_cookie) + else: + flag, data = (False,'%s 未匹配站点' % site_name) + + return flag, data + + if sign_type == 'hdchina': + flag, data = hdchina(site_name, site_name_cn, site_url, site_cookie) + elif sign_type in ['general','opencd','nosign']: + flag, data = general(site_name, site_name_cn, site_url, site_cookie) + elif sign_type == 'pterclub': + flag, data = pterclub(site_name, site_name_cn, site_url, site_cookie) + elif sign_type == 'hdarea': + flag, data = hdarea(site_name, site_name_cn, site_url, site_cookie) + elif sign_type == 'hdcity': + flag, data = hdcity(site_name, site_name_cn, site_url, site_cookie) + elif sign_type == 'btschool': + flag, data = btschool(site_name, site_name_cn, site_url, site_cookie) + elif sign_type == 'hares': + flag, data = hares(site_name, site_name_cn, site_url, site_cookie) + elif sign_type == 'ttg': + flag, data = ttg(site_name, site_name_cn, site_url, site_cookie) + elif sign_type == 'pt52': + flag, data = pt52(site_name, site_name_cn, site_url, site_cookie) + + elif sign_type == 'keepfrds': + flag, data = keepfrds(site_name, site_name_cn, site_url, site_cookie) + elif sign_type == 'tjupt': + flag, data = tjupt(site_name, site_name_cn, site_url, site_cookie) + elif sign_type == 'hd': + flag, data = hd(site_name, site_name_cn, site_url, site_cookie) + elif sign_type == 'greatposterwall': + flag, data = greatposterwall(site_name, site_name_cn, site_url, site_cookie) + + elif sign_type == 'hdsky': + try: + flag, data = hdsky(site_name, site_name_cn, site_url, site_cookie) + except Exception as e: + logger.error(str(e)) + return False,'%s 数据异常' % site_name + elif sign_type == 'haidan': + flag, data = haidan(site_name, site_name_cn, site_url, site_cookie) + elif sign_type == 'ptsbao': + flag, data = ptsbao(site_name, site_name_cn, site_url, site_cookie) + elif sign_type == 'ssd': + flag, data = ssd(site_name, site_name_cn, site_url, site_cookie) + else: + flag, data = (False,'%s 未匹配站点' % site_name) + + return flag, data + +def RepresentsInt(s): + """ + 判断是否整形 + """ + try: + int(s) + return True + except ValueError: + return False + +def general(site_name, site_name_cn, site_url, site_cookie): + """ + 通用获取 + """ + + headers = { + 'user-agent': user_agent, + 'cookie': site_cookie + } + + logger.info('--------------%s开始获取用户信息----------------' % site_name) + + #获取网站url,不带/结尾 + url = getSiteUrl(site_url) + '/index.php' + + session = requests.session() + + data = {} + #初始0,有些站点可能没有积分 + data['score'] = 0 + try: + response = session.get(url, headers=headers, timeout=10) + + if response.status_code == 200: + #需要安装pip install lxml + soup = BeautifulSoup(response.text, "lxml") + + tables = soup.findAll('table', {'id':'info_block'}) + #print(tables) + if len(tables) != 0: + + #span获取有2个,一个为用户信息,一个为信箱信息 + info = tables[0].findAll('span', {'class':'medium'}) + if info == []: + #获取只有1个 + info = tables[0].findAll('span', {'class':'nowrap'}) + user_info = info[0] + else: + user_info = info[0] + + #print(user_info) + #print("-------------") + #用户详情链接 + user_info_link = user_info.a.attrs['href'] + #获取用户ID + user_id = parseUrl(user_info_link)['query'].get('id',[])[0] + #用户名 + user_name = user_info.a.get_text() + #个人页无分享率的情况 + try: + #分享率 + ratio = user_info.find('font',{'class':'color_ratio'}).nextSibling.get_text() + data['ratio'] = ratio + except: + data['ratio'] = '0' + + #print("user_info_link--->",user_info_link) + #print("user_id--->",user_id) + #print("user_name--->",user_name) + data['user_id'] = user_id + data['user_name'] = user_name + if user_id == []: + data['msg'] = "格式错误" + return False, data + + userdetails_url = site_url + "/userdetails.php?id=%s" % user_id + + response = session.get(userdetails_url, headers=headers, timeout=10) + + soup = BeautifulSoup(response.text, "lxml") + + tables = soup.findAll('table', {'class':'main'}, limit=2) + if len(tables) == 2: + user_table = tables[1]#.find('table') + else: + user_table = [] + + if user_table != []: + #print(user_table) + + for index, tr in enumerate(user_table.find_all('tr')): + + if index == 0: + continue + + #由于获取td后 标题内存在一个table,实际完整的一个是15个td,标题后面2个td废弃 + tds = tr.find_all('td') + #print(tds) + #if '用户ID' in tds[0].get_text(): + #data['user_id'] = tds[1].get_text() + data_key = tds[0].get_text().strip() + data_value = tds[1].get_text().strip() + #if ('邀请' in tds[0].get_text() and '邀请人' not in tds[0].get_text()) or ('邀請' in tds[0].get_text() and '邀請人' not in tds[0].get_text()): + #if RepresentsInt(tds[1].get_text()): + #data['invite'] = tds[1].get_text() + #else: + #data['invite'] = 0 + if '邀请' == data_key or '邀請' == data_key or '剩余邀请量' == data_key : + #print(data_value) + #删除非数字字符(获取字符串的整数) \D:表示非数字 + num = re.sub(r'\D+', '', data_value) + if RepresentsInt(num): + data['invite'] = num + else: + data['invite'] = 0 + + #data['invite'] = data_value + + #if '加入日期' in tds[0].get_text(): + ##替换括号和括号的内容为空 + #data['create_time'] = re.sub("\(.*\)",'',tds[1].get_text()) + if '加入日期' == data_key: + data['create_time'] = re.sub("\(.*\)",'', data_value) + + if '分享率' in tds[0].get_text(): + data['ratio'] = tds[0].font.get_text() + + if ('上传量' in tds[0].get_text() and '实际' not in tds[0].get_text()) or ('上傳量' in tds[0].get_text() and '實際' not in tds[0].get_text()): + data['upload'] = re.sub("\(.*\)",'',tds[0].get_text().split(':')[-1]) + data['download'] = re.sub("\(.*\)",'',tds[1].get_text().split(':')[-1]) + + #pttime + if '核心数据' == data_key: + data['ratio'] = tds[1].font.get_text() + #分隔4个连续空格['', '上传量: 21.367TB\n ', '下载量: 5.072TB', '魔力值: 6469.8'] + d =tds[1].font.nextSibling.get_text().split(u'\xa0\xa0\xa0\xa0') + data['upload'] = d[1].split(':')[-1].replace('\\n','').strip() + data['download'] = d[2].split(':')[-1].strip() + data['bonus'] = d[3].split(':')[-1].strip() + + if '等级' in tds[0].get_text() or '等級' in tds[0].get_text(): + data['level'] = re.sub("\(.*\)",'',tds[1].img.attrs['title']) + + #if '魔力值' in tds[0].get_text(): + #data['bonus'] = tds[1].get_text() + + if '魔力值' == data_key: + data['bonus'] = data_value + + if '做种积分' in tds[0].get_text(): + data['score'] = tds[1].get_text() + + if '发布种子' in tds[0].get_text() or '發布種子' in tds[0].get_text(): + if '个种子' in tds[1].get_text(): + #页面直接包含数据 + data['published_seed_num'] = tds[1].a.nextSibling.get_text().split(',')[0].replace('(','').replace('个种子','') + else: + url = getSiteUrl(site_url) + "/getusertorrentlistajax.php?userid=%s&type=uploaded" % data['user_id'] + response = session.get(url, headers=headers, timeout=10) + soup = BeautifulSoup(response.text, "lxml") + published_seed_num= soup.find('b') + if published_seed_num != None: + data['published_seed_num'] = published_seed_num.get_text() + else: + data['published_seed_num'] = 0 + + if '当前做种' in tds[0].get_text() or '目前做種' in tds[0].get_text(): + if '个种子' in tds[1].get_text(): + data['seed_num'] = tds[1].a.nextSibling.get_text().split(',')[0].replace('(','').replace('个种子','') + data['totle_seed_size'] = tds[1].a.nextSibling.get_text().split(',')[-1].replace('(','').replace('共计','') + else: + url = getSiteUrl(site_url) + "/getusertorrentlistajax.php?userid=%s&type=seeding" % data['user_id'] + response = session.get(url, headers=headers, timeout=10) + soup = BeautifulSoup(response.text, "lxml") + seed_num= soup.find('b') + if seed_num != None: + data['seed_num'] = seed_num.get_text() + data['totle_seed_size'] = seed_num.nextSibling.get_text().split(':')[-1] + #pttime + if '记录' in data['totle_seed_size']: + url = site_url + "/getusertorrentlist.php?userid=%s&type=seeding" % data['user_id'] + response = session.get(url, headers=headers, timeout=10) + soup = BeautifulSoup(response.text, "lxml") + tds = soup.findAll('td',{'id':'outer'}, limit=2) + #print(tds) + span = tds[1].find_all('span') + #print(span[1].get_text()) + data['totle_seed_size'] = span[2].get_text().split(':')[-1].replace(u'\xa0','') + else: + data['seed_num'] = 0 + data['totle_seed_size'] = 0 + return True, data + else: + data['msg'] = "格式错误" + return False, data + else: + data['msg'] = "格式错误" + return False, data + + else: + data['msg'] = "cookie过期" + + return False, data + + except: + data['msg'] = "无法登录" + + return False, data diff --git a/apps/common/utils.py b/apps/common/utils.py index 1e10887..b5ef139 100644 --- a/apps/common/utils.py +++ b/apps/common/utils.py @@ -28,6 +28,7 @@ from urllib import parse from wechatpy.enterprise import WeChatClient from PIL import Image, ImageDraw, ImageFont import re +import random logger = logging.getLogger('django') @@ -664,6 +665,7 @@ def parseUrl(url): """ 拆解url #scheme='https', netloc='127.0.0.1:8080', path='/', params='', query='', fragment='' + #{'protocol': '', 'url': '', 'host': '', 'port': None, 'path': 'userdetails.php', 'params': '', 'query': {'id': ['16465']}} """ data = {} u = urlparse(url) @@ -675,7 +677,8 @@ def parseUrl(url): data['port'] = u.port data['path'] = u.path data['params'] = u.params - data['query'] = u.query + #将查询字符串字典话 + data['query'] = parse.parse_qs(u.query) return data @@ -855,4 +858,21 @@ class EnWechat: else: msg = reponse['errmsg'] - return False, msg \ No newline at end of file + return False, msg + +def Unicode(): + """ + 随机产生汉字 + """ + val = random.randint(0x4e00, 0x9fbf) + return chr(val) + +def GBK2312(): + """ + 随机产生汉字 + """ + head = random.randint(0xb0, 0xf7) + body = random.randint(0xa1, 0xfe) + val = f'{head:x} {body:x}' + str = bytes.fromhex(val).decode('gb2312') + return str \ No newline at end of file diff --git a/apps/common/views_request.py b/apps/common/views_request.py index 613db3b..6eefce0 100644 --- a/apps/common/views_request.py +++ b/apps/common/views_request.py @@ -67,7 +67,7 @@ def backupImport(request): backup_file = os.path.join(settings.BACKUP_DIR,'pthelper.json') logger.info("Starting load process.") - call_command('loaddata', 'test_dump.json') + call_command('loaddata', backup_file) #================== diff --git a/apps/cron/crontabs.py b/apps/cron/crontabs.py index 2b289f4..72a5846 100644 --- a/apps/cron/crontabs.py +++ b/apps/cron/crontabs.py @@ -13,7 +13,8 @@ import qbittorrentapi from common.utils import send_email,send_telegram,send_iyuu, send_enwechat, parseUrl from common.sites_sign import signIngress -from sites.models import SiteConfig, SiteInfo +from common.sites_user import userIngress +from sites.models import SiteConfig, SiteInfo, SiteUser from .models import Job, Log from notify.models import NotifyConfig from rss.models import Rule, SeedInfo @@ -104,7 +105,10 @@ def my_scheduler(crontab_id=None, crontab_status=None, hour="*", minute="*", job scheduler.add_job(re_fail_sign, 'cron', hour=hour, minute=minute, id=crontab_id, args=[crontab_id]) elif jobtype_id == 1002: #RSS订阅 - scheduler.add_job(rss, 'cron', hour=hour, minute=minute, id=crontab_id, args=[crontab_id]) + scheduler.add_job(rss, 'cron', hour=hour, minute=minute, id=crontab_id, args=[crontab_id]) + elif jobtype_id == 1001: + #更新用户信息 + scheduler.add_job(getUserInfo, 'cron', hour=hour, minute=minute, id=crontab_id, args=[crontab_id]) else: #禁用状态,直接删除任务 @@ -127,7 +131,9 @@ def my_scheduler(crontab_id=None, crontab_status=None, hour="*", minute="*", job elif jobtype_id == 1003: scheduler.add_job(re_fail_sign, 'cron', hour=hour, minute=minute, id=crontab_id, args=[crontab_id]) elif jobtype_id == 1002: - scheduler.add_job(rss, 'cron', hour=hour, minute=minute, id=crontab_id, args=[crontab_id]) + scheduler.add_job(rss, 'cron', hour=hour, minute=minute, id=crontab_id, args=[crontab_id]) + elif jobtype_id == 1001: + scheduler.add_job(getUserInfo, 'cron', hour=hour, minute=minute, id=crontab_id, args=[crontab_id]) return True @@ -574,4 +580,69 @@ def seed_download(seedinfo_id): except Exception as e: print(e) - return \ No newline at end of file + return + + +def getUserInfo(crontab_id): + """ + 更新用户信息 + """ + + #保存最后发送的结果 + send_data = [] + count_siteinfo = SiteInfo.objects.count() + #未配置任何站点直接返回 + if count_siteinfo == 0: + return + + _TIME_FORMAT = "%Y-%m-%d %H:%M:%S" + + ormdata_siteinfo = SiteInfo.objects.all() + for i in ormdata_siteinfo: + #记录ID值 + site_id = i.id + site_name = i.siteconfig_name + site_cookie = i.cookie + site_name_cn = i.siteconfig_name_cn + #获取站点配置信息 + site_config = SiteConfig.objects.get(name=site_name) + site_url = site_config.index_url + site_sign_type = site_config.sign_type + + flag, data = userIngress(site_name, site_name_cn, site_url, site_cookie, site_sign_type) + if flag: + count_userinfo = SiteUser.objects.filter(siteinfo_id = site_id).count() + if count_userinfo == 0: + #无记录 + SiteUser.objects.create(siteinfo_id=i, + username = data['user_name'], + uid = int(data['user_id']), + invite = int(data['invite']), + create_time = datetime.datetime.strptime(data['create_time'].strip(), _TIME_FORMAT).strftime('%Y-%m-%d %H:%M:%S'), + ratio = data['ratio'].strip(), + upload = data['upload'].strip(), + download = data['download'].strip(), + bonus = data['bonus'], + score = data['score'], + level = data['level'], + published_seed_num = int(data['published_seed_num']), + seed_num = int(data['seed_num']), + totle_seed_size = data['totle_seed_size'] + ) + else: + #已经存在 + SiteUser.objects.filter(siteinfo_id=site_id).update(username = data['user_name'], + uid = int(data['user_id']), + invite = int(data['invite']), + ratio = data['ratio'].strip(), + upload = data['upload'].strip(), + download = data['download'].strip(), + bonus = data['bonus'], + score = data['score'], + level = data['level'], + published_seed_num = int(data['published_seed_num']), + seed_num = int(data['seed_num']), + totle_seed_size = data['totle_seed_size'] + ) + + return \ No newline at end of file diff --git a/apps/dashboard/templates/dashboard/dashboard.html b/apps/dashboard/templates/dashboard/dashboard.html index 1f54c88..a8e7674 100644 --- a/apps/dashboard/templates/dashboard/dashboard.html +++ b/apps/dashboard/templates/dashboard/dashboard.html @@ -122,62 +122,47 @@ -