class TaoBaoStartRequest(object):
    """
    使用selenium+chrome模拟登陆淘宝
    采取的策略为当当前账号被检测到时,更换账号模拟登陆
    """
    def __init__(self, username, password):
        # 记录对象
        self.record = Record()
        # 手动输入账号密码的登陆界面,登录成功后跳转到搜索页面
        self.url = "https://login.taobao.com/member/login.jhtml?redirectURL=https%3A%2F%2Fwww.taobao.com%2F"
        # 浏览器对象
        self.browser = webdriver.Chrome()
        # 浏览器加载对象
        self.wait = WebDriverWait(self.browser, 20)
        # 淘宝账号
        self.username = username
        # 淘宝登陆密码
        self.password = password

    def login(self):
        """
        请求获取登陆界面,自动化输入账号密码,完成登陆,获取搜索界面
        :return:
        """
        # 删除所有的cookies, 请求获取登录界面
        self.browser.delete_all_cookies()
        self.browser.get(self.url)
        # 转换手动输入账号密码界面
        password_login = self.wait.until(
            EC.presence_of_element_located((By.CLASS_NAME, 'login-switch')))
        if password_login:
            password_login.click()
            time.sleep(1)
        # 获取用户名的输入框
        username = self.wait.until(
            EC.presence_of_element_located((By.ID, 'TPL_username_1')))
        # 获取账号的输入框
        password = self.wait.until(
            EC.presence_of_element_located((By.ID, 'TPL_password_1')))
        # 获取登陆按钮
        submit = self.wait.until(
            EC.element_to_be_clickable((By.ID, 'J_SubmitStatic')))
        # 填写表单内容
        username.send_keys(self.username)
        password.send_keys(self.password)
        time.sleep(1)
        # 提交表单
        submit.click()

    def password_error(self):
        """
        判断是否密码错误
        :return:
        """
        try:
            return WebDriverWait(self.browser, 5).until(
                EC.text_to_be_present_in_element_value(
                    (By.CLASS_NAME, 'error'), '你输入的密码和账户名不匹配'))
        except TimeoutException:
            return False

    def login_successfully(self):
        """
        判断是否登陆成功
        :return:
        """
        try:
            return bool(
                WebDriverWait(self.browser, 5).until(
                    EC.presence_of_element_located(
                        (By.CLASS_NAME, 'site-nav-login-info-nick '))))
        except TimeoutException:
            return False

    def get_input(self, keyword):
        """
        获取搜索框,输入关键字,搜索
        :param keyword:
        :return:
        """
        # 如果登陆成成功
        if self.login_successfully():
            # 获取搜索框
            search_key = self.wait.until(
                EC.presence_of_element_located((By.ID, 'q')))
            # 获取搜索按钮
            # search_click = self.wait.until(EC.presence_of_element_located((By.CLASS_NAME, 'btn-search tb-bg')))
            # 首先清空输入框
            search_key.clear()
            # 填写表单内容
            search_key.send_keys(keyword)
            time.sleep(1)
            # 提交表单
            # search_click.click()
            # 不知道为何搜索按钮就无法获得了,总是报错,故修改成使用键盘 ENTER 键来操作
            search_key.send_keys(Keys.ENTER)
            # 首先判断是否有搜索结果
            if not self.is_result():
                # 获取结果的总页数,使用find_element_by_xpath()也可以
                total = self.wait.until(
                    EC.presence_of_element_located((
                        By.XPATH,
                        '//div[@id="J_relative"]/div/div/div[@class="pager"]/ul/li[2]'
                    ))).text.split("/")[1]
                # 遍历传入页号采集
                for page in range(1, int(total) + 1):
                    try:
                        if page > 1:
                            self.skip_page(page)
                        print("正在采集[%s]关键字的[%s]页" % (keyword, page))
                        # 等待商品信息加载完成
                        self.wait.until(
                            EC.presence_of_element_located(
                                (By.CSS_SELECTOR, '.m-itemlist .items .item')))
                        # 采集搜索的商品信息
                        self.get_products()
                    except TimeoutException:
                        # 增加页面跳转失败时,将当前关键字和页号记录文件
                        self.record.record_breakpoint(keyword, page)
                    except InvalidElementStateException:
                        # 首先刷新页面
                        self.browser.refresh()
                        # 等待商品信息加载完成
                        self.wait.until(
                            EC.presence_of_element_located(
                                (By.CSS_SELECTOR, '.m-itemlist .items .item')))
                        # 采集搜索的商品信息
                        self.get_products()
            else:
                # 没有搜索结果将关键字写入文件
                print("关键字[%s]无搜索结果,写入文件" % keyword)
                self.record.no_search_result(keyword)

    def skip_page(self, num):
        """
        跳转指定的页号
        :param num:
        :return:
        """
        # 跳转页号的输入框
        input_ = self.wait.until(
            EC.presence_of_element_located(
                (By.CSS_SELECTOR, '#mainsrp-pager div.form> input')))
        # 提交按钮
        submit = self.wait.until(
            EC.presence_of_element_located(
                (By.CSS_SELECTOR,
                 '#mainsrp-pager div.form> span.btn.J_Submit')))
        # 清空输入框
        input_.clear()
        # 传入要跳转的页号
        input_.send_keys(num)
        # 提交,跳转
        submit.click()
        # 判断是否跳转成功
        self.wait.until(
            EC.text_to_be_present_in_element(
                (By.CSS_SELECTOR, '#mainsrp-pager li.item.active > span'),
                str(num)))

    def is_result(self):
        """
        判断是否有匹配结果,需要注意的是在捕获异常的时候得是:selenium.common.exceptions import TimeoutException
        如果捕获的是TimeOutError则依然会报错
        这是第一种情况:直接就是无搜索结果
        :return:
        """
        try:
            self.wait.until(
                EC.presence_of_element_located(
                    (By.XPATH, '//div[@id="mainsrp-tips"]//ul')))
            return True
        except TimeoutException:
            return False

    def get_products(self):
        """
        提取商品数据
        :return:
        """
        # 获取加载完成的页面
        html = self.browser.page_source
        # 使用pyquery解析页面
        doc = pq(html)
        # 定位包含商品信息的items
        items = doc('#mainsrp-itemlist .items .item').items()
        # 获取每一个商品项的信息
        for item in items:
            product = {
                'image': item.find('.pic .img').attr('data-src'),
                'price': item.find('.price').text(),
                'deal': item.find('.deal-cnt').text(),
                'title': item.find('.title').text(),
                'product_detail':
                item.find('.title .J_ClickStat').attr('href'),
                'shop': item.find('.shop').text(),
                'shop_detail': item.find('.shop .shopname').attr('href'),
                'location': item.find('.location').text()
            }
            print("查看商品信息:", product)
            # 将数据写入文件
            self.record.record_result(product)
