from FileUtil import *
from OtherUtil import *
from RequestUtil import *
from selenium import webdriver
class 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()