class API: def __init__(self): self.rankdb = MongoDB('Javdb', 'rankdb') @app.route('/<identity>', methods=['GET', 'POST']) def identity(self, identity=None): return str(self.rankdb.find({'identity': identity}))
class API(object): ''' 口袋48 api : func searchroom: 查找指定成员房间信息 : func login: 登录 : func chatroom: 查询房间消息 : func livedetail: 获取直播详情 ''' def __init__(self, mobile, password, membername): ''' :param mobile: 电话 int or string :param password: 密码 string :param membername: 成员全名 string ''' self.mobile = mobile self.password = password self.membername = membername self.dbtoken = MongoDB('Pocket48', 'dbtoken') self.headers = { 'Host': 'pocketapi.48.cn', 'accept': '*/*', 'Accept-Language': 'zh-Hans-CN;q=1', 'User-Agent': 'PocketFans201807/6.0.0 (iPhone; iOS 12.2; Scale/2.00)', 'Accept-Encoding': 'gzip, deflate', 'appInfo': '{"vendor":"apple","deviceId":"0", \ "appVersion":"6.0.0","appBuild":"190409", \ "osVersion":"12.2.0","osType":"ios", \ "deviceName":"iphone","os":"ios"}', 'Content-Type': 'application/json;charset=utf-8', 'Connection': 'keep-alive', } dic_data = self.searchroom self.ownerId, self.roomId = dic_data['ownerId'], dic_data['roomId'] @property def _token(self): ''' 获取token,超过1天则重新登录 : return: token string ''' hastoken = list(self.dbtoken.find({'mobile': self.mobile})) if not hastoken: token = self.login self.dbtoken.update(dict(timestamp=self._nowtime, token=token, mobile=self.mobile), upsert=True) elif self._nowtime - hastoken[0]['timestamp'] > 3600 * 24: self.dbtoken.remove({'mobile': self.mobile}) token = self.login self.dbtoken.update(dict(timestamp=self._nowtime, token=token, mobile=self.mobile), upsert=True) return list(self.dbtoken.find({'mobile': self.mobile}))[0]['token'] @property def _nowtime(self): ''' 当前时间戳 : return: 当前时间戳 float ''' return time.time() @property def searchroom(self): ''' 获取成员房间信息 : param membername: 成员全名 : return: 成员房间信息 json roomName 房间名, ownerName 成员名, roomId 房间名, ownerId 成员编号 ''' url = 'https://pocketapi.48.cn/im/api/v1/im/search' data = {'name': self.membername} try: response = requests.post(url, json=data, headers=self.headers, verify=False).json()['content']['data'][0] return dict(roomName=response['targetName'], ownerName=response['ownerName'], ownerId=response['ownerId'], roomId=response['targetId']) except Exception as e: raise e @property def login(self): ''' 登录 : param mobile: 手机号 : param password: 密码 : return token: 登录token string ''' try: url = 'https://pocketapi.48.cn/user/api/v1/login/app/mobile' data = { "pwd": str(self.password), "mobile": str(self.mobile), } res = requests.post(url, headers=self.headers, json=data, verify=False).json() return res['content']['token'] except Exception as e: raise e @property def chatroom(self): ''' 获取成员房间消息 : param roomId: 房间编号 : param ownerId: 成员编号 : return: 发言信息 json ''' url = 'https://pocketapi.48.cn/im/api/v1/chatroom/msg/list/homeowner' headers = self.headers headers.update({'token': self._token}) data = dict(needTop1Msg=False, roomId=str(self.roomId), ownerId=str(self.ownerId)) try: res = requests.post(url, headers=headers, json=data).json()['content']['message'] return res except Exception as e: raise e def livedetail(self, liveId): ''' 获取直播详情 :param liveId: 直播编号 int :return: playStreamPath string, response ''' url = "https://pocketapi.48.cn/live/api/v1/live/getLiveOne" form = {"liveId": str(liveId)} try: response = requests.post(url, json=form, headers=self.headers).json() if response['status'] == 200: playStreamPath = response['content']['playStreamPath'] return playStreamPath, response else: return False, False except BaseException: return False, False
class JavLib(object): def __init__(self): self.cookie = '' self.url = 'http://www.p26y.com/cn/' self.torrent_url = 'https://www.bturl.at/search/' self.video = {} self.headers = {'Cookie': self.cookie, 'Host': 'www.p26y.com', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,' '*/*;q=0.8', 'User-Agent': 'Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, ' 'like Gecko) Chrome/68.0.3440.75 Safari/537.36', 'If-None-Match': 'W/"3a18de34b39581014d560cc3522a80b7"', 'If-Modified-Since': 'Tue, 22 Jan 2019 00:00:00 GMT', 'Connection': 'keep-alive', 'Cache-Control': 'max-age=0', 'Accept-Language': 'zh-CN,zh;q=0.9', 'Upgrade-Insecure-Requests': '1', 'Accept-Encoding': 'gzip, deflate' } self.allgirls = MongoDB('Javdb', 'girlsname') # 所有girl名称—>页面编码键值对 self.rankdb = MongoDB('Javdb', 'rankdb') # 最受受欢迎作品榜单 self.girlsindexdb = MongoDB('Javdb', 'girlsindexdb') # 单个girl的所有作品db def get_cookie(self, now_url): """ 刷新页面cookie,存入self.cookie :now_url:需获取cookie的url """ self.cookie = '' chrome_options = Options() chrome_options.add_argument('--headless') browser = webdriver.Chrome(options=chrome_options) browser.implicitly_wait(30) browser.set_page_load_timeout(30) browser.get(now_url) time.sleep(10) for keys in browser.get_cookies(): self.cookie += '='.join([keys['name'], keys['value']]) + '; ' browser.close() self.headers['cookie'] = self.cookie @retry def torrent(self, identity): """ 根据番号identity获取磁力链接,按照标准格式存入self.video,单独使用时缺少title和score :identity:作品番号 """ torrent_url = parse.urljoin(self.torrent_url, identity + '_ctime_1.html') print(torrent_url) resp = requests.get(torrent_url, verify=False) soup = BeautifulSoup(resp.content, 'lxml') tags = soup.find_all('li') dic_torrent = {} dic_torrent[identity] = [] for tag in tags: dic_torrent[identity].append({'torrent_name': tag.a.text.strip(), 'torrent_href': tag.a['href'][1:-5], 'torrent_time': tag.span.text, 'torrent_memory': tag.find_all('span', limit=2)[1].text }) return dic_torrent @retry def spider(self, now_url): """ 作品页爬虫,调用soup_video获得作品信息 :now_url:作品页地址 """ resp = requests.get(now_url, headers=self.headers, verify=False) self.soup_spider(resp) @retry def allgirls_spider(self, url): """ 演员名录页爬虫 """ print(url) resp = requests.get(url, headers=self.headers) soup = BeautifulSoup(resp.content, 'lxml') searchitem = soup.find_all('div', class_='searchitem') for girl in searchitem: print(girl.a.text, girl['id'], self.allgirls.update({'girls': girl.a.text, 'code': girl['id']}, upsert=True)) if soup.find_all('a', class_='page next'): next_page = soup.find_all('a', class_='page next')[0]['href'] next_url = parse.urljoin(self.url, next_page) self.allgirls_spider(next_url) else: return 0 def soup_spider(self, resp): """ 作品页面解析,得到评分,题目,番号,存入self.video :param resp: 作品页response :return:返回identity, score, title """ soup = BeautifulSoup(resp.content, 'lxml') tags = soup.find_all('tr') for tag in tags: try: score = tag.find_all('td')[1].text title = tag.td.find_all('a')[-1]['title'] except: continue print(title) identity = title.split(' ')[0] self.video[identity] = {'score': score, 'title': title} @retry def soup_girlindex(self, url, girl): """ 单个girl的作品目录解析,得到文章数,评论数,番号,标题,存入girlsindexdb :param url:girl作品目录的url :return:存入girlsindexdb """ resp = requests.get(url, headers=self.headers, verify=False) soup = BeautifulSoup(resp.content, 'html.parser') tags = soup.find_all('tr') thread_list = [] for tag in tags: thread = MyThread(self.thread_grilindex, args=(tag, girl,)) thread.start() thread_list.append(thread) for thread in thread_list: thread.join() if soup.find_all('a', class_='page next'): next_page = soup.find_all('a', class_='page next')[0]['href'] next_url = parse.urljoin(self.url, next_page) self.soup_girlindex(next_url, girl) else: return 0 def thread_grilindex(self, tag, girl): try: date, article, replies = [i.text for i in tag.find_all('td')[1:]] article = int(article) replies = int(replies) title = tag.td.find_all('a')[-1]['title'] except: return print(title) identity = title.split(' ')[0] dic_torrent = self.torrent(identity) for torrent in dic_torrent[identity]: torrent_name = torrent['torrent_name'] torrent_href = torrent['torrent_href'] torrent_time = torrent['torrent_time'] torrent_memory = torrent['torrent_memory'] self.girlsindexdb.update({'girl': girl, 'title': title, 'date': date, 'article': article, 'replies': replies, 'torrent_name': torrent_name, 'torrent_href': torrent_href, 'torrent_memory': torrent_memory, 'torrent_time': torrent_time }, upsert=True) def rank(self, mode='bestrated'): """ 获取排行榜作品 """ dic_mode = {'bestrated': 'http://www.p26y.com/cn/vl_bestrated.php?list&page={}', 'mostwanted': 'vl_mostwanted.php?list&page={}'} # 最高评价,最受期待 real_url = parse.urljoin(self.url, dic_mode[mode]) self.get_cookie(self.url) for pages in range(1, 11): # 获取排行榜前10页作品信息 now_url = real_url.format(pages) self.spider(now_url) thread_list = [] for identity in self.video: # 根据番号查找磁力链接 thread = MyThread(self.torrent, args=(identity,)) thread.start() thread_list.append(thread) dic_torrent = {} for thread in thread_list: thread.join() dic_torrent.update(thread.get_result()) for identity in self.video: # 存入数据库self.allgirls for torrent in dic_torrent[identity]: torrent_name = torrent['torrent_name'] torrent_href = torrent['torrent_href'] torrent_time = torrent['torrent_time'] torrent_memory = torrent['torrent_memory'] print(torrent_name, torrent_href) self.rankdb.update({'identity': identity, 'title': self.video[identity]['title'], 'score': self.video[identity]['score'], 'torrent_name': torrent_name, 'torrent_href': torrent_href, 'torrent_time': torrent_time, 'torrent_memory': torrent_memory}, True) def girlindex(self, girl): """ 爬指定girl的所有作品,存入数据库self.girlsindexdb :return: """ self.girlcode = [girls['code'] for girls in self.allgirls.find({'girls': girl})] for code in self.girlcode: url = 'http://www.p26y.com/cn/vl_star.php?list&s={}'.format(code) self.get_cookie(url) self.soup_girlindex(url, girl) def allgirls(self): """ 更新演员名录,存入数据库db['Javdb']['girlsname'],仅用于更新名录 """ url_name = parse.urljoin(self.url, 'star_list.php?prefix={}&page=1') alphabet = list(string.ascii_uppercase) for character in alphabet: url = url_name.format(character) self.get_cookie(url) self.allgirls_spider(url) return 0 def write_down(self, data, filename='javlib'): """ 将数据(字典列表)输出到excel """ df = pd.DataFrame(data) df.to_excel('{}.xlsx'.format(filename), index=True)
class API(object): ''' 口袋48 api : func searchroom: 查找指定成员房间信息 : func login: 登录 : func chatroom: 查询房间消息 : func livedetail: 获取直播详情 ''' def __init__(self): ''' :param mobile: 电话 int or string :param password: 密码 string :param membername: 成员列表 string ''' self.color = ['#FEEEED', '##CCFFFF', '#CCFFCC', '#E0FFFF', '#F0FFF0', '#F0F8FF', '#FFF0F5', '#FFFAFA', '#F0FFFF', '#FFF5EE', '#E6E6FA', '#FFC0CB'] self.dbtoken = MongoDB('Pocket48', 'dbtoken') self.key = b'1O8zgva3PlT_Evikm61A97wsWZ0JlTGSNEiRc0S7rCY=' self.Fernet = Fernet(self.key) self.source_url = 'https://source.48.cn' self.headers = { 'Host': 'pocketapi.48.cn', 'accept': '*/*', 'Accept-Language': 'zh-Hans-CN;q=1', 'User-Agent': 'PocketFans201807/6.0.0 (iPhone; iOS 12.2; Scale/2.00)', 'Accept-Encoding': 'gzip, deflate', 'appInfo': '{"vendor":"apple","deviceId":"0", \ "appVersion":"6.0.0","appBuild":"190409", \ "osVersion":"12.2.0","osType":"ios", \ "deviceName":"iphone","os":"ios"}', 'Content-Type': 'application/json;charset=utf-8', 'Connection': 'keep-alive', } def token(self, token): ''' 验证token : return: token string ''' hastoken = list(self.dbtoken.find({'token': token}, projection={'_id': 0})) if not hastoken: return False elif self._nowtime - hastoken[0]['timestamp'] > 3600 * 24 * 7: self.dbtoken.remove({'token': token}) return False else: return hastoken[0] @property def _nowtime(self): ''' 当前时间戳 : return: 当前时间戳 float ''' return time.time() def addmember(self, name, token): ''' 添加成员 : param name: 成员全名 : param token: token : return: token及附带的信息 response_object json ''' url = 'https://pocketapi.48.cn/im/api/v1/im/search' data = { 'name': name } try: response = requests.post(url, json=data, headers=self.headers, verify=False).json()['content']['data'][0] temp = dict(roomName=response['targetName'], ownerName=response['ownerName'], ownerId=response['ownerId'], roomId=response['targetId'], color=random.choice(self.color), icon=self.source_url+response['icon'][0]) self.dbtoken.update({'token': token}, {'$addToSet': {'member': temp}}, upsert=True) return list(self.dbtoken.find({'token': token}, projection={'_id': 0}))[0] except Exception as e: raise e def removemember(self, roomId, token): ''' 删除成员 : param roomId: : param token: : return: ''' try: self.dbtoken.update({'token': token}, {'$pull': {'member':{'roomId':roomId}}}) return list(self.dbtoken.find({'token': token}, projection={'_id': 0}))[0] except Exception as e: raise e def removetoken(self, token): ''' 删除token : param roomId: : param token: : return: ''' try: self.dbtoken.remove({'token': token}) return True except Exception as e: raise e def login(self, mobile, password): ''' 登录 : param mobile: 手机号 : param password: 密码 : return token: 登录token string ''' try: token = str(mobile) hastoken = list(self.dbtoken.find({'token': token}, projection={'_id': 0})) if not hastoken: url = 'https://pocketapi.48.cn/user/api/v1/login/app/mobile' data = { "pwd": str(password), "mobile": str(mobile), } res = requests.post( url, headers=self.headers, json=data, verify=False).json()['content'] token48 = res['token'] nickname = res['userInfo']['nickname'] avatar = self.source_url + res['userInfo']['avatar'] temp = dict(token48=token48, token=str(mobile), member=[], timestamp=self._nowtime, avatar=avatar, nickname=nickname) self.dbtoken.update(temp, {'$set': temp}, upsert=True) return temp else: return hastoken[0] except Exception as e: raise e def chatroom(self, token): ''' 获取成员房间消息 : param roomId: 房间编号 : param ownerId: 成员编号 : return: 发言信息 json ''' url = 'https://pocketapi.48.cn/im/api/v1/chatroom/msg/list/homeowner' headers = self.headers res = list(self.dbtoken.find({'token': token}))[0] token48 = res['token48'] list_member = res['member'] if not list_member: return list_member headers.update({'token': token48}) return_data = [] for member in list_member: data = dict( needTop1Msg=False, roomId=str( member['roomId']), ownerId=str( member['ownerId'])) try: res = requests.post(url, headers=headers, json=data).json()[ 'content']['message'] color = member['color'] return_data.append({'color': color, 'res': res}) except Exception as e: raise e return return_data def livedetail(self, liveId): ''' 获取直播详情 :param liveId: 直播编号 int :return: playStreamPath string, response ''' url = "https://pocketapi.48.cn/live/api/v1/live/getLiveOne" form = { "liveId": str(liveId) } try: response = requests.post( url, json=form, headers=self.headers).json() if response['status'] == 200: playStreamPath = response['content']['playStreamPath'] return playStreamPath, response else: return False, False except BaseException: return False, False def encrypt(self, string): ''' 加密 :param string: :return: 加密字符串 ''' token = self.Fernet.encrypt(string.encode()).decode() return token def decrypt(self, token): ''' 解密 :param token: :return: 原文 ''' string = self.Fernet.decrypt(token.encode()).decode() return string