def delete_like(article_info): """ :param article_info:{content_irl} :return: 删除搜藏 """ # 从喜欢列表中删除 col_like.delete(content_url=article_info['content_url']) # 将原始数据库的like记录改为FALSE col_data = CollectionOperation(article_info['nickname']) article_data = col_data.get(content_url=article_info['content_url'])[0] article_data['like_folder'] = False col_data.insert(key='content_url', data=article_data)
def run(self, command, cmd_args): from app.api.gzh import Finished from cmp.db.mongo import CollectionOperation for gzh in Finished().get()['finished']: col = CollectionOperation(gzh['nickname']) articles_buffer = [] for a in col.get(): if type(a['mov']) == str: a['mov'] = int(a['mov']) articles_buffer.append(a) col.insert('id', articles_buffer) logger.info('转化完成 %d %s'%(len(articles_buffer), gzh['nickname'])) command_log('转化完成 %d %s'%(len(articles_buffer), gzh['nickname']))
def add_like(article_info): """ :param article_info: {nickname, content_url} :return: 添加到搜藏 """ # 根据nickname和url从数据库中获得原始记录 col_data = CollectionOperation(article_info['nickname']) article_data = col_data.get(content_url=article_info['content_url'])[0] # 原始数据库中增加已经搜藏字段 article_data['like_folder'] = True col_data.insert(key='content_url', data=article_data) # 增加收藏时间 article_data['like_time'] = datetime.now() # 插入 "微搜收藏" res = col_like.insert(key='content_url', data=article_data)
class ReadingData(): def __init__(self): # 从数据源获取的请求参数 self.wx_req_data_list = rd.tidy() # 微信昵称 self.nickname = self.wx_req_data_list[0]['nickname'] # 同一个微信账号两次请求之间的时间间隔 self.every_delay = 3.0 # 参加采集微信的数量 self.wx_num = len(self.wx_req_data_list) # 多个微信账号的情况下时间间隔 self.delay = round(self.every_delay/self.wx_num, 3) # 所有需要采集的文章 self.articles = [] # 数据库操作 self.col_data = CollectionOperation(self.nickname) # 上一次请求时间 self.pre_crawl_time = time.time() def get_all_reading_data(self, process=None, mov=10): """ :param mov: 10~17 :return: 轮流调用wx_req_data_list中的微信参数 采集文章的阅读数据 """ # 获取所有需要采集的文章url # 将url等参数传递给新建的爬虫对象 # 保存数据 if 'getappmsgext' in self.wx_req_data_list[0]: # 从书库库获取需要采集的文章列表 # raw_articles = self.col_data.get(read_num={"$exists": False}) # 选中没有阅读数据且位置低于mov的文章来采集阅读数据 raw_articles = self.col_data.table.find({"$and":[ {"read_num":{"$exists": False}}, {"mov":{"$lte": int(mov)}}]}) # 采集阅读数据需要较长时间 防止长时间占用数据库游标 缓存需要采集的文章列表 cnt = 0 for a in raw_articles: # [cnt, url, comment_id] if "mp.weixin.qq.com" in a['content_url']: # 在采集文章正文之前采集阅读数据 这时 并没有comment_id if 'comment_id' not in a: a['comment_id'] = 0 self.articles.append([cnt, a['content_url'], a['comment_id']]) cnt += 1 # 一个一个开始采集 for itme in self.articles: while time.time()-self.pre_crawl_time <= self.delay: time.sleep(0.05) self.pre_crawl_time = time.time() reading_data = Crawler(itme[1], itme[2], self.wx_req_data_list[itme[0]%self.wx_num]).run() # 开始安检 使用安检之后的数据 因为它一定是合格的数据 reading_data = self.check(reading_data, itme) # 安检通过 reading_data['id'] = get_md5(itme[1]) self.col_data.insert('id', reading_data) # 发送进度数据给前端 process.new_reading_data(itme[0]+1, len(self.articles), self.delay) # 使用多线程 同时采集所有的文章 测试证明不可行 容易被限制 # from cmp.mt import run_mt # run_mt(len(self.articles), self.prepare_task, self.task_handler) else: logger.warning('点击查看该公众号的任意一篇文章且出现阅读量') def save(self, reading_data): """ :param reading_data: :return: 保存数据 """ pass def prepare_task(self): """ :return: 多线程的方式准备任务 """ for item in self.articles: yield {'index':item[0], 'url':item[1]} def task_handler(self, task): """ :return: 多线程的方式任务处理器 """ Crawler(task['url'], self.wx_req_data_list[task['index']%self.wx_num]).run() def check(self, reading_data, item): """ :return: 带着本次请求的参数和结果一起过安检 请求失败导致安检不通过 安检提醒人重新操作手机 操作完之后再次发起请求 不排除还是会失败 继续调用自己 反正想办法让其获得成功的请求 最后返回成功的请求 """ if reading_data != 'req_data_error': stop_and_start.check({'crawler': '阅读数据', 'msg': 'success'}) else: # 先过安检 安检会提醒更新参数 stop_and_start.check({'crawler': '阅读数据', 'msg': 'req_data_error'}) # 参数更新完毕 从数据源读取参数 继续请求 self.wx_req_data_list = rd.tidy() # 参数有可能被用户删除了 循环检查 while len(self.wx_req_data_list) == 0: self.wx_req_data_list = rd.tidy() from utils.front import notification notification('没有发现参数','参数错误',_type='error') time.sleep(3) reading_data = Crawler(item[1], item[2], self.wx_req_data_list[0]).run() # 继续安检 self.check(reading_data, item) return reading_data
class AricleList: """ 优雅地拿下一个公众号的全部历史文章列表 如果有必要直接调用自动操作手机的方法 采集完毕之后结束对象的生命周期 """ def __init__(self): self.wx_req_data_list = rd.tidy() self.nickname = self.wx_req_data_list[0]['nickname'] self.every_delay = 2.0 self.wx_num = len(self.wx_req_data_list) self.delay = round(self.every_delay / self.wx_num, 3) self.article_num = 0 self.all_article_num = 0 self.current_article_list = [] self.col_data = CollectionOperation(self.nickname) self.pre_crawl_time = time.time() def get_all_article_list(self, filter=None, process=None): """ :param filter: 过滤器比如按照时间过滤 按照数量过滤 :param process: 前端进度显示实例 :return: 轮流调用list中的微信 获取所有的历史文章列表 """ offset = 0 can_msg_continue = 1 cnt = 0 if 'load_more' in self.wx_req_data_list[0]: while can_msg_continue: while time.time() - self.pre_crawl_time <= self.delay: time.sleep(0.05) self.pre_crawl_time = time.time() list_data = Crawler( offset, self.wx_req_data_list[cnt % self.wx_num]).run() list_data = self.check(list_data, offset, cnt) can_msg_continue = int(list_data['des']['can_msg_continue']) offset = int(list_data['des']['next_offset']) cnt += 1 self.current_article_list = list_data['data'] self.article_num += len(self.current_article_list) filter_res = self.filter_check(filter) self.all_article_num += len(self.current_article_list) col_crawler_log.insert( 'id', { 'id': self.nickname, 'num': self.all_article_num, 'nickname': self.nickname, 'time': datetime.now() }) process.new_article_list(self.all_article_num) if self.save(self.current_article_list) == 'UPDATE': break if not filter_res: break time.sleep(self.delay) else: logger.warning('没有上滑加载更多历史文章') def save(self, list_data): """ :return: 保存数据 """ res = None res = self.col_data.insert('id', list_data) return res def filter_check(self, filter): """ :param filter: :return: 根据过滤器中的条件 决定继续还是结束文章列表的采集 True继续 false停止 """ if filter['type'] == 'true': if int(filter['num']) == 0: return True if self.article_num >= int(filter['num']): return False return True else: use_article_list = [] res = True for a in self.current_article_list: p_date_timestamp = a['p_date'].timestamp() if p_date_timestamp >= filter[ 'start_time'] and p_date_timestamp <= filter[ 'end_time']: use_article_list.append(a) elif p_date_timestamp < filter['start_time']: res = False self.current_article_list = use_article_list return res def check(self, list_data, offset, cnt): """ :param list_data: 请求返回的结果 :param offset: :return: 带着本次请求的参数和结果一起过安检 请求失败导致安检不通过 安检提醒人重新操作手机 操作完之后再次发起请求 不排除还是会失败 继续调用自己 """ if list_data != 'req_data_error': stop_and_start.check({'crawler': '历史文章列表', 'msg': 'success'}) else: stop_and_start.check({ 'crawler': '历史文章列表', 'msg': 'req_data_error' }) self.wx_req_data_list = rd.tidy() while len(self.wx_req_data_list) == 0: self.wx_req_data_list = rd.tidy() from utils.front import notification notification('没有发现参数', '参数错误', _type='error') time.sleep(3) list_data = Crawler(offset, self.wx_req_data_list[0]).run() self.check(list_data, offset, cnt) return list_data
class AricleList(): """ 优雅地拿下一个公众号的全部历史文章列表 如果有必要直接调用自动操作手机的方法 采集完毕之后结束对象的生命周期 """ def __init__(self): # 从数据源获取的请求参数 self.wx_req_data_list = rd.tidy() # 微信昵称 self.nickname = self.wx_req_data_list[0]['nickname'] # 同一个微信账号两次请求之间的时间间隔 self.every_delay = 2.0 # 参加采集微信的数量 self.wx_num = len(self.wx_req_data_list) # 多个微信账号的情况下时间间隔 self.delay = round(self.every_delay/self.wx_num, 3) # 已经采集文章的数量 self.article_num = 0 # 所有已经采集的文章数 self.all_article_num = 0 # 当前的列表 self.current_article_list = [] # 数据库操作 self.col_data = CollectionOperation(self.nickname) # 上一次请求时间 self.pre_crawl_time = time.time() def get_all_article_list(self, filter=None,process=None): """ :param filter: 过滤器比如按照时间过滤 按照数量过滤 :param process: 前端进度显示实例 :return: 轮流调用list中的微信 获取所有的历史文章列表 """ offset = 0 can_msg_continue = 1 cnt = 0 if 'load_more' in self.wx_req_data_list[0]: while can_msg_continue: while time.time()-self.pre_crawl_time <= self.delay: time.sleep(0.05) self.pre_crawl_time = time.time() list_data = Crawler(offset, self.wx_req_data_list[cnt%self.wx_num]).run() # 安检开始 不合格会卡住 使用安检之后的数据 因为它一定是合格的数据 list_data = self.check(list_data, offset, cnt) # 安检通过进行后续处理 can_msg_continue = int(list_data['des']['can_msg_continue']) offset = int(list_data['des']['next_offset']) cnt += 1 self.current_article_list = list_data['data'] self.article_num += len(self.current_article_list) filter_res = self.filter_check(filter) self.all_article_num += len(self.current_article_list) # 写入文章采集日志 col_crawler_log.insert('id', {'id': self.nickname, 'num': self.all_article_num, 'nickname': self.nickname, 'time': datetime.now()}) # 保存数据 process.new_article_list(self.all_article_num) if self.save(self.current_article_list) == 'UPDATE': break # 不符合过滤器条件结束 if not filter_res: break # 过滤器检查 time.sleep(self.delay) else: logger.warning('没有上滑加载更多历史文章') def save(self, list_data): """ :return: 保存数据 """ res = None res = self.col_data.insert('id', list_data) return res def filter_check(self, filter): """ :param filter: :return: 根据过滤器中的条件 决定继续还是结束文章列表的采集 True继续 false停止 """ # 按照量控制采集 if filter['type'] == 'true': # 0表示采集全部文章 if int(filter['num'])==0: return True # 文章数已经超过过滤器设置的数量 if self.article_num >= int(filter['num']): return False # 文章数还没达到过滤器的设定值 else: return True # 按照时间控制 else: use_article_list = [] res = True # 根据日期删除部分文章 for a in self.current_article_list: p_date_timestamp = a['p_date'].timestamp() # 小于开始时间丢掉 继续 # if p_date_timestamp<filter['start_time']: # pass # 介于之间 保留继续 if (p_date_timestamp>=filter['start_time']) and (p_date_timestamp<=filter['end_time']): use_article_list.append(a) # 大于结束时间 停止 elif p_date_timestamp<filter['start_time']: res = False self.current_article_list = use_article_list return res def check(self, list_data, offset, cnt): """ :param list_data: 请求返回的结果 :param offset: :return: 带着本次请求的参数和结果一起过安检 请求失败导致安检不通过 安检提醒人重新操作手机 操作完之后再次发起请求 不排除还是会失败 继续调用自己 """ if list_data != 'req_data_error': stop_and_start.check({'crawler': '历史文章列表', 'msg': 'success'}) else: # 先过安检 安检会提醒更新参数 stop_and_start.check({'crawler': '历史文章列表', 'msg': 'req_data_error'}) # 参数更新完毕 从数据源读取参数 继续请求 self.wx_req_data_list = rd.tidy() # 参数有可能被用户删除了 循环检查 while len(self.wx_req_data_list) == 0: self.wx_req_data_list = rd.tidy() from utils.front import notification notification('没有发现参数','参数错误',_type='error') time.sleep(3) list_data = Crawler(offset, self.wx_req_data_list[0]).run() # 继续安检 self.check(list_data, offset, cnt) return list_data
class ReadingData: def __init__(self): self.wx_req_data_list = rd.tidy() self.nickname = self.wx_req_data_list[0]['nickname'] self.every_delay = 3.0 self.wx_num = len(self.wx_req_data_list) self.delay = round(self.every_delay / self.wx_num, 3) self.articles = [] self.col_data = CollectionOperation(self.nickname) self.pre_crawl_time = time.time() def get_all_reading_data(self, filter=None, process=None): """ :param filter: :return: 轮流调用wx_req_data_list中的微信参数 采集文章的阅读数据 """ if 'getappmsgext' in self.wx_req_data_list[0]: raw_articles = self.col_data.get(read_num={'$exists': False}) cnt = 0 for a in raw_articles: if 'mp.weixin.qq.com' in a['content_url']: if 'comment_id' not in a: a['comment_id'] = 0 self.articles.append( [cnt, a['content_url'], a['comment_id']]) cnt += 1 for itme in self.articles: while time.time() - self.pre_crawl_time <= self.delay: time.sleep(0.05) self.pre_crawl_time = time.time() reading_data = Crawler( itme[1], itme[2], self.wx_req_data_list[itme[0] % self.wx_num]).run() reading_data = self.check(reading_data, itme) reading_data['id'] = get_md5(itme[1]) self.col_data.insert('id', reading_data) process.new_reading_data(itme[0] + 1, len(self.articles), self.delay) else: logger.warning('点击查看该公众号的任意一篇文章且出现阅读量') def save(self, reading_data): """ :param reading_data: :return: 保存数据 """ pass def prepare_task(self): """ :return: 多线程的方式准备任务 """ for item in self.articles: yield {'index': item[0], 'url': item[1]} def task_handler(self, task): """ :return: 多线程的方式任务处理器 """ Crawler(task['url'], self.wx_req_data_list[task['index'] % self.wx_num]).run() def check(self, reading_data, item): """ :return: 带着本次请求的参数和结果一起过安检 请求失败导致安检不通过 安检提醒人重新操作手机 操作完之后再次发起请求 不排除还是会失败 继续调用自己 反正想办法让其获得成功的请求 最后返回成功的请求 """ if reading_data != 'req_data_error': stop_and_start.check({'crawler': '阅读数据', 'msg': 'success'}) else: stop_and_start.check({'crawler': '阅读数据', 'msg': 'req_data_error'}) self.wx_req_data_list = rd.tidy() while len(self.wx_req_data_list) == 0: self.wx_req_data_list = rd.tidy() from utils.front import notification notification('没有发现参数', '参数错误', _type='error') time.sleep(3) reading_data = Crawler(item[1], item[2], self.wx_req_data_list[0]).run() self.check(reading_data, item) return reading_data