diff --git a/send_msg_with_mongo.py b/send_msg_with_mongo.py new file mode 100644 index 0000000..d7d3118 --- /dev/null +++ b/send_msg_with_mongo.py @@ -0,0 +1,119 @@ +import datetime +import time +from wxpy import * +from pymongo import MongoClient +from pymongo.collection import Collection +from xianyu import return_result, loop_reply +import threading +client = MongoClient() # 里面什么都不填的话, 默认localhost, 27017 +killer_test = client['killer_test'] +config_list = Collection(killer_test, 'config_list') + +bot = Bot(cache_path = True) +print('Welcom to Killer\'s World') +friend_list = bot.friends() +# 这里配置我们想要什么信息 +# msg.text.startswith('搜索关键词:') 这个写在判断语句里, 也是我们想要的信息 +WORD_DICT = { + 'keyword': ['配置信息', '配置', '1', '2'] +} + + +@bot.register(friend_list, TEXT) +def auto_reply(msg): + print(msg.text) + if msg.text in WORD_DICT['keyword'] or msg.text.startswith('搜索关键词:'): + # 如果用户输入 '配置信息' 或者 '配置' + if msg.text == '配置信息' or msg.text == "配置": + print(msg.sender.name,':', msg.text, 'MSG_TYPE:', msg.type) + return '请按格式回复你的配置信息,格式如下,请把内容替换成你的内容:\n搜索关键词:麻瓜编程、自动办公、实用主义学Python' + + # 如果用户输入的以搜索关键词:开头的储存进数据库 + if msg.text.startswith('搜索关键词:') and len(msg.text.strip()) > 6: + print(msg.text) + config = {} + config['is_sure'] = 0 + config['user_name'] = msg.sender.name + config['query_list'] = [i.strip() for i in msg.text.lstrip('搜索关键词:').split('、') if len(i.strip())>0] + if len(config['query_list']) == 0: + return '请按格式回复你的配置信息,格式如下,请把内容替换成你的内容:\n搜索关键词:麻瓜编程、自动办公、实用主义学Python' + config['is_crawled'] = False + config['crawled_time'] = None + + # 这里应该添加一个判断, 就比如用户 输入了两遍 搜索关键词:麻瓜编程、自动办公、实用主义学Python + # 搜索关键词:麻瓜编程、自动办公、实用主义学Python + # 如果数据库里有这个用户配置的信息 就让用户回复1 和 2 否则就插入数据库 + print(config) + # 我们先插数据库里是否有这个用户的设置记录, 若果有就让他按 2 清除 + user = config_list.find_one({'user_name':msg.sender.name, 'is_sure': 1, 'is_crawled': True}) + if user is not None: + return f'你之前提交过配置 配置的信息如下:\n搜索关键词:{"、".join(user["query_list"])}\n如需修改请回复 2' + # else 证明数据库里没有这个用户的爬取数据 则判断用户是否已经设置过一次 + else: + user = config_list.find_one({'user_name':msg.sender.name, 'is_sure': 0, 'is_crawled': False}) + if user is not None: + # if len(user) > 0 : + return f'你之前提交过配置 配置的信息如下:\n搜索关键词:{"、".join(user["query_list"])}\n确认请回复 1\n如需修改请回复 2' + else: + config_list.insert(config) + + return f'你配置的信息如下:\n {msg.text}\n确认请回复 1\n如需修改请回复 2' + + + # 如果用户会回复的是1 就说明要 确认 搜索关键词 + if msg.text == '1': + user = config_list.find_one({'user_name':msg.sender.name, 'is_sure': 1, 'is_crawled': True}) + if user is not None: + return f'你之前提交过配置 配置的信息如下:\n搜索关键词:{"、".join(user["query_list"])}\n如需重新配置请回复 2' + # else 证明数据库里没有这个用户的爬取数据 则判断用户是否已经设置过一次 + else: + user = config_list.find_one({'user_name':msg.sender.name, 'is_sure': 0, 'is_crawled': False}) + if user is not None: + print('找到了该用户%s' %msg.sender.name) + config_list.update({'user_name':msg.sender.name, 'is_sure': 0, 'is_crawled': False}, {'$set': {'is_sure': 1}}) + msg.reply('配置成功,请稍后') + return_result(user, msg, config_list) + else: + return '你还没有配置\n请按格式回复你的配置信息,格式如下,请把内容替换成你的内容:\n搜索关键词:麻瓜编程、自动办公、实用主义学Python' + + # 如果用户输入的是2 就要删除数据库中的记录 可以做逻辑删除, 我这里直接物理删除了 + if msg.text == '2': + user = config_list.find_one({'user_name':msg.sender.name}) + if user is not None: + config_list.remove({'user_name':msg.sender.name}) + return '请按格式回复你的配置信息,格式如下,请把内容替换成你的内容:\n搜索关键词:麻瓜编程、自动办公、实用主义学Python' + else: + return '你还没有配置\n请按格式回复你的配置信息,格式如下,请把内容替换成你的内容:\n搜索关键词:麻瓜编程、自动办公、实用主义学Python' + # 如果输入的文本 不在 WORD_DICT 中或者 不是以搜索关键词:开头的话 + # 这里如果是自己的微信号的话 建议注释掉。。。。 + # else: + # return '少侠你又调皮了 配置信息有误\n请按格式回复你的配置信息,格式如下,请把内容替换成你的内容:\n搜索关键词:麻瓜编程、自动办公、实用主义学Python' + + +# 自动添加好友并回复 我是盗版杀手机器人,请通过回复 "配置" 来配置你的信息 +@bot.register(msg_types=FRIENDS) +def auto_accept_friends(msg): + # 接受好友请求 + new_friend = msg.card.accept() + # 向新的好友发送消息 + new_friend.send('我是一个没有感情的盗版杀手机器人,请通过回复 "配置" 来配置你的信息') + +# 每日自动发送 +# 测试用的 每隔5分钟。。。 +def _main(): + while True: + for user in config_list.find({}): + time_now = datetime.datetime.now() + if user['is_crawled'] == True and time_now > user['crawled_time'] + datetime.timedelta(minutes=1): + # if user['is_crawled'] == True and user['crawled_time'] + datetime.timedelta(hours=24) > time_now: + friend = bot.friends().search(name=user['user_name'])[0] + loop_reply(friend, user, config_list) + # 这里设计有缺陷 + time.sleep(60) + + +t = threading.Thread(target=_main) +t.start() + +embed() +# bot.join() \ No newline at end of file diff --git a/wxpy.pkl b/wxpy.pkl new file mode 100644 index 0000000..52b74e9 Binary files /dev/null and b/wxpy.pkl differ diff --git a/xianyu.py b/xianyu.py new file mode 100644 index 0000000..2410c6d --- /dev/null +++ b/xianyu.py @@ -0,0 +1,151 @@ +import re +import time +import requests +import datetime +from fake_useragent import UserAgent +from lxml import etree +# 不能从send_msg_with_mongo 导入 我就把这边的函数引过去。。。。 +# from send_msg_with_mongo import config_list, friend_list + +ua = UserAgent() +headers = { + 'User-Agent': ua.random +} + +def get_you_want(query): + url = f'https://s.2.taobao.com/list/?_input_charset=utf8&ist=1&q={query}' + resp = requests.get(url, headers=headers).text + urls = [] + try: + total_page = int(re.findall("共(\d+)页", resp)[0]) + # 我们这里返回前10页就够了, 100页的商品 后面基本都是没用的 + if total_page > 10: + total_page = 10 + for i in range(1, total_page+1): + url = f'https://s.2.taobao.com/list/?_input_charset=utf8&ist=1&q={query}&page={i}' + urls.append(url) + return urls + except: + return None + +def parse_pub_time(pub_time): + if '分钟' in pub_time: + num = int(re.search('\d+', pub_time).group()) + pub_time = datetime.datetime.now() - datetime.timedelta(minutes=num) + elif '小时' in pub_time: + num = int(re.search('\d+', pub_time).group()) + pub_time = datetime.datetime.now() - datetime.timedelta(hours=num) + elif '天' in pub_time: + num = int(re.search('\d+', pub_time).group()) + pub_time = datetime.datetime.now() - datetime.timedelta(days=num) + elif '月' in pub_time: + num = int(re.search('\d+', pub_time).group()) + pub_time = datetime.datetime.now() - datetime.timedelta(days=30*num) + elif '年' in pub_time: + num = int(re.search('\d+', pub_time).group()) + pub_time = datetime.datetime.now() - datetime.timedelta(days=365*num) + return pub_time + + +def parse_page_auto(url, data_list, query, user): + resp = requests.get(url, headers=headers).text + time.sleep(1) + html = etree.HTML(resp) + items = html.xpath("//div[contains(@class, 'ks-waterfall')]")[1:] + for item in items: + item_id = item.xpath('.//div[@class="item-pic"]/a/@href')[0].split('=')[-1] + data = { + 'title': item.xpath('.//div[@class="item-pic"]/a/@title')[0], + 'img': item.xpath('.//div[@class="item-pic"]/a/img/@src')[0], + 'href': 'https:' + item.xpath('.//div[@class="item-pic"]/a/@href')[0], + 'item_id': item_id, + 'desc': item.xpath('.//div[@class="item-brief-desc"]/text()')[0], + 'price': item.xpath('.//span[@class="price"]/em/text()')[0], + 'location': item.xpath('.//div[@class="item-location"]/text()')[0], + 'pub_time': parse_pub_time(item.xpath('.//span[@class="item-pub-time"]/text()')[0]), + 'app_link': 'https://market.m.taobao.com/app/idleFish-F2e/widle-taobao-rax/page-detail?wh_weex=true&wx_navbar_transparent=true&id=' + item_id + # 'is_sold': False + } + # 这里最好判断一下关键词在不在里面。。。 设置个办公自动化 美容美体床、自动双面激光打印机都给我出来了。。。 + # 如果第一爬的话 就全部返回 第一次爬 + if query in data['title'] or query in data['desc']: + # if user['crawled_time'] is None: + print(f"{query} 新发现一个盗版商品-{data['title']}-{data['href']}") + data_list.append(data) + +def return_result(user, msg, config_list): + query_list = user['query_list'] + print(query_list) + # query = '麻瓜编程' + for query in query_list: + data_list = [] + urls = get_you_want(query) + if urls: + for url in urls: + parse_page_auto(url, data_list, query, user) + if len(data_list) > 0: + for data in data_list: + msg.reply(f"{query} 新发现一个盗版商品-{data['title']}-{data['href']}\napp链接为:{data['app_link']}") + time.sleep(1) + msg.reply('-----------------------') + else: + msg.reply('没有找到相关的信息 %s' %query) + msg.reply('回复完毕, 请查看!') + # 更新用户 是否已经爬取 是 。这里不保存信息的话也可以从数据库直接删除 + config_list.update({'user_name':user['user_name'], 'is_sure': 1, 'is_crawled': False},{"$set":{'is_crawled': True, 'crawled_time':datetime.datetime.now()}}) + + +def parse_page(url, data_list, query, user): + resp = requests.get(url, headers=headers).text + time.sleep(1) + html = etree.HTML(resp) + items = html.xpath("//div[contains(@class, 'ks-waterfall')]")[1:] + for item in items: + item_id = item.xpath('.//div[@class="item-pic"]/a/@href')[0].split('=')[-1] + data = { + 'title': item.xpath('.//div[@class="item-pic"]/a/@title')[0], + 'img': item.xpath('.//div[@class="item-pic"]/a/img/@src')[0], + 'href': 'https:' + item.xpath('.//div[@class="item-pic"]/a/@href')[0], + 'item_id': item_id, + 'desc': item.xpath('.//div[@class="item-brief-desc"]/text()')[0], + 'price': item.xpath('.//span[@class="price"]/em/text()')[0], + 'location': item.xpath('.//div[@class="item-location"]/text()')[0], + 'pub_time': parse_pub_time(item.xpath('.//span[@class="item-pub-time"]/text()')[0]), + 'app_link': 'https://market.m.taobao.com/app/idleFish-F2e/widle-taobao-rax/page-detail?wh_weex=true&wx_navbar_transparent=true&id=' + item_id + # 'is_sold': False + } + print(f"pub_time:{data['pub_time']}, crawled_time:{user['crawled_time']}") + # 这里最好判断一下关键词在不在里面。。。 设置个办公自动化 美容美体床、自动双面激光打印机都给我出来了。。。 + # 如果第一爬的话 就全部返回 第一次爬 + if query in data['title'] or query in data['desc']: + if data['pub_time'] > user['crawled_time']: + print(f"{query} 新发现一个盗版商品-{data['title']}-{data['href']}") + data_list.append(data) + + + + +def loop_reply(friend, user, config_list): + # 更新用户 是否已经爬取 是 。这里不保存信息的话也可以从数据库直接删除 + config_list.update({'user_name':user['user_name'], 'is_sure': 1, 'is_crawled': True},{"$set":{'crawled_time':datetime.datetime.now()}}) + + query_list = user['query_list'] + print(query_list) + # query = '麻瓜编程' + for query in query_list: + data_list = [] + urls = get_you_want(query) + print(urls) + if urls: + for url in urls: + parse_page(url, data_list, query, user) + if len(data_list) > 0: + for data in data_list: + friend.send(f"{query} 新发现一个盗版商品-{data['title']}-{data['href']}\napp链接为:{data['app_link']}") + time.sleep(1) + friend.send('-----------------------') + else: + friend.send('没有找到相关的信息 %s' %query) + friend.send('回复完毕, 请查看!') + +