def page_detail_captcha(session, isId): url = 'https://captcha.jd.com/verify/image' acid = '{}_{}'.format(random.random(), random.random()) payload = { 'acid': acid, 'srcid': 'trackWeb', 'is': isId, } headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/531.36", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3", "Referer": "https://trade.jd.com/shopping/order/getOrderInfo.action", "Connection": "keep-alive", 'Host': 'captcha.jd.com', } try: resp = session.get(url=url, params=payload, headers=headers) if not response_status(resp): logger.error('获取订单验证码失败') return '' logger.info('解析验证码开始') image = Image.open(BytesIO(resp.content)) image.save('captcha.jpg') result = analysis_captcha(resp.content) if not result: logger.error('解析订单验证码失败') return '' global submit_captcha_text, submit_captcha_rid submit_captcha_text = result submit_captcha_rid = acid return result except Exception as e: logger.error('订单验证码获取异常:%s', e) return ''
def check_stock(): skuidString = ','.join(skuids) callback = 'jQuery' + str(random.randint(1000000, 9999999)) headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/531.36", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3", "Referer": "https://cart.jd.com/cart.action", "Connection": "keep-alive", } url = 'https://c0.3.cn/stocks' payload = { 'type': 'getstocks', 'skuIds': skuidString, 'area': area, 'callback': callback, '_': int(time.time() * 1000), } resp = checksession.get(url=url, params=payload, headers=headers) resptext = resp.text.replace(callback + '(', '').replace(')', '') respjson = json.loads(resptext) inStockSkuid = [] nohasSkuid = [] abnormalSkuid = [] for i in skuids: try: if respjson[i]['StockStateName'] != '无货': inStockSkuid.append(i) else: nohasSkuid.append(i) except Exception as e: abnormalSkuid.append(i) logger.info('[%s]类型口罩无货', ','.join(nohasSkuid)) if len(abnormalSkuid) > 0: logger.info('[%s]类型口罩查询异常', ','.join(abnormalSkuid)) return inStockSkuid
def _get_QRcode_ticket(self): url = 'https://qr.m.jd.com/check' payload = { 'appid': '133', 'callback': 'jQuery{}'.format(random.randint(1000000, 9999999)), 'token': self.session.cookies.get('wlfstk_smdl'), '_': str(int(time.time() * 1000)), } headers = { 'User-Agent': self.default_user_agent, 'Referer': 'https://passport.jd.com/new/login.aspx', } resp = self.session.get(url=url, headers=headers, params=payload) if not resp.ok: logger.error('获取二维码扫描结果异常') return False resp_json = parse_json(resp.text) if resp_json['code'] != 200: logger.info('Code: %s, Message: %s', resp_json['code'], resp_json['msg']) return None else: logger.info('已完成手机客户端确认') return resp_json['ticket']
def _get_seckill_init_info(self): """获取秒杀初始化信息(包括:地址,发票,token) :return: 初始化信息组成的dict """ for i in range(3): logger.info('获取秒杀初始化信息:{}次...'.format(i)) url = 'https://marathon.jd.com/seckillnew/orderService/pc/init.action' data = { 'sku': self.sku_id, 'num': 1, 'isModifyAddress': 'false', } headers = { 'User-Agent': self.default_user_agent, 'Host': 'marathon.jd.com', } resp = self.session.post(url=url, data=data, headers=headers) if not resp.ok: continue if resp.text == "null": continue if resp.text.find("{") != -1: break else: logger.info('获取秒杀初始化信息 respText:' + resp.text) return parse_json(resp.text)
def login_by_QRcode(self): """二维码登陆 :return: """ if self.is_login: logger.info('登录成功') return self._get_login_page() # download QR code if not self._get_QRcode(): logger.info('二维码下载失败') return # get QR code ticket ticket = None retry_times = 85 for _ in range(retry_times): ticket = self._get_QRcode_ticket() if ticket: break time.sleep(2) else: logger.info('二维码过期,请重新获取扫描') return # validate QR code ticket if not self._validate_QRcode_ticket(ticket): logger.info('二维码信息校验失败') return logger.info('二维码登录成功') self.is_login = True self.nick_name = self.get_user_info()
def fastMode(): flag = 1 while (1): try: if flag == 1: validate_cookies() getUsername() select_all_cart_item() remove_item() # modelType logger.info('第' + str(flag) + '次 ') flag += 1 # 检测库存 inStockSkuid = check_stock() # 下单任务 fastModeAutoBuy(inStockSkuid) timesleep = random.randint(5, 10) / 10 time.sleep(timesleep) if flag % 40 == 0: logger.info('校验是否还在登录') validate_cookies() except Exception as e: print(traceback.format_exc()) time.sleep(10)
def _get_seckill_init_info(self): """获取秒杀初始化信息(包括:地址,发票,token) :return: 初始化信息组成的dict """ logger.info('获取秒杀初始化信息...') url = 'https://marathon.jd.com/seckillnew/orderService/pc/init.action' data = { 'sku': self.sku_id, 'num': 1, 'isModifyAddress': 'false', } headers = { 'User-Agent': self.default_user_agent, 'Host': 'marathon.jd.com', } #in request_seckill_url sleep(0.1) NameError: name 'sleep' is not defined 报错信息在这,调用time.sleep(0.1) #此处如果获取不到,会自动重定向,重定向会报错,这里去掉重定向 while True: resp = self.session.post(url=url, data=data, headers=headers, allow_redirects=False) if len(resp.text) >= 100: break else: sleep(0.01) print(resp) return parse_json(resp.text)
def remove_item(): url = "https://cart.jd.com/batchRemoveSkusFromCart.action" data = { 't': 0, 'null': '', 'outSkus': '', 'random': random.random(), 'locationId': '19-1607-4773-0' } headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.37", "Accept": "application/json, text/javascript, */*; q=0.01", "Referer": "https://cart.jd.com/cart.action", "Host": "cart.jd.com", "Content-Type": "application/x-www-form-urlencoded", "Accept-Encoding": "gzip, deflate, br", "Accept-Encoding": "zh-CN,zh;q=0.9,ja;q=0.8", "Origin": "https://cart.jd.com", "Connection": "keep-alive" } resp = session.post(url, data=data, headers=headers) logger.info('清空购物车') if resp.status_code != requests.codes.OK: print('Status: %u, Url: %s' % (resp.status_code, resp.url)) return False return True
def get_seckill_url(self): """获取商品的抢购链接 点击"抢购"按钮后,会有两次302跳转,最后到达订单结算页面 这里返回第一次跳转后的页面url,作为商品的抢购链接 :return: 商品的抢购链接 """ url = 'https://itemko.jd.com/itemShowBtn' payload = { 'callback': 'jQuery{}'.format(random.randint(1000000, 9999999)), 'skuId': self.sku_id, 'from': 'pc', '_': str(int(time.time() * 1000)), } headers = { 'User-Agent': self.default_user_agent, 'Host': 'itemko.jd.com', 'Referer': 'https://item.jd.com/{}.html'.format(self.sku_id), } while True: resp = self.session.get(url=url, headers=headers, params=payload) resp_json = parse_json(resp.text) if resp_json.get('url'): # https://divide.jd.com/user_routing?skuId=8654289&sn=c3f4ececd8461f0e4d7267e96a91e0e0&from=pc router_url = 'https:' + resp_json.get('url') # https://marathon.jd.com/captcha.html?skuId=8654289&sn=c3f4ececd8461f0e4d7267e96a91e0e0&from=pc seckill_url = router_url.replace('divide', 'marathon').replace( 'user_routing', 'captcha.html') logger.info("抢购链接获取成功: %s", seckill_url) return seckill_url else: logger.info("抢购链接获取失败,%s不是抢购商品或抢购页面暂未刷新,0.5秒后重试") time.sleep(0.1)
def start(self): logger.info('正在等待到达设定时间:%s' % self.buy_time) now_time = datetime.now while True: if now_time() >= self.buy_time: logger.info('时间到达,开始执行……') break
def make_reserve(self): """商品预约""" logger.info('商品名称:{}'.format(get_sku_title())) url = 'https://yushou.jd.com/youshouinfo.action?' payload = { 'callback': 'fetchJSON', 'sku': self.sku_id, '_': str(int(time.time() * 1000)), } headers = { 'User-Agent': self.default_user_agent, 'Referer': 'https://item.jd.com/{}.html'.format(self.sku_id), } resp = self.session.get(url=url, params=payload, headers=headers) resp_json = parse_json(resp.text) reserve_url = resp_json.get('url') self.timers.start() while True: try: self.session.get(url='https:' + reserve_url) logger.info('预约成功,已获得抢购资格 / 您已成功预约过了,无需重复预约') if global_config.getRaw('messenger', 'enable') == 'true': success_message = "预约成功,已获得抢购资格 / 您已成功预约过了,无需重复预约" send_wechat(success_message) break except Exception as e: logger.error('预约失败正在重试...')
def make_reserve(self): """商品预约""" logger.info('商品名称:{}'.format(get_sku_title())) url = 'https://yushou.jd.com/youshouinfo.action?' payload = { 'callback': 'fetchJSON', 'sku': self.sku_id, '_': str(int(time.time() * 1000)), } headers = { 'User-Agent': self.default_user_agent, 'Referer': 'https://item.jd.com/{}.html'.format(self.sku_id), } print("payload" + json.dumps(payload) + "\n" + "headers" + json.dumps(headers)) resp = self.session.get(url=url, params=payload, headers=headers) print(resp) resp_json = parse_json(resp.text) reserve_url = resp_json.get('url') for flag in range(10): try: self.session.get(url='https:' + reserve_url) logger.info('预约成功,已获得抢购资格 / 您已成功预约过了,无需重复预约') if global_config.getRaw('messenger', 'enable') == 'true': success_message = "预约成功,已获得抢购资格 / 您已成功预约过了,无需重复预约" send_wechat(success_message) break except Exception as e: logger.error('预约失败正在重试...' + str(flag) + " " + str(e)) sleep(random.randint(1, 3)) sys.exit(1)
def V3check(skuId): select_all_cart_item() remove_item() validate_cookies() logger.info('校验是否还在登录') add_item_to_cart(skuId) if not item_removed(skuId): logger.info('[%s]已下柜商品', skuId)
def check_Config(): global configMd5, configTime nowMd5 = getconfigMd5() configTime = time.time() if not nowMd5 == configMd5: logger.info('配置文件修改,重新读取文件') getconfig() configMd5 = nowMd5
def get_seckill_url(self): """获取商品的抢购链接 点击"抢购"按钮后,会有两次302跳转,最后到达订单结算页面 这里返回第一次跳转后的页面url,作为商品的抢购链接 :return: 商品的抢购链接 """ url = 'https://item-soa.jd.com/getWareBusiness' payload = { 'callback': 'jQuery{}'.format(random.randint(1000000, 9999999)), 'skuId': self.sku_id, '_': str(int(time.time() * 1000)), } headers = { 'User-Agent': self.default_user_agent, # 'Host': 'item-soa.jd.com', 'Referer': 'https://item.jd.com/', 'authority': 'item-soa.jd.com', 'scheme': 'https', 'method': 'GET', 'num': '1', 'path': '/getWareBusiness?callback=' + payload['callback'] + '&skuId=' + self.sku_id, } tryTime = 0 while True and tryTime < 20: # self.session.mount('https://cart.jd.com/', HTTP20Adapter()) # 加购物车 resp = self.session.get(url=url, headers=headers, params=payload) resp_json = parse_json(resp.text) yuyueInfo = resp_json.get('yuyueInfo') if yuyueInfo is not None and yuyueInfo.get('state') == 4: cookies = self.session.cookies url = 'https://cart.jd.com/gate.action?pcount=1&ptype=1&pid=' + self.sku_id resp = requests.get(url, cookies=cookies) return resp.url # https://divide.jd.com/user_routing?skuId=8654289&sn=c3f4ececd8461f0e4d7267e96a91e0e0&from=pc # router_url = 'https:' + resp_json.get('url') # # https://marathon.jd.com/captcha.html?skuId=8654289&sn=c3f4ececd8461f0e4d7267e96a91e0e0&from=pc # seckill_url = router_url.replace( # 'divide', 'marathon').replace( # 'user_routing', 'captcha.html') # logger.info("抢购链接获取成功: %s", seckill_url) # return seckill_url else: logger.info("抢购链接获取失败,%s不是抢购商品或抢购页面暂未刷新,0.1秒后重试") time.sleep(0.2) tryTime = tryTime + 1
def start(self): logger.info('正在等待到达设定时间:%s' % self.buy_time) now_time_local = datetime.now while True: now_time = datetime.fromtimestamp(self.getTime()) if now_time >= self.buy_time or now_time_local() >= self.buy_time: logger.info('时间到达,开始执行……') break else: time.sleep(self.sleep_interval)
def start(self): logger.info('正在等待到达设定时间:%s' % self.buy_time) now_time = datetime.now print(now_time()) while True: if now_time() >= self.buy_time: logger.info('时间到达,开始执行……') break else: time.sleep(self.sleep_interval)
def request_seckill_checkout_page(self): """访问抢购订单结算页面""" logger.info('访问抢购订单结算页面...') url = 'https://marathon.jd.com/seckill/seckill.action' payload = {'skuId': self.sku_id, 'num': 1, 'rid': int(time.time())} headers = { 'User-Agent': self.default_user_agent, 'Host': 'marathon.jd.com', 'Referer': 'https://item.jd.com/{}.html'.format(self.sku_id), } self.session.get(url=url, params=payload, headers=headers)
def normalModeAutoBuy(inStockSkuid): for skuId in inStockSkuid: if item_removed(skuId): logger.info('[%s]类型口罩有货啦!马上下单', skuId) skuidUrl = 'https://item.jd.com/' + skuId + '.html' if normalModeBuyMask(skuId): message.send(skuidUrl, True) sys.exit(1) else: message.send(skuidUrl, False) else: logger.info('[%s]类型口罩有货,但已下柜商品', skuId)
def _get_seckill_order_data(self): """生成提交抢购订单所需的请求体参数 :return: 请求体参数组成的dict """ logger.info('生成提交抢购订单所需参数...') # 获取用户秒杀初始化信息 try: self.seckill_init_info[self.sku_id] = self._get_seckill_init_info() init_info = self.seckill_init_info.get(self.sku_id) if init_info == None: return None default_address = init_info['addressList'][0] # 默认地址dict invoice_info = init_info.get('invoiceInfo', {}) # 默认发票信息dict, 有可能不返回 token = init_info['token'] data = { 'skuId': self.sku_id, 'num': 1, 'addressId': default_address['id'], 'yuShou': 'true', 'isModifyAddress': 'false', 'name': default_address['name'], 'provinceId': default_address['provinceId'], 'cityId': default_address['cityId'], 'countyId': default_address['countyId'], 'townId': default_address['townId'], 'addressDetail': default_address['addressDetail'], 'mobile': default_address['mobile'], 'mobileKey': default_address['mobileKey'], 'email': default_address.get('email', ''), 'postCode': '', 'invoiceTitle': invoice_info.get('invoiceTitle', -1), 'invoiceCompanyName': '', 'invoiceContent': invoice_info.get('invoiceContentType', 1), 'invoiceTaxpayerNO': '', 'invoiceEmail': '', 'invoicePhone': invoice_info.get('invoicePhone', ''), 'invoicePhoneKey': invoice_info.get('invoicePhoneKey', ''), 'invoice': 'true' if invoice_info else 'false', 'password': '', 'codTimeType': 3, 'paymentType': 4, 'areaCode': '', 'overseas': 0, 'phone': '', 'eid': global_config.getRaw('config', 'eid'), 'fp': global_config.getRaw('config', 'fp'), 'token': token, 'pru': '' } return data except Exception as e: logger.error('获取用户秒杀初始化信息失败{0},正在重试...'.format(e)) return None
def get_checkout_page_detail(): """获取订单结算页面信息 该方法会返回订单结算页面的详细信息:商品名称、价格、数量、库存状态等。 :return: 结算信息 dict """ url = 'http://trade.jd.com/shopping/order/getOrderInfo.action' # url = 'https://cart.jd.com/gotoOrder.action' payload = { 'rid': str(int(time.time() * 1000)), } headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/531.36", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3", "Referer": "https://cart.jd.com/cart.action", "Connection": "keep-alive", 'Host': 'trade.jd.com', } try: resp = session.get(url=url, params=payload, headers=headers) if not response_status(resp): logger.error('获取订单结算页信息失败') return '' if '刷新太频繁了' in resp.text: return '刷新太频繁了' soup = BeautifulSoup(resp.text, "html.parser") showCheckCode = get_tag_value(soup.select('input#showCheckCode'), 'value') if not showCheckCode: pass else: if showCheckCode == 'true': logger.info('提交订单需要验证码') global is_Submit_captcha, encryptClientInfo encryptClientInfo = get_tag_value(soup.select('input#encryptClientInfo'), 'value') is_Submit_captcha = True risk_control = get_tag_value(soup.select('input#riskControl'), 'value') order_detail = { 'address': soup.find('span', id='sendAddr').text[5:], # remove '寄送至: ' from the begin 'receiver': soup.find('span', id='sendMobile').text[4:], # remove '收件人:' from the begin 'total_price': soup.find('span', id='sumPayPriceId').text[1:], # remove '¥' from the begin 'items': [] } logger.info("下单信息:%s", order_detail) return risk_control except requests.exceptions.RequestException as e: logger.error('订单结算页面获取异常:%s' % e) except Exception as e: logger.error('下单页面数据解析异常:%s', e) return ''
def parse_json(text): try: begin = text.find('{') end = text.rfind('}') + 1 return json.loads(text[begin:end]) except Exception as e: logger.error('parse_json error:{0}'.format(e)) try: return json.loads(text) except Exception as ex: logger.error('parse_json error:{0}'.format(ex)) logger.info('resp json string:' + text) return None
def analysis_captcha(pic): for i in range(1, 10): try: url = captchaUrl resp = session.post(url, pic) if not response_status(resp): logger.error('解析验证码失败') continue logger.info('解析验证码[%s]', resp.text) return resp.text except Exception as e: print(traceback.format_exc()) continue return ''
def validate_cookies(): for flag in range(1, 3): try: targetURL = 'https://order.jd.com/center/list.action' payload = { 'rid': str(int(time.time() * 1000)), } resp = session.get(url=targetURL, params=payload, allow_redirects=False) if resp.status_code == requests.codes.OK: logger.info('登录成功') return True else: logger.info('第【%s】次请重新获取cookie', flag) time.sleep(5) continue except Exception as e: logger.info('第【%s】次请重新获取cookie', flag) time.sleep(5) continue wx_info = 'Cookie失效了!请及时更新!' data = {'text': '警告', 'desp': wx_info} requests.post('微信接口', data=data) logger.info('Cookie失效通知已发送微信!')
def getUsername(): userName_Url = 'https://passport.jd.com/new/helloService.ashx?callback=jQuery339448&_=' + str( int(time.time() * 1000)) session.headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/531.36", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3", "Referer": "https://order.jd.com/center/list.action", "Connection": "keep-alive" } resp = session.get(url=userName_Url, allow_redirects=True) resultText = resp.text resultText = resultText.replace('jQuery339448(', '') resultText = resultText.replace(')', '') usernameJson = json.loads(resultText) logger.info('登录账号名称' + usernameJson['nick'])
def V3AutoBuy(inStockSkuid): if skuId in inStockSkuid: global submit_Time submit_Time = int(time.time() * 1000) logger.info('[%s]类型口罩有货啦!马上下单', skuId) skuidUrl = 'https://item.jd.com/' + skuId + '.html' if buyMask(skuId): message.send(skuidUrl, True) sys.exit(1) else: if item_removed(skuId): message.send(skuidUrl, False) else: logger.info('[%s]已下柜商品', skuId) sys.exit(1)
def fastModeAutoBuy(inStockSkuid): for skuId in inStockSkuid: logger.info('[%s]类型口罩有货啦!马上下单', skuId) skuidUrl = 'https://item.jd.com/' + skuId + '.html' if fastModeBuyMask(skuId): message.send(skuidUrl, True) sys.exit(1) else: if item_removed(skuId): message.send(skuidUrl, False) else: logger.info('[%s]商品已下柜,商品列表中踢出') skuids.remove(skuId) select_all_cart_item() remove_item()
def real_time(): jd_headers={ "accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.87 Safari/537.36", } global Info flag = 1 while True: try: if flag == 1: # 检测Cookie有效性 validate_cookies() # 获取京东账户名 getUsername() # 记录检测次数 flag += 1 # 检测列表所有链接 for url1 in jd_url_list: req = requests.get(url1, headers=jd_headers, timeout=10) # 提取出商品实际链接 jd_url = "https://item.jd.com/"+ url1.split('skuId=')[1].split('&')[0]+'.html' if req.text.find('无货') > 0: print ('[%s]--无货...'%jd_url) else: # 将信息写到日志文件中 logger.info('[%s]--有货!!!'%jd_url) # 购买商品,购买异常则退出 if buyMask(url1.split('skuId=')[1].split('&')[0]): sys.exit(1) # Info存储到货的商品链接 Info = jd_url except Exception as e: print (str(e)) if Info != '': # 微信信息 wx_info = '口罩有货了!点击进入:'+'['+Info+']'+'('+Info+')' data = {'text': '口罩有货了', 'desp': wx_info} # 在Server酱中绑定微信获取 requests.post('server酱微信接口', data=data) # 对列表中的邮箱发送邮件 for mailto_list in mailto_lists: send_mail(mailto_list) Info = '' time.sleep(5) # 每检测20次,就检查一次cookie的有效性 if flag % 20 == 0: logger.info('校验是否还在登录') validate_cookies()
def _validate_QRcode_ticket(self, ticket): url = 'https://passport.jd.com/uc/qrCodeTicketValidation' headers = { 'User-Agent': self.default_user_agent, 'Referer': 'https://passport.jd.com/uc/login?ltype=logout', } resp = self.session.get(url=url, headers=headers, params={'t': ticket}) if not resp.ok: return False resp_json = parse_json(resp.text) if resp_json['returnCode'] == 0: return True else: logger.info(resp_json) return False
def cart_detail(): url = 'https://cart.jd.com/cart.action' headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/531.36", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3", "Referer": "https://order.jd.com/center/list.action", "Host": "cart.jd.com", "Connection": "keep-alive" } resp = session.get(url, headers=headers) soup = BeautifulSoup(resp.text, "html.parser") cart_detail = dict() for item in soup.find_all(class_='item-item'): try: sku_id = item['skuid'] # 商品id except Exception as e: logger.info('购物车中有套装商品,跳过') continue try: # 例如:['increment', '8888', '100001071956', '1', '13', '0', '50067652554'] # ['increment', '8888', '100002404322', '2', '1', '0'] item_attr_list = item.find(class_='increment')['id'].split('_') p_type = item_attr_list[4] promo_id = target_id = item_attr_list[-1] if len( item_attr_list) == 7 else 0 cart_detail[sku_id] = { 'name': get_tag_value(item.select('div.p-name a')), # 商品名称 'verder_id': item['venderid'], # 商家id 'count': int(item['num']), # 数量 'unit_price': get_tag_value(item.select('div.p-price strong'))[1:], # 单价 'total_price': get_tag_value(item.select('div.p-sum strong'))[1:], # 总价 'is_selected': 'item-selected' in item['class'], # 商品是否被勾选 'p_type': p_type, 'target_id': target_id, 'promo_id': promo_id } except Exception as e: logger.error("商品%s在购物车中的信息无法解析,报错信息: %s,该商品自动忽略", sku_id, e) logger.info('购物车信息:%s', cart_detail) return cart_detail