def create_task_order_log(data): url = 'http://third.gets.com/api/index.php?sec=20171212getscn&act=aliexpressCreateTaskOrderLog' resp = requests.post(url, data) if resp.json()['status'] == 0: logger.info('新增刷单操作日志成功!') else: logger.info('新增刷单操作日志失败!')
def update_brushing_status(data): # 测试机 # url = 'http://testthird.gets.com:8383/api/index.php?sec=20171212getscn&act=aliexpressModifyTaskOrderStatus' # 线上 url = 'http://third.gets.com/api/index.php?sec=20171212getscn&act=aliexpressModifyTaskOrderStatus' resp = requests.post(url=url, data=data) # print(resp.text) if resp.json()['msg'] == 'ok': logger.info('刷单状态更新成功!') else: logger.info('刷单状态更新失败!')
def parse_list_page(self, html): parseHtml = etree.HTML(html) good_detail_urls = parseHtml.xpath( '//ul[@id="hs-below-list-items"]/li/div[1]/div[1]/div/a/@href') #绑定当前页的所有商品详情链接 self.good_detail_urls = good_detail_urls for detail_url in good_detail_urls: if re.search(self.target_id, detail_url): detail_url = "https:" + detail_url self.target_good_detail_url = detail_url logger.info('目标商品的详情链接是:%s' % self.target_good_detail_url) self.good_detail_urls = good_detail_urls # logger.info('目标商品所在列表页的所有商品的详情链接是:%s' % self.good_detail_urls) return True return False
def get_detail_page_to_add(self, url): self.driver.get(url) #弹窗处理 try: WebDriverWait(self.driver, 20).until( EC.element_to_be_clickable((By.CLASS_NAME, 'close-layer'))) self.driver.find_element_by_class_name('close-layer').send_keys( Keys.ENTER) except TimeoutException: pass try: #有些商品是没有颜色可选的,需要做异常处理 WebDriverWait(driver=self.driver, timeout=10).until( EC.element_to_be_clickable( (By.XPATH, '//ul[@id="j-sku-list-1"]/li[1]/a'))) self.driver.find_element_by_xpath( '//ul[@id="j-sku-list-1"]/li[1]/a').send_keys(Keys.ENTER) except TimeoutException: pass time.sleep(random.randint(1, 4)) try: #有些商品是没有规格可选的,需要做异常处理 WebDriverWait(driver=self.driver, timeout=10).until( EC.element_to_be_clickable( (By.XPATH, '//ul[@id="j-sku-list-2"]/li[1]/a'))) self.driver.find_element_by_xpath( '//ul[@id="j-sku-list-2"]/li[1]/a').click() except TimeoutException: pass time.sleep(random.randint(1, 4)) self.driver.find_element_by_id('j-add-cart-btn').send_keys(Keys.ENTER) if self.target_id in url: logger.info('目标商品已成功添加到购物车!') else: logger.info('非目标商品已成功添加到购物车!') #关闭添加购物车后的提示窗口 try: WebDriverWait(driver=self.driver, timeout=10).until( EC.element_to_be_clickable( (By.XPATH, '//a[@class="ui-window-close"]'))) self.driver.find_element_by_xpath( '//a[@class="ui-window-close"]').click() except TimeoutException: pass
def delete_other_goods_from_cart(self): WebDriverWait(driver=self.driver, timeout=20).until( EC.element_to_be_clickable( (By.XPATH, '//div[@class="nav-cart nav-cart-box"]/a[1]'))) self.driver.find_element_by_xpath( '//div[@class="nav-cart nav-cart-box"]/a[1]').send_keys(Keys.ENTER) items = self.driver.find_elements_by_class_name("item-group-wrapper") try: for item in items: good_detail_url = item.find_element_by_xpath( './/a[@target="_blank"]').get_attribute('href') if not re.search(self.target_id, good_detail_url): #非目标商品,直接从购物车删除 item.find_element_by_xpath( './/div[@class="product-remove"]/form[1]/a').click() logger.info('非目标商品已从购物车中删除!') time.sleep(2) #点击删除后,网页会刷新,元素已发生改变,需捕获异常并处理 except StaleElementReferenceException: self.delete_other_goods_from_cart()
def fill_in_and_save_payment_information(self): logger.info('正在进入支付信息的填写流程...') WebDriverWait(driver=self.driver, timeout=60).until( EC.element_to_be_clickable((By.XPATH, '//input[@name="cardNum"]'))) time.sleep(random.uniform(0.5, 1.0)) self.driver.find_element_by_name('cardNum').send_keys( self.task_infos[str(self.task_id)]["payment"]["CreditCardNumber"]) time.sleep(random.uniform(0.5, 1.0)) self.driver.find_element_by_name('dateM').send_keys( self.task_infos[str(self.task_id)]["payment"]["ccMonth"]) time.sleep(random.uniform(0.5, 1.0)) self.driver.find_element_by_name('dateY').send_keys( self.task_infos[str(self.task_id)]["payment"]["ccYear"]) time.sleep(random.uniform(0.5, 1.0)) self.driver.find_element_by_name('cvv2').send_keys(self.task_infos[str( self.task_id)]["payment"]["cvv"]) # 切割全名并判断长度 FullName_text = self.task_infos[str( self.task_id)]["address"]["FullName"].split() if len(FullName_text) == 1: time.sleep(random.uniform(0.5, 1.0)) self.driver.find_element_by_name('cardHolderF').send_keys( FullName_text[0]) time.sleep(random.uniform(0.5, 1.0)) self.driver.find_element_by_name('cardHolderL').send_keys( FullName_text[0]) else: time.sleep(random.uniform(0.5, 1.0)) self.driver.find_element_by_name('cardHolderF').send_keys( FullName_text[0]) time.sleep(random.uniform(0.5, 1.0)) self.driver.find_element_by_name('cardHolderL').send_keys( FullName_text[1]) # time.sleep(random.uniform(0.5, 1.0)) # self.driver.find_element_by_name('saveinfo').click() time.sleep(random.uniform(0.5, 1.0)) self.driver.find_element_by_xpath( '//div[@class="payment-line"]/button[1]').click() logger.info('完成支付信息的填写!')
def main(): #单进程模式:循环获取待刷单任务,一次获取一个;若获取不到任务,程序退出。 while True: #测试机地址,获取刷单任务,返回字典格式的json串 # url = 'http://testthird.gets.com:8383/api/index.php?sec=20171212getscn&act=aliexpressGetTaskOrdersList2&get_type=1&limit=1&debug_list=0&debug_allot=0' #线上地址,获取刷单任务,返回字典格式的json串 url = 'http://third.gets.com/api/index.php?sec=20171212getscn&act=aliexpressGetTaskOrdersList2&get_type=1&limit=1' resp = requests.get(url) # if json.loads(resp.text,strict=False) == []: try: # if 'status' in resp.json(): if resp.json() == []: logger.info('未获取到待刷单列表的数据,程序结束!') sys.exit(0) else: logger.info('成功获取到一条待刷单的数据!') task_infos = resp.json() # print(task_infos) for key in task_infos.keys(): task_id = int(key) spider = AliexpressOrderSpider(task_infos, task_id) spider.run() except json.decoder.JSONDecodeError: pass
def run(self): try: self.driver.get('http://www.aliexpress.com/') #过滤弹窗 try: WebDriverWait(self.driver, 40).until( EC.element_to_be_clickable((By.CLASS_NAME, 'close-layer')) ) self.driver.find_element_by_class_name('close-layer').click() except TimeoutException: pass WebDriverWait(self.driver, 40).until( EC.element_to_be_clickable((By.XPATH, '//span[@class="register-btn"]/a')) ) #点击登录 self.driver.find_element_by_xpath('//span[@class="register-btn"]/a').click() # WebDriverWait(self.driver, 40).until( # EC.frame_to_be_available_and_switch_to_it # ) time.sleep(10) #切换到子iframe self.driver.switch_to.frame('alibaba-login-box') #输入登录信息 WebDriverWait(self.driver, 40).until( EC.element_to_be_clickable((By.XPATH, '//input[@id="fm-login-id"]')) ) self.driver.find_element_by_id('fm-login-id').send_keys(self.task_infos[str(self.task_id)]["account"]["login_aliexpress_email"]) time.sleep(random.randint(1, 5)) self.driver.find_element_by_id('fm-login-password').send_keys(self.task_infos[str(self.task_id)]["account"]["login_aliexpress_password"]) time.sleep(random.randint(1, 5)) self.driver.find_element_by_id('fm-login-submit').submit() #此处判断登录过程中是否有滑块验证码,有则终止程序 if 'display: block' in self.driver.find_element_by_id('fm-login-checkcode-title').get_attribute('style'): logger.info('登录时发现滑块验证码,程序退出!') self.driver.quit() sys.exit(0) #弹窗处理 try: WebDriverWait(self.driver, 40).until( EC.element_to_be_clickable((By.CLASS_NAME, 'close-layer')) ) self.driver.find_element_by_class_name('close-layer').click() except TimeoutException: pass if self.driver.current_url == 'https://www.aliexpress.com/': #插入账号登录日志 login_log_data = { 'data':{ "account_id":self.task_infos[str(self.task_id)]["account"]["account_id"], "header":self.task_infos[str(self.task_id)]['account']['header'], "cookies": json.dumps(self.driver.get_cookies()), "login_status": "1", "note": "登录成功" } } self.insert_account_login_log(json.dumps(login_log_data)) #当账户成功登录时, 把登录的header和cookie修改对应账户表的字段 login_success_info_data = { 'data':{ "account_id": self.task_infos[str(self.task_id)]["account"]["account_id"], "header": self.task_infos[str(self.task_id)]['account']['header'], "cookies": json.dumps(self.driver.get_cookies()) } } self.update_account_login_success_info(json.dumps(login_success_info_data)) elif 'passport.aliexpress.com' in self.driver.current_url: logger.info('登录后发现验证码,账户已被封!') #账户被封,也更新刷单状态 brushing_data = { str(self.task_id): { "task_id": self.task_id, "status": 10, # "order_no": '', # "payment_date": '', # "actual_order_amount": 0.00 } } self.update_brushing_status(json.dumps(brushing_data)) self.driver.quit() logger.info('程序退出!') sys.exit(0) # 先检查cofirm_pay_file文件夹下,是否存在一个taskid_xx.txt文件,xx为本次任务id。 # 若存在,则进入个人订单中心,获取订单号和定价总价等信息,更新刷单状态。并删除该文件。 # 若不存在,则正常走流程。 confirm_receive_dir = os.path.join(os.path.dirname(__file__), 'confirm_receive_files') confirm_receive_filename = confirm_receive_dir + '/' + 'taskid_' + str(self.task_id) + '.txt' if os.path.exists(confirm_receive_filename): logger.info('发现任务id: %d之前已确认收货,准备进入个人订单中心,确认是否留评状态,并进行相应的处理...' % self.task_id) ## 点击首页中的"My Orders",进入个人订单页面 WebDriverWait(self.driver, 40).until( EC.element_to_be_clickable((By.XPATH, '//div[@id="user-benefits"]//ul/li[2]/a')) ) self.driver.find_element_by_xpath('//div[@id="user-benefits"]//ul/li[2]/a').click() # 搜索按钮可点击 # WebDriverWait(self.driver, 40).until( # EC.element_to_be_clickable((By.ID, 'id="search-btn"')) # ) time.sleep(5) # 先找到所有的订单items,再根据订单号或者商品asin,定位到目标订单所在的item items = self.driver.find_elements_by_xpath('//*[@id="buyer-ordertable"]/tbody') for item in items: if item.find_element_by_xpath('./tr[1]/td[2]/p[1]/span[2]').text == self.task_infos[str(self.task_id)]["import_aliexpress_order"]: logger.info('找到目标订单所在的tbody!') # 根据当前订单的状态做判断 if item.find_element_by_xpath('./tr[2]/td[4]/button[3]').text.strip() == 'Leave Feedback': logger.info('当前账户已收货,但未成功留评,准备执行留评的流程...') item.find_element_by_xpath('./tr[2]/td[4]/button[3]').click() # 进入评论页面 WebDriverWait(self.driver, 60).until( EC.element_to_be_clickable((By.XPATH, '//div[@name="eval_star_node"]/span[1]')) # EC.element_to_be_clickable((By.XPATH, '//*[@id="star_%s"]/span[1]' % '99723247396644')) ) logger.info('进入评论填写页面...') logger.info('当前url:%s' % self.driver.current_url) # 此处需要根据接口数据,来判断好评与差评,再调整星级的点按位置(修改Xpath,可使用占位符,设置星级数为一个实例属性,这样可以简化减少代码臃肿) # 点星商品描述时,需要上传图片 if self.task_infos[str(self.task_id)]['review']['title'] == 'bad': stars_num = 1 else: stars_num = 5 self.driver.find_element_by_xpath( '//div[@name="eval_star_node"]/span[%s]' % stars_num).click() time.sleep(10) # self.driver.find_element_by_xpath('//*[@id="image_uploader_99723247396644"]/div/button') self.driver.find_element_by_xpath('//div[@class="feedback-main"]/textarea').send_keys( self.task_infos[str(self.task_id)]['review']["content"]) time.sleep(random.randint(1, 5)) img_url = self.task_infos[str(self.task_id)]['review']["images"] if img_url: logger.info('发现图片链接,正在下载图片并将图片上传到评论页面中...') # img_path = ' '#图片的绝对路径或者相对路径 img_path = self.get_img_path(img_url=img_url) self.driver.find_element_by_xpath('//div[@class="ui-uploader"]/button[1]').send_keys( img_path) # 时间延迟,使图片上传完,此处的时间延迟应该怎么做?多久合适? time.sleep(30) else: logger.info('未发现图片链接,将不上传图片到评论页面!') time.sleep(random.randint(1, 3)) # 服务态度 self.driver.find_element_by_xpath( '//*[@id="j-leave-feedback-container"]/div/div[4]/div[2]/div/div[1]/span[%s]' % stars_num).click() # 物流速度 time.sleep(random.randint(1, 3)) self.driver.find_element_by_xpath( '//*[@id="j-leave-feedback-container"]/div/div[4]/div[3]/div/div[1]/span[%s]' % stars_num).click() # 勾选,设置为匿名评论 time.sleep(random.randint(1, 3)) self.driver.find_element_by_id('j-anonymous-feedback').click() # 点击按钮留下反馈 time.sleep(random.randint(1, 3)) self.driver.find_element_by_id('buyerLeavefb-submit-btn').click() # 留评后的url # 'https://feedback.aliexpress.com/management/leaveFeedback.htm?parentOrderId=99723247396644' time.sleep(20) # 评论完成时,url中没有'isOrderCompleted=Y' # if not 'isOrderCompleted=Y' in self.driver.current_url: if 'Your feedback has been submitted' in self.driver.page_source: logger.info('留评成功!') # 更新刷单状态 review_data = { str(self.task_id): { "task_id": self.task_id, "status": 6, } } self.update_brushing_status(json.dumps(review_data)) # 新增刷单操作日志 log_data = { "task_id": self.task_id, "info": "留评成功!", 'ip': self.get_ip_info(proxies={'https': self.proxy}) } self.create_task_order_log(json.dumps(log_data)) os.remove(confirm_receive_filename) logger.info('删除了一个文件:%s' % confirm_receive_filename) else: logger.info('留评失败!') review_data = { str(self.task_id): { "task_id": self.task_id, "status": 61, } } # 更新刷单状态 self.update_brushing_status(json.dumps(review_data)) # 新增刷单操作日志 log_data = { "task_id": self.task_id, "info": "留评失败!", 'ip': self.get_ip_info(proxies={'https': self.proxy}) } self.create_task_order_log(json.dumps(log_data)) os.remove(confirm_receive_filename) logger.info('删除了一个文件:%s' % confirm_receive_filename) break else: self.review() logger.info('当前账户操作完毕,关闭当前浏览器!') self.driver.quit() except NoSuchFrameException: logger.info('切换到登录的frame超时,正在重新请求主页,继续执行登录操作') self.run() except (TimeoutException, WebDriverException): logger.info('等待超时,或者元素位未完全加载导致定位出错!') logger.info('关闭当前浏览器,结束当前线程!') logger.info('系统会自动生成新的线程来执行下单任务!') self.driver.quit() sys.exit(0)
def update_account_login_success_info(data): url = 'http://third.gets.com/api/index.php?sec=20171212getscn&act=aliexpressUpdateAccountLoginSuccessInfo' requests.post(url, data) logger.info('对应账户的header和cookies字段已成功修改!')
def insert_account_login_log(data): url = 'http://third.gets.com/api/index.php?sec=20171212getscn&act=aliexpressInsertAccountLoginLog' requests.post(url, data) logger.info('账户登录日志已成功插入!')
def review(self): # 点击首页中的"My Orders",进入个人订单页面 WebDriverWait(self.driver, 40).until( EC.element_to_be_clickable((By.XPATH, '//div[@id="user-benefits"]//ul/li[2]/a')) ) self.driver.find_element_by_xpath('//div[@id="user-benefits"]//ul/li[2]/a').click() #点击确认收货 WebDriverWait(self.driver, 40).until( EC.element_to_be_clickable((By.XPATH, '//table[@id="buyer-ordertable"]/tbody/tr[2]/td[4]/button[2]')) ) #此处先进行判断,如果卖家发货,则可以走留评的流程,否则,程序退出。 if self.driver.find_element_by_xpath('//table[@id="buyer-ordertable"]/tbody/tr[2]/td[4]/button[2]').text.strip() == 'Confirm Goods Received': logger.info('卖家已发货,正在执行留评的流程...') self.driver.find_element_by_xpath('//table[@id="buyer-ordertable"]/tbody/tr[2]/td[4]/button[2]').click() # 进入订单明细页面,勾选目标商品所在的订单,再次点击确认收货 WebDriverWait(self.driver, 40).until( EC.element_to_be_clickable((By.XPATH, '//*[@id="button-confirmOrderReceived"]')) ) trs = self.driver.find_elements_by_xpath('//*[@id="confirm-receiving"]/tbody/tr') for tr in trs: good_detail_url = tr.find_element_by_xpath('./td[4]/div[1]/a').get_attribute('href') if re.search(self.target_id, good_detail_url): tr.find_element_by_xpath('./td[2]/input').click() time.sleep(random.randint(1, 3)) self.driver.find_element_by_xpath('//*[@id="button-confirmOrderReceived"]').click() # 点击弹出的“comfirm”按钮 WebDriverWait(self.driver, 40).until( EC.element_to_be_clickable((By.ID, 'confirm_cpf')) ) self.driver.find_element_by_id('confirm_cpf').click() logger.info('点击了最终确认收货的按钮!') # 在项目的根目录下,新建一个文件夹confirm_receive_files,并在该文件夹下生成一个文件,文件名命名为'taskid_xx.txt'文件,‘xx’代表任务id confirm_receive_dir = os.path.join(os.path.dirname(__file__), 'confirm_receive_files') if not os.path.exists(confirm_receive_dir): os.mkdir(confirm_receive_dir) confirm_receive_filename = confirm_receive_dir + '/' + 'taskid_' + str(self.task_id) + '.txt' f = open(confirm_receive_filename, 'w', encoding='utf-8') f.close() logger.info('同时创建了一个文件:%s' % confirm_receive_filename) #进入评论页面 WebDriverWait(self.driver, 60).until( EC.element_to_be_clickable((By.XPATH, '//div[@name="eval_star_node"]/span[1]')) # EC.element_to_be_clickable((By.XPATH, '//*[@id="star_%s"]/span[1]' % '99723247396644')) ) logger.info('进入评论填写页面...') logger.info('当前url:%s' % self.driver.current_url) #此处需要根据接口数据,来判断好评与差评,再调整星级的点按位置(修改Xpath,可使用占位符,设置星级数为一个实例属性,这样可以简化减少代码臃肿) #点星商品描述时,需要上传图片 if self.task_infos[str(self.task_id)]['review']['title'] == 'bad': stars_num = 1 else: stars_num = 5 self.driver.find_element_by_xpath('//div[@name="eval_star_node"]/span[%s]' % stars_num).click() time.sleep(10) # self.driver.find_element_by_xpath('//*[@id="image_uploader_99723247396644"]/div/button') self.driver.find_element_by_xpath('//div[@class="feedback-main"]/textarea').send_keys(self.task_infos[str(self.task_id)]['review']["content"]) time.sleep(random.randint(1, 5)) img_url = self.task_infos[str(self.task_id)]['review']["images"] if img_url: logger.info('发现图片链接,正在下载图片并将图片上传到评论页面中...') # img_path = ' '#图片的绝对路径或者相对路径 img_path = self.get_img_path(img_url=img_url) self.driver.find_element_by_xpath('//div[@class="ui-uploader"]/button[1]').send_keys(img_path) #时间延迟,使图片上传完,此处的时间延迟应该怎么做?多久合适? time.sleep(30) else: logger.info('未发现图片链接,将不上传图片到评论页面!') time.sleep(random.randint(1, 3)) #服务态度 self.driver.find_element_by_xpath('//*[@id="j-leave-feedback-container"]/div/div[4]/div[2]/div/div[1]/span[%s]' % stars_num).click() #物流速度 time.sleep(random.randint(1, 3)) self.driver.find_element_by_xpath('//*[@id="j-leave-feedback-container"]/div/div[4]/div[3]/div/div[1]/span[%s]' % stars_num).click() #勾选,设置为匿名评论 time.sleep(random.randint(1, 3)) self.driver.find_element_by_id('j-anonymous-feedback').click() #点击按钮留下反馈 time.sleep(random.randint(1, 3)) self.driver.find_element_by_id('buyerLeavefb-submit-btn').click() #留评后的url # 'https://feedback.aliexpress.com/management/leaveFeedback.htm?parentOrderId=99723247396644' time.sleep(20) #评论完成时,url中没有'isOrderCompleted=Y' # if not 'isOrderCompleted=Y' in self.driver.current_url: if 'Your feedback has been submitted' in self.driver.page_source: logger.info('留评成功!') # 更新刷单状态 review_data = { str(self.task_id): { "task_id": self.task_id, "status": 6, } } self.update_brushing_status(json.dumps(review_data)) # 新增刷单操作日志 log_data = { "task_id": self.task_id, "info": "留评成功!", 'ip': self.get_ip_info(proxies={'https': self.proxy}) } self.create_task_order_log(json.dumps(log_data)) os.remove(confirm_receive_filename) logger.info('删除了一个文件:%s' % confirm_receive_filename) else: logger.info('留评失败!') review_data = { str(self.task_id): { "task_id": self.task_id, "status": 61, } } #更新刷单状态 self.update_brushing_status(json.dumps(review_data)) # 新增刷单操作日志 log_data = { "task_id": self.task_id, "info": "留评失败!", 'ip': self.get_ip_info(proxies={'https': self.proxy}) } self.create_task_order_log(json.dumps(log_data)) os.remove(confirm_receive_filename) logger.info('删除了一个文件:%s' % confirm_receive_filename) else: logger.info('卖家尚未发货,暂时不能留评,程序退出!') self.driver.quit() sys.exit(0)
def main(task_infos, task_id): spider = AliexpressReviewSpider(task_infos, task_id) spider.run() if __name__ == '__main__': # 多线程循环模式:默认一次最多获取5个待评论任务,自动根据获取到的任务数量创建相应数量的线程数,去执行各自分配到的刷单任务;当获取不到任务时,程序退出。 #修改limit参数即可设置获取的任务数量,现在是1 while True: url = 'http://third.gets.com/api/index.php?sec=20171212getscn&act=aliexpressGetTaskOrdersList2&get_type=3&limit=2' resp = requests.get(url) try: if resp.json() == []: # logger.info('未获取到待评论列表的数据,程序结束!') # sys.exit(0) logger.info('当前未获取到待评论的数据,程序将启动休眠模式,60分钟后自动唤醒...') time.sleep(60 * 60) else: task_infos = resp.json() task_id_str_list = [] for task_id_str in task_infos: task_id_str_list.append(task_id_str) logger.info('成功获取到%d条待评论的数据!' % len(task_id_str_list)) logger.info('将创建%d个线程来分别执行评论任务!' % len(task_id_str_list)) threads = [] for i in range(len(task_id_str_list)): task_id = int(task_id_str_list[i]) t = threading.Thread(target=main, args=(task_infos, task_id)) threads.append(t) t.start() time.sleep(30)
def run(self): try: self.driver.get('http://www.aliexpress.com/') #过滤弹窗 try: WebDriverWait(self.driver, 40).until( EC.element_to_be_clickable((By.CLASS_NAME, 'close-layer'))) self.driver.find_element_by_class_name('close-layer').click() except TimeoutException: pass WebDriverWait(self.driver, 40).until( EC.element_to_be_clickable( (By.XPATH, '//span[@class="register-btn"]/a'))) #点击登录 self.driver.find_element_by_xpath( '//span[@class="register-btn"]/a').click() # WebDriverWait(self.driver, 40).until( # EC.frame_to_be_available_and_switch_to_it # ) time.sleep(10) #切换到子iframe self.driver.switch_to.frame('alibaba-login-box') #输入登录信息 WebDriverWait(self.driver, 40).until( EC.element_to_be_clickable( (By.XPATH, '//input[@id="fm-login-id"]'))) # time.sleep(random.randint(1,3)) self.driver.find_element_by_id('fm-login-id').send_keys( self.task_infos[str( self.task_id)]["account"]["login_aliexpress_email"]) time.sleep(random.randint(1, 5)) self.driver.find_element_by_id('fm-login-password').send_keys( self.task_infos[str( self.task_id)]["account"]["login_aliexpress_password"]) time.sleep(random.randint(1, 5)) self.driver.find_element_by_id('fm-login-submit').click() #此处判断登录过程中是否有滑块验证码,有则终止程序 if 'display: block' in self.driver.find_element_by_id( 'fm-login-checkcode-title').get_attribute('style'): logger.info('登录时发现滑块验证码,程序退出!') self.driver.quit() sys.exit(0) #弹窗处理 try: WebDriverWait(self.driver, 40).until( EC.element_to_be_clickable((By.CLASS_NAME, 'close-layer'))) self.driver.find_element_by_class_name('close-layer').click() except TimeoutException: pass if self.driver.current_url == 'https://www.aliexpress.com/': #插入账号登录日志 login_log_data = { 'data': { "account_id": self.task_infos[str( self.task_id)]["account"]["account_id"], "header": self.task_infos[str( self.task_id)]['account']['header'], "cookies": json.dumps(self.driver.get_cookies()), "login_status": "1", "note": "登录成功" } } self.insert_account_login_log(json.dumps(login_log_data)) #当账户成功登录时, 把登录的header和cookie修改对应账户表的字段 login_success_info_data = { 'data': { "account_id": self.task_infos[str( self.task_id)]["account"]["account_id"], "header": self.task_infos[str( self.task_id)]['account']['header'], "cookies": json.dumps(self.driver.get_cookies()) } } self.update_account_login_success_info( json.dumps(login_success_info_data)) elif 'passport.aliexpress.com' in self.driver.current_url: logger.info('登录后发现验证码,账户已被封!') #账户被封,也更新刷单状态 brushing_data = { str(self.task_id): { "task_id": self.task_id, "status": 10, # "order_no": '', # "payment_date": '', # "actual_order_amount": 0.00 } } self.update_brushing_status(json.dumps(brushing_data)) self.driver.quit() logger.info('程序退出!') sys.exit(0) WebDriverWait(self.driver, 40).until( EC.element_to_be_clickable((By.ID, "search-key"))) self.driver.find_element_by_id('search-key').send_keys( self.task_infos[str(self.task_id)]["asin"]["keywords"]) time.sleep(random.uniform(0.5, 1.5)) self.driver.find_element_by_class_name('search-button').send_keys( Keys.ENTER) for i in range(1, 3): #弹窗处理 try: WebDriverWait(self.driver, 20).until( EC.element_to_be_clickable( (By.CLASS_NAME, 'close-layer'))) self.driver.find_element_by_class_name( 'close-layer').click() except TimeoutException: pass WebDriverWait(driver=self.driver, timeout=30).until( EC.element_to_be_clickable(( By.XPATH, '//span[@class="ui-pagination-active"]/following-sibling::a[1]' ))) source = self.driver.page_source result = self.parse_list_page(source) if result: self.get_detail_page_to_add(self.target_good_detail_url) break else: next_page_btn = self.driver.find_element_by_xpath( '//span[@class="ui-pagination-active"]/following-sibling::a[1]' ) next_page_btn.click() logger.info('第%d列表搜索页没找到目标商品,正在跳转到第%d列表搜索页...' % (i, i + 1)) time.sleep(3) else: logger.info('前2页中没有找到目标商品,正在拼接目标商品的详情url,进行特殊处理...') self.target_good_detail_url = 'https://www.aliexpress.com/item/-a/' + self.target_id + '.html' self.get_detail_page_to_add(self.target_good_detail_url) self.add_other_goods() self.delete_other_goods_from_cart() brushing_data = self.place_order() # 更新刷单状态. place_order()成功下单时返回json数据,否则返回None. if brushing_data: self.update_brushing_status(brushing_data) # 新增刷单操作日志 data = { "task_id": self.task_id, "info": "下单成功!", 'ip': self.get_ip_info(proxies={'https': self.proxy}) } self.create_task_order_log(json.dumps(data)) self.driver.quit() logger.info('当前账户操作完毕,关闭当前浏览器!') except NoSuchFrameException: logger.info('切换到登录的frame超时,正在重新请求主页,继续执行登录操作') self.run() # except NoSuchElementException: # logger.info('定位不到对应的元素,将重新访问首页,继续走流程!') # self.run() # except WebDriverException: # logger.info('点击下一页连接时出错,将重新访问首页,继续走流程!') # self.run() except (TimeoutException, WebDriverException) as e: # 在操作过程中等待超时,先退出当前登录状态,再重新执行run方法回调,重新走流程。也可直接结束程序,只适合在多线程的情况下操作。 logger.info('等待超时,或者元素位未完全加载导致点击出错,正在检查登录状态,若已登录,则退出登录状态,重新走流程!') self.driver.execute_script( 'window.scrollTo(document.body.scrollWidth,0 );') time.sleep(3) try: element = self.driver.find_element_by_xpath( '//div[@id="nav-user-account"]/div[1]') actions = ActionChains(self.driver) actions.move_to_element(element) actions.perform() WebDriverWait(self.driver, 60).until( EC.element_to_be_clickable( (By.XPATH, '//div[@id="nav-user-account"]/div[2]/div[1]/a'))) self.driver.find_element_by_xpath( '//div[@id="nav-user-account"]/div[2]/div[1]/a').click() time.sleep(4) # 此处必须有关闭浏览器的操作,否则登录状态退出不彻底,不能正常run回调 self.driver.close() except NoSuchElementException: pass #是否需要close? self.run()
def place_order(self): #页面刷新,可有可无 self.driver.refresh() WebDriverWait(driver=self.driver, timeout=20).until( EC.element_to_be_clickable( (By.XPATH, '//div[@class="product-price-info3"]/a[1]'))) quantity = self.driver.find_element_by_xpath( '//input[@readonly="readonly"]').get_attribute('value') # 发现一个有意思的情况,同一款商品同规格同颜色,多次添加到购物车,进入购物车查看时,商品数量依然为1。 # 所以,商品数量的处理,可以简化。 if quantity == '1': price_text = self.driver.find_element_by_xpath( '//span[@class="total-price ui-cost notranslate"]/b').text price = re.sub(r'US \$', '', price_text) #此处购物车中的待支付金额是否超出单笔最大额度,若超出,则终止刷单。 logger.info('删除非目标商品后,购物车中查看到的待支付金额:%s' % price) if float(price) > float(self.task_infos[str( self.task_id)]["payment"]["single_max_trade"]): logger.info('删除非目标商品后,购物车中查看到的待支付金额超出单笔最大额度,终止刷单!') # 新增刷单操作日志 data = { "task_id": self.task_id, "info": "删除非目标商品后,购物车中查看到的待支付金额超出单笔最大额度,终止刷单!", 'ip': self.get_ip_info(proxies={'https': self.proxy}) } self.create_task_order_log(json.dumps(data)) logger.info('程序结束!') sys.exit(0) self.driver.find_element_by_xpath( '//div[@class="product-price-info3"]/a[1]').send_keys( Keys.ENTER) logger.info('走下单流程!准备进入个人信息和支付信息的填写流程...') #跳转到个人信息填写页面,需要加以判断,是否已有地址信息 WebDriverWait(driver=self.driver, timeout=30).until( EC.presence_of_element_located( (By.XPATH, '//*[@id="page"]/div[1]/div[1]/ol/li[1]'))) try: default_address_info_element = self.driver.find_element_by_xpath( '//*[@id="address-main"]/div[2]/ul/li/div/div[1]') if 'selected' in default_address_info_element.get_attribute( 'class'): logger.info('已有默认收货地址!') self.driver.execute_script( 'window.scrollTo(0,document.body.scrollHeight)') time.sleep(3) try: # if self.driver.find_element_by_xpath('//*[@id="j-payment-method"]/div[4]/ul/li[1]/span/span'): if self.driver.find_element_by_xpath( '//ul[@class="pay-method-list"]/li[1]/span/span' ): logger.info('已有默认支付信息!') except NoSuchElementException: # 找不到对应的元素,即没有默认支付信息,则继续走支付信息的填写流程 self.fill_in_and_save_payment_information() except NoSuchElementException as e: logger.info('没有默认收货地址,正在新建收货地址...') WebDriverWait(driver=self.driver, timeout=30).until( EC.element_to_be_clickable( (By.XPATH, '//div[@class="sa-btn-group"]/a'))) self.driver.find_element_by_name('contactPerson').send_keys( self.task_infos[str(self.task_id)]["address"]["FullName"]) time.sleep(random.uniform(0.5, 1.0)) country_selectBtn = Select( self.driver.find_element_by_name('country')) country_selectBtn.select_by_visible_text('United States') time.sleep(random.uniform(0.5, 1.0)) self.driver.find_element_by_name('address').send_keys( self.task_infos[str( self.task_id)]["address"]["AddressLine1"]) if self.task_infos[str( self.task_id)]["address"]["AddressLine2"]: time.sleep(random.uniform(0.5, 1.0)) self.driver.find_element_by_name('address2').send_keys( self.task_infos[str( self.task_id)]["address"]["AddressLine2"]) state_selectBtn = Select( self.driver.find_element_by_xpath( '//input[@name="province"]/following-sibling::select[1]' )) try: time.sleep(random.uniform(0.5, 1.0)) state_selectBtn.select_by_visible_text(self.task_infos[str( self.task_id)]["address"]["StateOrRegion"]) except Exception: logger.info('从接口获取的StateOrRegion信息对应不上,默认为下拉列表的第一个州或地区!') StateOrRegion = self.driver.find_element_by_xpath( '//input[@name="province"]/following-sibling::select[1]/option[2]' ).text print(StateOrRegion) time.sleep(random.uniform(0.5, 1.0)) state_selectBtn.select_by_visible_text(StateOrRegion) # 此处需要时间延迟,来加载城市的下拉列表 time.sleep(12) city_selectBtn = Select( self.driver.find_element_by_xpath( '//input[@name="city"]/following-sibling::select[1]')) #amazon的城市信息与速卖通的城市信息不一定匹配,比如大小写不一致,需要做异常处理 try: time.sleep(random.uniform(0.5, 1.0)) city_selectBtn.select_by_visible_text(self.task_infos[str( self.task_id)]["address"]["City"]) except Exception: logger.info('从接口获取的城市信息对应不上,正在进行异常处理...') try: city_text = self.task_infos[str( self.task_id)]["address"]["City"].split() city_text[-1] = city_text[-1].lower() city = " ".join(city_text) print(city) time.sleep(random.uniform(0.5, 1.0)) city_selectBtn.select_by_visible_text(city) except Exception: logger.info('大小写处理失败,默认为下拉列表的第一个城市!') city = self.driver.find_element_by_xpath( '//input[@name="city"]/following-sibling::select[1]/option[2]' ).text # print(city) time.sleep(random.uniform(0.5, 1.0)) city_selectBtn.select_by_visible_text(city) # city_selectBtn.select_by_visible_text('Jersey city') time.sleep(random.uniform(0.5, 1.0)) self.driver.find_element_by_name('zip').send_keys( self.task_infos[str( self.task_id)]["address"]["PostalCode"]) #电话号码需要处理,若有"+1"前缀,则去掉"+1"前缀 PhoneNumber = self.task_infos[str( self.task_id)]["address"]["PhoneNumber"] if re.match(r'\+1', PhoneNumber): PhoneNumber = re.sub(r'\+1', '', PhoneNumber) time.sleep(random.uniform(0.5, 1.0)) self.driver.find_element_by_name('mobileNo').send_keys( PhoneNumber) time.sleep(random.uniform(0.5, 1.0)) self.driver.find_element_by_name('isDefault').click() time.sleep(random.uniform(0.5, 1.0)) self.driver.find_element_by_xpath( '//div[@class="sa-btn-group"]/a[1]').click() self.fill_in_and_save_payment_information() WebDriverWait(driver=self.driver, timeout=30).until( EC.element_to_be_clickable( (By.XPATH, '//div[@class="place-order-button"]/button[1]'))) #点击"Confirm & Pay" time.sleep(random.uniform(0.5, 1.0)) self.driver.find_element_by_xpath( '//div[@class="place-order-button"]/button[1]').click() WebDriverWait(driver=self.driver, timeout=30).until( EC.element_to_be_clickable( (By.XPATH, '//*[@id="header"]/div/div[2]/div[1]/a'))) time.sleep(15) if 'payOnlineSuccess' in self.driver.current_url: self.driver.save_screenshot('PaySuccess.png') logger.info('下单成功!') # logger.info("成功下单后的url:%s" % self.driver.current_url) payment_date = datetime.datetime.now().strftime( '%Y-%m-%d %H:%M:%S') logger.info('下单时间:%s' % payment_date) self.driver.back() time.sleep(2) self.driver.execute_script( 'window.scrollTo(document.body.scrollWidth,0 );') WebDriverWait(driver=self.driver, timeout=30).until( EC.presence_of_element_located( (By.XPATH, '//div[@id="nav-user-account"]/div[1]'))) element = self.driver.find_element_by_xpath( '//div[@id="nav-user-account"]/div[1]') # print(element) actions = ActionChains(self.driver) actions.move_to_element(element) actions.perform() time.sleep(1) WebDriverWait(self.driver, 40).until( EC.element_to_be_clickable( (By.XPATH, '//ul[@class="flyout-quick-entry"]/li[2]/a'))) self.driver.find_element_by_xpath( '//ul[@class="flyout-quick-entry"]/li[2]/a').click() time.sleep(4) order_no = self.driver.find_element_by_xpath( '//*[@id="buyer-ordertable"]//tr[1]/td[2]/p[1]/span[2]' ).text logger.info("订单号为:%s" % order_no) price_text = self.driver.find_element_by_xpath( '//*[@id="buyer-ordertable"]/tbody[1]/tr[1]/td[4]/div/p[2]' ).text.strip() actual_order_amount = re.sub(r'\$ ', '', price_text) logger.info('订单总价:%s' % actual_order_amount) brushing_data = { str(self.task_id): { "task_id": self.task_id, "status": 2, "order_no": order_no, "payment_date": payment_date, "actual_order_amount": float(actual_order_amount) } } # print(json.dumps(data)) return json.dumps(brushing_data) else: logger.info('支付失败!') self.driver.save_screenshot('PayFailed.png') logger.info('支付失败的url:%s' % self.driver.current_url) #新增刷单操作日志 data = { "task_id": self.task_id, "info": "支付失败!导致下单失败!", 'ip': self.get_ip_info(proxies={'https': self.proxy}) } self.create_task_order_log(json.dumps(data))