Example #2
0
class TaoBaoStartSearch(object):
    """
    尝试在不登录的情况下直接根据关键字进行搜索
    """
    def __init__(self):
        # 在不登陆的情况下:淘宝的搜索页面
        self.index_url = "https://s.taobao.com/search?q={}"
        # 浏览器对象
        self.browser = webdriver.Chrome()
        # 浏览器加载对象
        self.wait = WebDriverWait(self.browser, 20)
        # 记录对象
        self.record = Record()

    def index_page(self, keyword):
        """
        尝试在不登录的情况下获取搜索数据
        :param keyword:
        :return:
        """
        print("正在抓取的关键字:", keyword)
        # 发起请求
        self.browser.get(self.index_url.format(keyword))
        # 查看响应的页面
        # print("查看获取的响应页面:", self.browser.page_source)
        # 首先判断是否有搜索结果
        if not self.is_result():
            # 获取结果的总页数,使用find_element_by_xpath()也可以
            total = self.wait.until(
                EC.presence_of_element_located((
                    By.XPATH,
                    '//div[@id="J_relative"]/div/div/div[@class="pager"]/ul/li[2]'
                ))).text.split("/")[1]
            # 遍历传入页号采集
            for page in range(1, int(total) + 1):
                try:
                    if page > 1:
                        self.skip_page(page)
                    print("正在采集[%s]关键字的[%s]页" % (keyword, page))
                    # 等待商品信息加载完成
                    self.wait.until(
                        EC.presence_of_element_located(
                            (By.CSS_SELECTOR, '.m-itemlist .items .item')))
                    # 采集搜索的商品信息
                    self.get_products()
                except TimeoutException:
                    # 增加页面跳转失败时,将当前关键字和页号记录文件
                    self.record.record_breakpoint(keyword, page)
                except InvalidElementStateException:
                    # 首先刷新页面
                    self.browser.refresh()
                    # 等待商品信息加载完成
                    self.wait.until(
                        EC.presence_of_element_located(
                            (By.CSS_SELECTOR, '.m-itemlist .items .item')))
                    # 采集搜索的商品信息
                    self.get_products()
        else:
            # 没有搜索结果将关键字写入文件
            print("关键字[%s]无搜索结果,写入文件" % keyword)
            self.record.no_search_result(keyword)

    def skip_page(self, num):
        """
        跳转指定的页号
        :param num:
        :return:
        """
        # 跳转页号的输入框
        input_ = self.wait.until(
            EC.presence_of_element_located(
                (By.CSS_SELECTOR, '#mainsrp-pager div.form> input')))
        # 提交按钮
        submit = self.wait.until(
            EC.presence_of_element_located(
                (By.CSS_SELECTOR,
                 '#mainsrp-pager div.form> span.btn.J_Submit')))
        # 清空输入框
        input_.clear()
        # 传入要跳转的页号
        input_.send_keys(num)
        # 提交,跳转
        submit.click()
        # 判断是否跳转成功
        self.wait.until(
            EC.text_to_be_present_in_element(
                (By.CSS_SELECTOR, '#mainsrp-pager li.item.active > span'),
                str(num)))

    def is_result(self):
        """
        判断是否有匹配结果,需要注意的是在捕获异常的时候得是:selenium.common.exceptions import TimeoutException
        如果捕获的是TimeOutError则依然会报错
        这是第一种情况:直接就是无搜索结果
        :return:
        """
        try:
            self.wait.until(
                EC.presence_of_element_located(
                    (By.XPATH, '//div[@id="mainsrp-tips"]//ul')))
            return True
        except TimeoutException:
            return False

    def get_products(self):
        """
        提取商品数据
        :return:
        """
        # 获取加载完成的页面
        html = self.browser.page_source
        # 使用pyquery解析页面
        doc = pq(html)
        # 定位包含商品信息的items
        items = doc('#mainsrp-itemlist .items .item').items()
        # 获取每一个商品项的信息
        for item in items:
            product = {
                'image': item.find('.pic .img').attr('data-src'),
                'price': item.find('.price').text(),
                'deal': item.find('.deal-cnt').text(),
                'title': item.find('.title').text(),
                'product_detail':
                item.find('.title .J_ClickStat').attr('href'),
                'shop': item.find('.shop').text(),
                'shop_detail': item.find('.shop .shopname').attr('href'),
                'location': item.find('.location').text()
            }
            print("查看商品信息:", product)
            # 将数据写入文件
            self.record.record_result(product)