from FileUtil import *from OtherUtil import *from RequestUtil import *from selenium import webdriverclass JdHelper: def __init__(self, need_type, filter_list, is_reverse_filter, user_name, user_pwd): self.not_apply_list = [] # 忽略种草官商品 self.user_name = user_name self.user_pwd = user_pwd self.cookie_file = "cookie.txt" self.not_apply_file = "notApply.txt" self.wait_apply_list = [] # 待申请列表 self.session = requests.session() self.headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.85 Safari/537.36", "Referer": "https://try.jd.com/activity/getActivityList?page=1&cids=737", } self.count = 0 self.base_url_list = { "家用电器": "https://try.jd.com/activity/getActivityList?activityState=0&cids=737", "手机数码": "https://try.jd.com/activity/getActivityList?activityState=0&cids=652,9987", "电脑办公": "https://try.jd.com/activity/getActivityList?activityState=0&cids=670", "家居家装": "https://try.jd.com/activity/getActivityList?activityState=0&cids=1620,6728,9847,9855,6196,15248,14065", "美妆护肤": "https://try.jd.com/activity/getActivityList?activityState=0&cids=1316", "服饰鞋包": "https://try.jd.com/activity/getActivityList?activityState=0&cids=1315,1672,1318,11729", "母婴玩具": "https://try.jd.com/activity/getActivityList?activityState=0&cids=1319,6233", "生鲜美食": "https://try.jd.com/activity/getActivityList?activityState=0&cids=12218", "图书音像": "https://try.jd.com/activity/getActivityList?activityState=0&cids=1713,4051,4052,4053,7191,7192,5272", "钟表奢品": "https://try.jd.com/activity/getActivityList?activityState=0&cids=5025,6144", "个人护理": "https://try.jd.com/activity/getActivityList?activityState=0&cids=16750", "家庭清洁": "https://try.jd.com/activity/getActivityList?activityState=0&cids=15901", "食品饮料": "https://try.jd.com/activity/getActivityList?activityState=0&cids=1320,12259", "更多惊喜": "https://try.jd.com/activity/getActivityList?activityState=0&cids=4938,13314,6994,9192,12473,6196,5272,12379,13678,15083,15126,15980" } self.not_apply() if not self.check_login(): LoginHelper().login(self.user_name, self.user_pwd) self.check_login() self.sum() # 是否反转过滤 True:商品名必须包含在filter_list False:商品名不能包含在filter_list self.is_reverse_filter = is_reverse_filter self.filter_list = filter_list self.need_type = need_type if self.is_reverse_filter: print("入选词汇:", self.filter_list) else: print("过滤词汇:", self.filter_list) @retry(stop_max_attempt_number=20) def get_resp(self, url): return self.session.get(url, headers=self.headers, timeout=3) # 查询是否已申请 def getApplyStateByActivityIds(self, activityIds): url = "https://try.jd.com/user/getApplyStateByActivityIds?activityIds=" + activityIds resp = self.get_resp(url) for item in resp.json(): obj = self.find_obj(item["activityId"]) if obj: self.wait_apply_list.remove(obj) # 过滤list def find_obj(self, id): for data in self.wait_apply_list: if str(id) == str(data["activity_id"]): return data # 申请 def apply(self): can_stop = False for wait_apply in self.wait_apply_list: print("\n正在申请,", wait_apply["activity_id"], wait_apply["name"]) # 获取店铺id activity_id = wait_apply["activity_id"] item_url = "https://try.jd.com/{}.html".format(activity_id) shop_id = re.findall('id="_shopId" value="(.*?)"', self.get_resp(item_url).text)[0] time.sleep(1) # 关注 follow_url = "https://try.jd.com/migrate/follow?_s=pc&venderId={}".format(shop_id) resp = self.get_resp(follow_url) print(resp.json()) time.sleep(2) # 申请 url = "https://try.jd.com/migrate/apply?activityId={}&source=0".format(activity_id) resp = self.get_resp(url) resp_data = resp.json() print(resp_data) if resp_data["success"]: self.count += 1 print("当天已申请次数:", self.count) elif '种草官' in resp_data["message"]: with open("notApply.txt", encoding="utf-8", mode="a+") as f: f.write(activity_id + "\n") elif '超过' in resp_data["message"] or '已超' in resp_data["message"]: self.cancel_follow_item() self.cancel_follow_shop() can_stop = True break time.sleep(3) return can_stop # 获取页面大小 def get_page_size(self, url): resp = self.get_resp(url) return int(re.findall('"pages":(\d+)', resp.text)[0]) # 检查登录状态 def check_login(self): self.set_cookie() url = "https://passport.jd.com/user/petName/getUserInfoForMiniJd.action" resp = self.get_resp(url) if 'null' in resp.text: print("cookie失效, 返回信息:", resp.text) return False else: print("登录成功, 当前用户名:", resp.json()["nickName"]) return True # 读取并设置cookie def set_cookie(self): if os.path.exists(self.cookie_file): with open(self.cookie_file, encoding="utf-8", mode="r") as f: self.headers["Cookie"] = f.read().strip() # 统计今日已申请次数 def sum(self): page = 1 run = True today = time.strftime("%Y-%m-%d") while run: url = "https://try.jd.com/user/myTrial?page={}".format(page) resp = self.get_resp(url) parser = etree.HTML(resp.text) day_list = parser.xpath('//span[@class="time"]/em/text()') for day in day_list: if today in day: self.count += 1 else: run = False page += 1 print("今日已申请次数:", self.count) # 过滤器 def in_filter_list(self, name): has_find = True for filter in self.filter_list: if filter in name: has_find = False if self.is_reverse_filter: has_find = not has_find return has_find # 过滤种草官级别 def not_apply(self): if os.path.exists(self.not_apply_file): with open(self.not_apply_file, encoding="utf-8", mode="r") as f: for line in f.readlines(): self.not_apply_list.append(line.strip()) # 取关商品 def cancel_follow_item(self): can_run = True while can_run: page_url = "https://t.jd.com/home/follow?index=1" resp = self.get_resp(page_url) parser = etree.HTML(resp.text) item_id_list = "" for item in parser.xpath('//*[@id="main"]/div/div[2]/div[2]/div[1]/div'): if not item.xpath("./@id"): print("当前没有需要取关的商品") can_run = False break item_id_list += item.xpath("./@id")[0].replace('goods_', '') + "," item_id_list = item_id_list[0:-1] url = "https://api.m.jd.com/api?functionId=batchCancelFavorite&body={%22skus%22:%22" + item_id_list + "%22}&appid=follow_for_concert&soaKey=2e2i4fRvyfAek5MfHNCe;fMeBpvzbQimFgonJp9YpBqyMcz1VvO4sWcyIBRb8VdOTNQDVo7&client=pc&t=1627133437064&jsonp=result&_=1627133437064" resp = self.get_resp(url) print(resp.text) # 取关店铺 def cancel_follow_shop(self): can_run = True while can_run: page_url = "https://t.jd.com/follow/vender/list.do" resp = self.get_resp(page_url) re_list = re.findall('id="vender_(.*?)"', resp.text) if not re_list: print("当前没有需要取关的店铺") break shop_id_list = "" for item in re_list: shop_id_list += item + "," shop_id_list = shop_id_list[0:-1] url = "https://t.jd.com/follow/vender/batchUnfollow.do" resp = self.session.post(url, data={"venderIds": shop_id_list}, headers=self.headers) print(resp.text) def run(self): can_stop = False for need in self.need_type: base_url = self.base_url_list[need] page_size = self.get_page_size(base_url) print("当前类型:{} 总页数:{}".format(need, page_size)) if can_stop: break for i in range(1, page_size + 1): self.wait_apply_list = [] url = base_url + "&page={}".format(i) print("\n获取第{}页 总页数:{} {}".format(i, page_size, url)) resp = self.get_resp(url) parser = etree.HTML(resp.text) activityIds = [] # 查询是否已申请 item_list = parser.xpath('//*[@id="goods-list"]/div[2]/div/ul/li') for item in item_list: wait_apply = {} activity_id = item.xpath("./@activity_id")[0] activityIds.append(activity_id) wait_apply["activity_id"] = activity_id wait_apply["name"] = item.xpath(".//div[@class='p-name']/text()")[0].strip() if activity_id in self.not_apply_list: print("该申请需种草官要求,跳过", wait_apply["name"]) continue if self.in_filter_list(wait_apply["name"]): print("加入待申请:", wait_apply["name"]) self.wait_apply_list.append(wait_apply) else: print("该商品已被过滤:", wait_apply["name"]) continue self.getApplyStateByActivityIds(",".join(activityIds)) can_stop = self.apply() if can_stop: break# 模拟登录class LoginHelper: def login(self, user_name, user_pwd): chrome_options = webdriver.ChromeOptions() chrome_options.add_argument('log-level=2') try: driver = webdriver.Chrome(options=chrome_options) except: driver = webdriver.Chrome(options=chrome_options, executable_path="C:/chromedriver.exe") driver.get('https://passport.jd.com/new/login.aspx') driver.find_element_by_css_selector( '#content > div.login-wrap > div.w > div > div.login-tab.login-tab-r > a').click() driver.implicitly_wait(2) input_username = driver.find_element_by_name('loginname') input_username.send_keys(user_name) input_password = driver.find_element_by_name('nloginpwd') input_password.send_keys(user_pwd) button_logOK = driver.find_elements_by_id('loginsubmit') button_logOK = button_logOK[0] button_logOK.click() while True: try: if driver.find_element_by_css_selector('#ttbar-login > div.dt.cw-icon > a'): break except: print_exc() time.sleep(1) print('登陆成功!') cookie_dict_list = driver.get_cookies() self.save_cookie(cookie_dict_list) driver.quit() def save_cookie(self, cookie_dict_list): cookies_str = "" for cookie_dict in cookie_dict_list: name = cookie_dict["name"] value = cookie_dict["value"] cookies_str += name + "=" + value + "; " cookies_str = cookies_str[0:-2] with open("cookie.txt", encoding="utf-8", mode="w") as f: f.write(cookies_str)if __name__ == '__main__': user_name = "手机账号" user_pwd = "密码" need_type = [ "家用电器", "手机数码", "电脑办公", "家居家装", "美妆护肤", "服饰鞋包", "母婴玩具", "生鲜美食", "图书音像", "钟表奢品", "个人护理", "家庭清洁", "食品饮料", ] filter_list = [ '电话卡', '流量卡', '电信', '进销存', '贴纸', '书签', '便利贴', '笔', '纸', '文具', '儿童', '贴画', '除螨', '口罩', '财务', '软件', '马丁靴', '耳罩', '鞋垫', '长虹', '钥匙' , '系统', '钢化膜', '特雷索', '流量', '卡槽', '手机壳', '手套', '帽子', '指甲', '领带', '牙刷', '刀', '袜子', '口红', '数据线', '充电器', '茶', '卸妆', '洗脸', '面巾', '毛巾', '伸缩带', '剂', '灯', '香水', '车贴', '地漏', '雨刷', '胶', '门窗' ] jdHelper = JdHelper(need_type, filter_list, False, user_name, user_pwd) jdHelper.run()