暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

python_自动化测试框架

老柴杂货铺 2025-03-14
130

有很多网站,例如淘宝,它上面的很多页面 的数据是由JavaScript生成的,而不是原始HTML代码,而且还有很多ajax获取的数据,甚至有些数据是加密的。当我们使用普通的requests来处理时,需要分析很多的js代码,此时非常困难,所以我们就用selenium来解决。

selenium框架的简单介绍

selenium是一个Web的自动化测试工具,最初是为网站自动化测试而开发的,利用它可以控制浏览器执行特定的动作,例如点击、下拉、输入内容等

selenium文档地址:https://selenium-python.readthedocs.io/

一、环境配置
安装命令:
    # 在安装过程中最好限定框架版本为4.9.1
    pip install selenium==4.9.1 -i https://pypi.tuna.tsinghua.edu.cn/simple

    安装完selenium后,还需要安装使用selenium控制的浏览器需要的驱动。

    谷歌驱动下载地址:https://googlechromelabs.github.io/chrome-for-testing/#stable

    驱动下载完成后将文件移动到系统环境变量中:

    ● MacOS:将文件移动到/usr/local/bin目录

    ● Windows:将文件移动到miniconda3安装目录

    编写以下代码,验证是否能正常运行:

      from selenium import webdriver
      browser = webdriver.Chrome()

      如果可以正常打开浏览器则配置成功。

      除了可以配置谷歌浏览器之外也可以配置火狐浏览器,配置方式与谷歌浏览器大致相同。

      火狐驱动下载地址:https://github.com/mozilla/geckodriver/releases

      二、基本使用
      加载网页
        from selenium import webdriver
        # 获取要操作的浏览器驱动对象(直白点说,这个对象可以控制浏览器)
        browser = webdriver.Chrome()
        # 加载指定的页面
        browser.get("http://www.baidu.com")
        # 截屏
        browser.save_screenshot("百度首页.png")
        定位与操作
          import time
          from selenium import webdriver
          from selenium.webdriver.common.by import By




          # 获取要操作的浏览器驱动对象
          browser = webdriver.Chrome()


          # 加载指定的页面
          browser.get("http://www.baidu.com")


          # 获取指定的元素
          browser.find_element(By.ID, 'kw').send_keys('java')


          # 延时,以便看清楚要进行的操作
          time.sleep(2)


          # 点击 "百度一下"
          browser.find_element(By.ID, 'su').click()
          查看响应信息
            import time
            from selenium import webdriver


            # 获取要操作的浏览器驱动对象
            browser = webdriver.Chrome()


            # 加载指定的页面
            browser.get("http://www.baidu.com")


            # 查看访问的页面源代码
            print(browser.page_source)


            # 查看cookie
            print(browser.get_cookies())


            # 查看经过处理之后,本页面最后显示的url,如果有302的话,那么就是302之后的url
            print(browser.current_url)
            打开新页面
              import time
              from selenium import webdriver


              # 创建浏览器
              browser = webdriver.Chrome()


              # 打开百度
              browser.get("http://www.baidu.com")


              time.sleep(3)


              # 打开京东
              browser.get("https://jd.com")
              time.sleep(3)


              # 关闭
              browser.close()
              通过js脚本打开新标签页
                import time
                from selenium import webdriver




                browser = webdriver.Chrome()


                # 打开淘宝
                browser.get("http://login.taobao.com")


                time.sleep(3)


                # 打开搜狗: 执行js脚本打开新的标签页
                js = "window.open('http://www.sogou.com')"
                browser.execute_script(js)
                切换标签页
                  import time
                  from selenium import webdriver




                  browser = webdriver.Chrome()


                  # 打开淘宝
                  browser.get("http://login.taobao.com")


                  time.sleep(3)


                  # 打开搜狗
                  js = "window.open('http://www.sogou.com')"
                  browser.execute_script(js)


                  time.sleep(3)


                  # 切换到第1个标签页
                  browser.switch_to.window(browser.window_handles[0])
                  time.sleep(1)


                  browser.switch_to.window(browser.window_handles[1])
                  time.sleep(1)


                  # 关闭第2个标签页
                  browser.close()


                  time.sleep(1)


                  # 切换到第1个标签页
                  browser.switch_to.window(browser.window_handles[0])
                  # 关闭第1个标签页
                  browser.close()
                  退出
                    import time
                    from selenium import webdriver




                    # 获取要操作的浏览器驱动对象
                    browser = webdriver.Chrome()


                    # 加载指定的页面
                    browser.get("http://www.baidu.com")


                    # 为了演示,浏览器打开后关闭的效果,要先延时一会
                    time.sleep(3)


                    # 关闭当前页面(当浏览器只有1个页面时,此操作会让浏览器退出)
                    browser.close()


                    # 让浏览器退出(如果用selenium打开了很多标签页的情况下)
                    browser.quit()

                    多个标签页切换顺序混乱的问题

                    window_handles列表保存了根据顺序打开的标签页句柄,但是在某些特殊的情况下标签页顺序和列表句柄元素顺序不一致,比如网络速度或页面响应速度的不同会导致实际打开页面的顺序和预期不同。所以在代码中不能完全依赖列表索引的方式完成页面切换。

                    解决方式如下:

                      import time
                      from selenium import webdriver




                      browser = webdriver.Chrome()


                      # 打开淘宝
                      browser.get("http://login.taobao.com")
                      time.sleep(3)


                      # 打开搜狗
                      js = "window.open('http://www.sogou.com')"
                      browser.execute_script(js)
                      time.sleep(3)


                      # 打开必应
                      js = "window.open('http://www.bing.com')"
                      browser.execute_script(js)
                      time.sleep(3)


                      # 打印当前所有标签页的窗口句柄
                      print(browser.window_handles)


                      # 打印所有句柄对应的标签页名称
                      for handle in browser.window_handles:
                          browser.switch_to.window(handle)
                          print("句柄: {},页面标题: {}".format(handle, browser.title))




                      for handle in browser.window_handles:
                          browser.switch_to.window(handle)
                          # 通过页面标题或URL来定位
                          if ("搜狗" in browser.title) or ("sogou.com" in browser.current_url):
                              print("已切换到搜狗页面:", handle)
                              time.sleep(2)
                              browser.close()  # 关闭搜狗标签页
                          elif ("必应" in browser.title) or ("bing.com" in browser.current_url):
                              print("已切换到必应页面:", handle)
                              time.sleep(2)
                          else:
                              print('已切换到淘宝页面:', handle)
                              time.sleep(2)


                      print(browser.window_handles)
                      browser.quit()
                      三、元素定位方法

                      元素定位的基本使用方式 

                      在定位元素时,需要借助selenium框架提供的定位工具来进行元素定位。元素定位工具导入路径如下:

                        from selenium.webdriver.common.by import By

                        为了能够点击某个按钮,此时我们就需要准确无误地定位到需要的元素。元素定位主要分为以下两种:

                        ● 单个节点(返回是一个对象) 

                          ○ find_element(By.ID, '定位规则')

                          ○ find_element(By.NAME, '定位规则')

                          ○ find_element(By.XPATH, '定位规则')

                          ○ find_element(By.LINK_TEXT, '定位规则')

                          ○ find_element(By.PARTIAL_LINK_TEXT, '定位规则')

                          ○ find_element(By.TAG_NAME, '定位规则')

                          ○ find_element(By.CLASS_NAME, '定位规则')

                          ○ find_element(By.CSS_SELECTOR, '定位规则')

                        ● 多个节点(返回是一个列表) 

                          ○ find_elements(By.ID, '定位规则')

                          ○ find_elements(By.NAME, '定位规则')

                          ○ find_elements(By.XPATH, '定位规则')

                          ○ find_elements(By.LINK_TEXT, '定位规则')

                          ○ find_elements(By.PARTIAL_LINK_TEXT, '定位规则')

                          ○ find_elements(By.TAG_NAME, '定位规则')

                          ○ find_elements(By.CLASS_NAME, '定位规则')

                          ○ find_elements(By.CSS_SELECTOR, '定位规则')

                        案例:获取单个节点

                          import time
                          from selenium import webdriver
                          from selenium.webdriver.common.by import By


                          # 获取浏览器驱动对象
                          browser = webdriver.Chrome()


                          # 打开指定URL
                          browser.get('http://news.baidu.com/')


                          # 定位搜索框
                          ret = browser.find_element(By.ID, 'ww')
                          # ret = browser.find_element(By.CSS_SELECTOR, '#ww')  # 查询id为ww
                          # ret = browser.find_element(By.CSS_SELECTOR, '.word')  # 查询class为word
                          # ret = browser.find_element(By.XPATH, "//input[@class='word']")
                          print(ret)


                          time.sleep(3)
                          browser.quit()
                          案例:获取多个节点
                            import time
                            from selenium import webdriver
                            from selenium.webdriver.common.by import By




                            # 获取浏览器驱动对象
                            browser = webdriver.Chrome()


                            # 打开指定URL
                            browser.get('https://movie.douban.com/top250')


                            # 定位25个电影信息
                            ret = browser.find_elements(By.CSS_SELECTOR, '.item')  # 查询class为item
                            print(ret)


                            ret = browser.find_elements(By.XPATH, "//*[@class='item']")
                            print(ret)


                            time.sleep(3)
                            browser.quit()

                            注意点

                            find_element和find_elements的区别是:前者返回一个对象,后者返回一个列表

                            by_link_text和by_partial_link_text的区别:前者匹配全部文本,后者包含某个文本

                            四、selenium框架的其他方法

                            提取标签内容与属性值

                            find_element仅仅能够获取元素,不能够直接获取其中的数据,如果需要获取数据需要使用以下方法:

                            ● 获取文本:element.text

                            ● 获取属性值:element.get_attribute("href")

                              import time
                              from selenium import webdriver
                              from selenium.webdriver.common.by import By




                              # 获取浏览器驱动对象
                              browser = webdriver.Chrome()


                              # 打开指定URL
                              browser.get('https://www.douban.com')


                              # 定位h1标签
                              ret = browser.find_elements(By.TAG_NAME, "h1")
                              print(ret[0].text)
                              # 输出:豆瓣


                              ret = browser.find_elements(By.LINK_TEXT, "下载豆瓣 App")
                              print(ret[0].get_attribute("href"))
                              # 输出:https://www.douban.com/doubanapp/app?channel=nimingye


                              time.sleep(3)
                              browser.quit()

                              处理cookie

                              通过driver.get_cookies()能够获取所有的cookie

                              cookie转dict

                                from selenium import webdriver


                                browser = webdriver.Chrome()
                                browser.get("http://www.baidu.com")


                                cookie_list = browser.get_cookies()
                                print(cookie_list)


                                # 整理为requests等需要的字典方式,因为浏览器在发送新请求时携带的cookie只有name、value
                                # 所以此时提取的也只有name、value,其他的不需要
                                cookie_dict = {x["name"]: x["value"for x in cookie_list}
                                print(cookie_dict)


                                # 关闭页面
                                browser.close()
                                删除cookie
                                  # 删除一条cookie
                                  browser.delete_cookie("CookieName")
                                  # 删除所有的cookie
                                  browser.delete_all_cookies()

                                  添加cookie

                                  注意点:添加的字段必须包含name和value,name是cookie信息中的键,value是cookie中的值

                                    # 添加cookie与获取指定cookie
                                    from selenium import webdriver




                                    browser = webdriver.Chrome()
                                    browser.get('https://www.baidu.com')


                                    browser.add_cookie({'name''username''value''安娜'})
                                    browser.add_cookie({'name''gender''value''女'})


                                    cookie_list = browser.get_cookies()


                                    cookie_dict = {x["name"]: x["value"for x in cookie_list}
                                    print(cookie_dict)


                                    print(browser.get_cookie('username'))  # 获取指定cookie
                                    print(browser.get_cookie('gender'))


                                    browser.quit()

                                    页面等待

                                    如果网站采用了动态html技术,那么页面上的部分元素出现时间便不能确定,这个时候就可以设置一个等待时间,强制要求在时间内出现,否则报错。

                                    获取京东网站的搜索输入框

                                    presence_of_element_located:判定符合查询条件的一个元素是否存在

                                    presence_of_elements_located:判断符合查询条件的所有元素是否存在

                                      import time
                                      from selenium import webdriver
                                      from selenium.webdriver.common.by import By
                                      from selenium.webdriver.support.ui import WebDriverWait
                                      from selenium.webdriver.support import expected_conditions as EC


                                      # 创建浏览器驱动对象
                                      browser = webdriver.Chrome()
                                      # 窗口最大化: 保证页面元素不会被其他元素遮挡
                                      browser.maximize_window()


                                      # 创建等待操作对象
                                      wait_ob = WebDriverWait(browser, 10)


                                      # 加载url
                                      browser.get("http://jd.com")


                                      # 等待条件满足
                                      search_input = wait_ob.until(EC.presence_of_element_located((By.ID, 'key')))
                                      # 输入内容
                                      search_input.send_keys("Mac Pro")


                                      # 点击查询
                                      search_button = wait_ob.until(EC.presence_of_element_located((By.XPATH, '//*[@id="search"]/div/div[2]/button')))
                                      search_button.click()


                                      # 延时等待以便于观察页面变化
                                      time.sleep(10)
                                      # 退出
                                      browser.quit()


                                      页面的前进与后退

                                        import time
                                        from selenium import webdriver




                                        browser = webdriver.Chrome()
                                        browser.get("http://jd.com")


                                        time.sleep(2)
                                        browser.get("http://ganji.com")
                                        time.sleep(2)


                                        # 后退
                                        browser.back()
                                        time.sleep(1)


                                        # 前进
                                        browser.forward()


                                        time.sleep(1)
                                        browser.quit()

                                        动作链

                                        在selenium中,动作链是一种用于模拟用户交互的技术。它允许你执行一系列连续的动作,例如鼠标移动、鼠标点击、按键操作等。通过使用动作链,你可以模拟用户在网页上的复杂交互操作,例如拖拽元素、悬停、双击等。

                                          from selenium import webdriver
                                          from selenium.webdriver.common.by import By
                                          from selenium.webdriver import ActionChains


                                          browser = webdriver.Chrome()
                                          url = 'http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable'
                                          browser.get(url)


                                          log = browser.find_element(By.XPATH'//div[@id="iframewrapper"]/iframe')
                                          browser.switch_to.frame(log)
                                          source = browser.find_element(By.CSS_SELECTOR'#draggable')
                                          target = browser.find_element(By.CSS_SELECTOR'#droppable')


                                          actions = ActionChains(browser)
                                          actions.drag_and_drop(source, target)
                                          actions.perform()

                                          案例:登录网易邮箱

                                            import time
                                            from selenium import webdriver
                                            from selenium.webdriver.common.by import By




                                            class WyMail:
                                                def __init__(self):
                                                    self.driver = webdriver.Chrome()


                                                def open_email(self, url):
                                                    self.driver.get(url)
                                                    time.sleep(1)


                                                def login_email(self, email, password):
                                                    iframe = self.driver.find_element(By.XPATH, '//div[@id="loginDiv"]/iframe[@scrolling = "no"]')


                                                    # 登录表单为一个子页面, 需要切入到当前这个子页面中
                                                    self.driver.switch_to.frame(iframe)


                                                    self.driver.find_element(By.XPATH, '//input[@name="email"]').send_keys(email)
                                                    self.driver.find_element(By.XPATH, '//div[@class="u-input box"]//input[@name="password"]').send_keys(password)


                                                    self.driver.find_element(By.XPATH, './/*[@id="dologin"]').click()


                                                def close(self):
                                                    time.sleep(10)
                                                    self.driver.quit()




                                            if __name__ == '__main__':
                                                email = WyMail()
                                                email.open_email('https://mail.163.com/')
                                                email.login_email('wt_poppies@163.com''wt199486')
                                                email.close()

                                            页面滚动

                                            大部分网站数据是动态数据,需要触发ajax请求后才能在页面中进行数据渲染,触发ajax请求的方式之一就是页面滑动,例如爱奇艺、今日头条等网站。

                                              import time
                                              from selenium import webdriver




                                              browser = webdriver.Chrome()
                                              browser.get('https://36kr.com/')




                                              for num in range(110):
                                                  # 绝对位置
                                                  # browser.execute_script(f'window.scrollTo(0, {num * 700})')


                                                  # 相对位置
                                                  browser.execute_script(f'window.scrollBy(0, {num * 700})')
                                                  time.sleep(1)

                                              绕过检测

                                              在一些网站当中有专门对浏览器驱动程序进行检测,例如:https://bot.sannysoft.com/

                                              我们可以谷歌浏览器配置项来隐藏浏览器驱动信息,代码如下:

                                                import time
                                                from selenium import webdriver




                                                # 创建浏览器配置对象
                                                options = webdriver.ChromeOptions()
                                                options.add_argument('--disable-blink-features=AutomationControlled')


                                                browser = webdriver.Chrome(options=options)


                                                browser.get('https://bot.sannysoft.com/')
                                                time.sleep(10)
                                                browser.quit()
                                                浏览器信息配置
                                                  import time
                                                  from selenium import webdriver




                                                  # 浏览器配置加载
                                                  options = webdriver.ChromeOptions()


                                                  # 禁止图片加载
                                                  prefs = {"profile.managed_default_content_settings.images"2}
                                                  options.add_experimental_option('prefs', prefs)


                                                  # 设置UA
                                                  user_agent = 'abc'
                                                  options.add_argument(f'user-agent={user_agent}')


                                                  # 隐藏开发者警告
                                                  options.add_experimental_option('useAutomationExtension'False)
                                                  options.add_experimental_option('excludeSwitches', ['enable-automation'])


                                                  # 设置代理
                                                  options.add_argument("--proxy-server=http://127.0.0.1:7890")




                                                  # 初始化浏览器对象并加载自定义配置
                                                  browser = webdriver.Chrome(options=options)
                                                  browser.get('https://www.baidu.com')


                                                  # 程序休眠以便观察浏览器中的参数设置
                                                  time.sleep(100)

                                                  selenium中的异常处理

                                                  在selenium框架中自定义了一些异常类,可以使用框架定义的异常类进行异常捕获。

                                                    from selenium import webdriver
                                                    from selenium.webdriver.common.by import By
                                                    from selenium.common.exceptions import NoSuchElementException


                                                    browser = webdriver.Chrome()


                                                    try:
                                                        browser.find_element(By.ID, 'hello')
                                                    except NoSuchElementException:
                                                        print('No Element')
                                                    finally:
                                                        browser.close()
                                                    五、项目实战
                                                    案例:唯品会商品数据抓取
                                                      import time
                                                      from random import randint
                                                      from pymongo import MongoClient
                                                      from selenium import webdriver
                                                      from selenium.webdriver.common.by import By
                                                      from selenium.common.exceptions import NoSuchElementException




                                                      class WpShop:
                                                          mongo_client = MongoClient()
                                                          collection = mongo_client['py_spider']['wp_shop']


                                                          # 创建浏览器配置对象
                                                          options = webdriver.ChromeOptions()
                                                          # 屏蔽图片
                                                          prefs = {"profile.managed_default_content_settings.images"2}
                                                          options.add_experimental_option('prefs', prefs)


                                                          # 驱动配置
                                                          browser = webdriver.Chrome(options=options)


                                                          # cookies信息
                                                          cookies = {
                                                              "mars_cid""1730106769949_4ed705c897904ab6da6ed2df7c05b3fe",
                                                              "mars_pid""0",
                                                              "vip_address""%257B%2522pid%2522%253A%2522104103%2522%252C%2522cid%2522%253A%2522104103101%2522%252C%2522pname%2522%253A%2522%255Cu6e56%255Cu5357%255Cu7701%2522%252C%2522cname%2522%253A%2522%255Cu957f%255Cu6c99%255Cu5e02%2522%257D",
                                                              "vip_province""104103",
                                                              "vip_province_name""%E6%B9%96%E5%8D%97%E7%9C%81",
                                                              "vip_city_name""%E9%95%BF%E6%B2%99%E5%B8%82",
                                                              "vip_city_code""104103101",
                                                              "vip_wh""VIP_HZ",
                                                              "smidV2""20241028171250025f8fa5509f7d38e275ae812288691700fc76827844722a0",
                                                              "VipRUID""469642189",
                                                              "VipUID""b4fcb7035781600c26fa0fd1f5ce4581",
                                                              "VipRNAME""ph_*****************************739",
                                                              "pc_fdc_area_id""104103101",
                                                              "pc_fdc_source_ip""1",
                                                              "VipDFT""0",
                                                              "vip_ipver""31",
                                                              "user_class""b",
                                                              "VipUINFO""luc%3Ab%7Csuc%3Ab%7Cbct%3Ac_new%7Chct%3Ac_new%7Cbdts%3A0%7Cbcts%3A0%7Ckfts%3A0%7Cc10%3A0%7Crcabt%3A0%7Cp2%3A0%7Cp3%3A1%7Cp4%3A0%7Cp5%3A1%7Cul%3A3105",
                                                              "mst_area_code""104104",
                                                              "visit_id""E126929EE78BFFA527BA00E1DF14EADE",
                                                              "VIP_QR_FIRST""1",
                                                              "vip_access_times""%7B%22list%22%3A4%7D",
                                                              "vipshop_passport_src""https%3A%2F%2Fcategory.vip.com%2Fsuggest.php%3Fkeyword%3D%25E7%2594%25B5%25E8%2584%2591%26ff%3D235%257C12%257C1%257C1%26tfs_url%3D%252F%252Fmapi-pc.vip.com%252Fvips-mobile%252Frest%252Fshopping%252Fpc%252Fsearch%252Fproduct%252Frank",
                                                              "_jzqco""%7C%7C%7C%7C%7C1.132200.1730106770684.1733379498656.1733899693050.1733379498656.1733899693050.0.0.0.5.5",
                                                              "PASSPORT_ACCESS_TOKEN""A1E6FBB16FE08B779FBC0584A6E6BFB6C216BCA5",
                                                              "VipLID""0%7C1733899726%7C36a609",
                                                              "VipDegree""D1",
                                                              "mars_sid""003a0190be16c7096355fdc127695897",
                                                              "sfl_d""0",
                                                              ".thumbcache_f65dad1092aa9e66c73b4823b4493a2f""XyVkJWUOgfG07LTNryoorllgUzp645alot0AsbsCnY2tLH7/WmW5mimEiatW/KXMZcGu4Wavdc6BbnbmKtPjgw%3D%3D",
                                                              "tfs_fp_token""BXyVkJWUOgfG07LTNryoorllgUzp645alot0AsbsCnY2tLH7/WmW5mimEiatW/KXMZcGu4Wavdc6BbnbmKtPjgw%3D%3D",
                                                              "tfs_fp_timestamp""1733900421487",
                                                              "pg_session_no""1",
                                                              "vip_tracker_source_from""",
                                                              "waitlist""%7B%22pollingId%22%3A%22BEBAB3CA-A350-4F61-B240-E50056DA4087%22%2C%22pollingStamp%22%3A1733900428480%7D"
                                                          }


                                                          # 发送请求
                                                          @classmethod
                                                          def base(cls):
                                                              cls.browser.get('https://category.vip.com/suggest.php?keyword=%E7%94%B5%E8%84%91&ff=235|12|1|1')
                                                              for key, value in cls.cookies.items():
                                                                  cookie_dict = {'name': key, 'value': value}
                                                                  cls.browser.add_cookie(cookie_dict)


                                                              # 页面刷新
                                                              cls.browser.refresh()
                                                              time.sleep(randint(13))


                                                          # 页面滚动
                                                          @classmethod
                                                          def drop_down(cls):
                                                              for i in range(112):
                                                                  js_code = f'document.documentElement.scrollTop = {i * 1000}'
                                                                  cls.browser.execute_script(js_code)
                                                                  time.sleep(randint(12))


                                                          # 数据提取
                                                          @classmethod
                                                          def parse_data(cls):
                                                              cls.drop_down()
                                                              div_list = cls.browser.find_elements(
                                                                  By.XPATH,
                                                                  '//section[@id="J_searchCatList"]/div[@class="c-goods-item  J-goods-item c-goods-item--auto-width"]'
                                                              )


                                                              for div in div_list:
                                                                  price = div.find_element(
                                                                      By.XPATH,
                                                                      './/div[@class="c-goods-item__sale-price J-goods-item__sale-price"]'
                                                                  ).text


                                                                  title = div.find_element(
                                                                      By.XPATH,
                                                                      './/div[2]/div[2]'
                                                                  ).text


                                                                  item = {
                                                                      'title': title,
                                                                      'price': price
                                                                  }
                                                                  print(item)
                                                                  cls.save_mongo(item)
                                                              cls.next_page()  # 当前页面获取完成之后需要点击下一页


                                                          # 数据保存
                                                          @classmethod
                                                          def save_mongo(cls, item):
                                                              cls.collection.insert_one(item)


                                                          # 翻页
                                                          @classmethod
                                                          def next_page(cls):
                                                              try:
                                                                  next_button = cls.browser.find_element(By.XPATH, '//*[@id="J_nextPage_link"]')
                                                                  if next_button:
                                                                      next_button.click()
                                                                      cls.parse_data()  # 进入到下一页需要重新解析页面数据
                                                                  else:
                                                                      cls.browser.close()
                                                              except NoSuchElementException:
                                                                  print('最后一页...')
                                                                  cls.browser.quit()


                                                          # 启动函数
                                                          @classmethod
                                                          def main(cls):
                                                              cls.base()
                                                              cls.parse_data()




                                                      if __name__ == '__main__':
                                                          WpShop.main()


                                                      六、补充 - DrissionPage框架
                                                      DrissionPage:让网页自动化变得如此简单

                                                      DrissionPage与之前学习的Selenium大致相同,也是一个基于Python的页面自动化工具。区别在于DrissionPage既可以控制浏览器也能收发数据包,将两者功能合二为一。功能相对Selenium更强大,语法也更加简洁优雅,具有Selenium基础之后再学习DrissionPage也会更加简单。

                                                      官网地址:https://www.drissionpage.cn/


                                                      环境安装

                                                      操作系统:Windows、Linux和Mac。

                                                      Python版本:3.6及以上

                                                      支持浏览器:Chromium内核(如Chrome和Edge)

                                                        pip install DrissionPage

                                                        标签定位

                                                        本小节中主要学习如何创建浏览器对象并使用浏览器对象的内置方法完成网站访问以及元素定位。

                                                        ele:定位符合条件的单个元素(支持xpath定位以及选择器定位,可以设定timeout超时时间)

                                                        官网参数说明:https://www.drissionpage.cn/browser_control/get_elements/find_in_object/#-ele

                                                          import time
                                                          from DrissionPage.common import By
                                                          from DrissionPage import ChromiumPage




                                                          # 1.创建浏览器对象并访问百度首页
                                                          page = ChromiumPage()
                                                          page.get('https://www.baidu.com')


                                                          # 2.浏览器最大化
                                                          page.set.window.max()


                                                          # 3.输入搜索内容
                                                          # page.ele('xpath://input[@id="kw"]').input('jk')
                                                          # page.ele('xpath://input[@id="su"]').click()


                                                          page.ele((By.XPATH, '//input[@id="kw"]')).input('jk')
                                                          page.ele((By.XPATH, '//input[@id="su"]')).click()


                                                          time.sleep(5)


                                                          # 4.关闭浏览器
                                                          page.quit()

                                                          标签等待

                                                          本小节主要学习page对象中的eles_loaded方法,用于等待某一个元素或所有元素是否载入到页面中

                                                          官网参数说明:https://www.drissionpage.cn/browser_control/waiting/#-waiteles_loaded

                                                            from DrissionPage import ChromiumPage


                                                            page = ChromiumPage()
                                                            page.get('https://www.baidu.com')
                                                            flag = page.wait.eles_loaded('xpath://input[@id="su"]', timeout=2)
                                                            print(flag)


                                                            page.quit()

                                                            多标签定位

                                                            本小节主要学习eles方法定位多标签以及如何使用ele eles对象完成文本数据提取以及属性值的提取

                                                            eles:定位符合条件的多个元素,返回值类型为列表

                                                            官网参数说明:https://www.drissionpage.cn/browser_control/get_elements/find_in_object/#-eles

                                                              from DrissionPage import ChromiumPage


                                                              page = ChromiumPage()
                                                              page.get('https://movie.douban.com/top250')
                                                              div_list = page.eles("xpath://ol[@class='grid_view']/li/div[@class='item']")


                                                              for item in div_list:
                                                                  item_dict = dict()
                                                                  movie_name = item.ele('xpath:./div[@class="info"]/div[@class="hd"]//span[1]').text


                                                                  movie_image = item.ele('xpath:./div[@class="pic"]/a').attr('href')
                                                                  """
                                                                  attr: 获取指定的属性值
                                                                  attrs: 获取当前标签中的所有属性与值, 返回的数据类型为字典
                                                                  详情: https://www.drissionpage.cn/SessionPage/get_ele_info/#%EF%B8%8F%EF%B8%8F-attrs
                                                                  """
                                                                  # movie_attr = item.ele('xpath:./div[@class="pic"]/a').attrs


                                                                  print(movie_name, movie_image)


                                                              page.quit()


                                                              子页面切换

                                                              在Selenium中如果需要控制iframe标签中的内容则需要使用switch_to.frame方法,DrissionPage无需操作。

                                                              DrissionPage也可以单独对iframe进行操作:https://www.drissionpage.cn/browser_control/iframe

                                                                import time
                                                                from DrissionPage.common import By
                                                                from DrissionPage import ChromiumPage




                                                                page = ChromiumPage()
                                                                page.get('https://www.douban.com')


                                                                page.ele((By.CLASS_NAME, 'account-tab-account')).click()
                                                                page.ele((By.ID, 'username')).input('admin')
                                                                page.ele((By.ID, 'password')).input('admin123')


                                                                time.sleep(3)
                                                                page.quit()
                                                                163邮箱登录.py
                                                                  import time
                                                                  from DrissionPage import ChromiumPage




                                                                  class MyEmail:
                                                                      def __init__(self):
                                                                          self.page = ChromiumPage()
                                                                          self.url = 'https://mail.163.com/'


                                                                      def login_email(self, email, password):
                                                                          self.page.get(self.url)
                                                                          self.page.ele('xpath://input[@name="email"]').input(email)
                                                                          self.page.ele('xpath://div[@class="u-input box"]//input[@name="password"]').input(password)
                                                                          self.page.ele('xpath://*[@id="dologin"]').click()
                                                                          time.sleep(10)
                                                                          self.page.quit()




                                                                  if __name__ == '__main__':
                                                                      my_email = MyEmail()
                                                                      my_email.login_email('admnin@163.com''admin123')


                                                                  接口监听

                                                                  本小节主要学习如何使用DrissionPage监听指定的api接口并直接获取接口中的数据

                                                                  page.listen.start('接口地址'):启动监听器

                                                                  page.listen.steps(count=你要获取的数据包总数):返回一个可迭代对象,用于for循环,每次循环可从中获取到数据包

                                                                  <DataPacket>.response.body:获取数据包中的数据

                                                                  网站请求地址:http://www.ccgp-hunan.gov.cn/page/content/more.jsp?column_code=2

                                                                  官网参数说明:https://www.drissionpage.cn/browser_control/listener/#-listenstart

                                                                    from DrissionPage.common import By
                                                                    from DrissionPage import ChromiumPage


                                                                    page = ChromiumPage()
                                                                    url = 'http://www.ccgp-hunan.gov.cn/page/content/more.jsp?column_code=2'


                                                                    # api监听: 先监听再请求
                                                                    page.listen.start('/mvc/getContentList.do')
                                                                    page.get(url)


                                                                    # 获取api返回的数据(page.listen.steps(): 返回的是一个迭代器)
                                                                    # print(page.listen.steps())


                                                                    # 循环获取数据(count: 监听次数)
                                                                    page_num = 1
                                                                    for item in page.listen.steps(count=8):
                                                                        # 打印监听后返回的对象
                                                                        # print(item)


                                                                        # 打印数据
                                                                        print(f'第{page_num}页(数据类型[{type(item.response.body[0])}]):', item.response.body)


                                                                        # 下一页
                                                                        flag = page.ele((By.LINK_TEXT, '下一页'), timeout=3)
                                                                        if flag:
                                                                            flag.click()
                                                                        else:
                                                                            print('翻页结束...')
                                                                            page.quit()
                                                                            break
                                                                        page_num += 1

                                                                    动作链

                                                                    本小节主要学习actions动作链对象所提供的内置方法

                                                                    官网内置方法说明:https://www.drissionpage.cn/browser_control/actions/#%EF%B8%8F-%E4%BD%BF%E7%94%A8%E6%96%B9%E6%B3%95

                                                                      import time
                                                                      from DrissionPage.common import By
                                                                      from DrissionPage import ChromiumPage




                                                                      page = ChromiumPage()
                                                                      url = 'http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable'
                                                                      page.get(url)


                                                                      source = page.ele((By.ID'draggable'))
                                                                      target = page.ele((By.ID'droppable'))


                                                                      page.actions.hold(source).release(target)
                                                                      time.sleep(2)
                                                                      page.quit()
                                                                      验证码滑动测试.py
                                                                        import time
                                                                        from DrissionPage.common import By
                                                                        from DrissionPage import ChromiumPage


                                                                        url = 'https://ynjzjgcx.com/dataPub/enterprise'
                                                                        page = ChromiumPage()
                                                                        page.get(url)


                                                                        # 定位滑动控件并选中控件
                                                                        button = page.ele((By.CLASS_NAME, 'slide-verify-slider-mask-item'))
                                                                        page.actions.hold(button)


                                                                        # 向右移动指定的像素位并释放
                                                                        page.actions.right(150).release()


                                                                        time.sleep(3)
                                                                        page.quit()


                                                                        """
                                                                        绕过验证码需要专门学习ocr图像识别库
                                                                        """

                                                                        SessionPage的使用

                                                                        SessionPage基于requests进行网络连接,因此可使用requests内置的所有请求方式,包括get()、post()、head()、options()、put()、patch()、delete()。

                                                                        官网内置方法说明:https://www.drissionpage.cn/SessionPage/visit/

                                                                          from DrissionPage import SessionPage


                                                                          url = 'http://www.ccgp-hunan.gov.cn/mvc/getContentList.do'
                                                                          form_data = {
                                                                              'column_code'2,
                                                                              'title''',
                                                                              'pub_time1''',
                                                                              'pub_time2''',
                                                                              'own_org'1,
                                                                              'page'1,
                                                                              'pageSize'18
                                                                          }


                                                                          page = SessionPage()
                                                                          page.post(url, data=form_data)
                                                                          print(page.user_agent)  # 自动构建请求头
                                                                          print(page.response.json())
                                                                          # page.close()

                                                                          WebPage的使用

                                                                          WebPage是整合了上面两者的页面对象,既可控制浏览器,又可收发数据包,并且可以在这两者之间共享登录信息。

                                                                          它有两种工作模式:d模式和s模式。d模式用于控制浏览器,s模式用于收发数据包。WebPage可在两种模式间切换,但同一时间只能处于其中一种模式。

                                                                          当前对象在新版本中已被作者刻意淡化,不建议使用。

                                                                          官方文档说明:https://drissionpage.cn/DP32Docs/get_start/basic_concept/#webpage

                                                                            import time
                                                                            from DrissionPage import WebPage


                                                                            # 创建页面对象,初始d模式
                                                                            page = WebPage('d')


                                                                            # 访问百度
                                                                            page.get('http://www.baidu.com')


                                                                            # 定位输入框并输入关键字
                                                                            page.ele('#kw').input('DrissionPage')


                                                                            # 点击"百度一下"按钮
                                                                            page.ele('@value=百度一下').click()


                                                                            # 等待页面加载
                                                                            page.wait.load_start()


                                                                            # 切换到s模式
                                                                            page.change_mode()


                                                                            # 获取所有结果元素
                                                                            results = page.eles('tag:h3')


                                                                            # 遍历所有结果
                                                                            for result in results:
                                                                                # 打印结果文本
                                                                                print(result.text)


                                                                            time.sleep(3)
                                                                            page.quit()

                                                                            请求头加密的爬虫案例

                                                                            网站访问地址:https://kaoyan.docin.com/pdfreader/web/#/docin/documents?type=1&keyword=%E5%A4%8D%E8%AF%95%E4%BB%BF%E7%9C%9F%E6%A8%A1%E6%8B%9F

                                                                            使用requests完成请求.py

                                                                              import requests




                                                                              headers = {
                                                                                  "Accept""application/json, text/plain, */*",
                                                                                  "Accept-Language""zh-CN,zh;q=0.9",
                                                                                  "Cache-Control""no-cache",
                                                                                  "Connection""keep-alive",
                                                                                  "Content-Type""application/json",
                                                                                  "Origin""https://kaoyan.docin.com",
                                                                                  "Pragma""no-cache",
                                                                                  "Referer""https://kaoyan.docin.com/",
                                                                                  "Sec-Fetch-Dest""empty",
                                                                                  "Sec-Fetch-Mode""cors",
                                                                                  "Sec-Fetch-Site""cross-site",
                                                                                  "User-Agent""Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
                                                                                  "X-Application""Pdfreader.Web",
                                                                                  "X-Nonce""02fec55d-8a78-2453-cb18-42f62ef46732",
                                                                                  "X-Sign""C0FC7B5784DDE2FD774DD00C6AB89BE5",
                                                                                  "X-Timestamp""1733317931",
                                                                                  "X-Token""null",
                                                                                  "X-Version""V2.2",
                                                                                  "sec-ch-ua""Google Chrome;v=131, Chromium;v=131, Not_A Brand;v=24",
                                                                                  "sec-ch-ua-mobile""?0",
                                                                                  "sec-ch-ua-platform""macOS"
                                                                              }
                                                                              url = "https://www.handebook.com/api/web/document/list"
                                                                              json_data = {
                                                                                  "SearchType": 0,
                                                                                  "SearchKeyword""复试仿真模拟",
                                                                                  "DocumentType"" ",
                                                                                  "UniversityCode""",
                                                                                  "MajorCode""",
                                                                                  "ExamSubjectList": [],
                                                                                  "PageIndex": 1,
                                                                                  "PageSize": 30
                                                                              }


                                                                              response = requests.post(url, headers=headers, json=json_data)
                                                                              print(response.json())


                                                                              使用WebPage完成请求.py
                                                                                import pymongo
                                                                                from DrissionPage import WebPage
                                                                                from DrissionPage.common import By




                                                                                class DouDing:
                                                                                    mongo_client = pymongo.MongoClient()


                                                                                    def __init__(self):
                                                                                        self.url = 'https://kaoyan.docin.com/pdfreader/web/#/docin/documents?type=1&keyword=%E5%A4%8D%E8%AF%95%E4%BB%BF%E7%9C%9F%E6%A8%A1%E6%8B%9F'
                                                                                        # self.page = WebPage(mode='d')  # mode为设置session模式或者driver模式, 默认为driver
                                                                                        self.page = WebPage()


                                                                                    def get_info(self):
                                                                                        self.page.listen.start('/api/web/document/list')
                                                                                        self.page.get(self.url)
                                                                                        for item in self.page.listen.steps(count=20):
                                                                                            # print(item)
                                                                                            self.parse_info(item.response.body)


                                                                                            # 翻页
                                                                                            self.page.ele((By.CLASS_NAME, 'btn-next'), timeout=3).click()
                                                                                        self.page.quit()


                                                                                    def parse_info(self, info):
                                                                                        for temp in info['Data']['DocumentInfos']:
                                                                                            item = dict()
                                                                                            item['DocumentGuid'] = temp['DocumentGuid']
                                                                                            item['DocumentName'] = temp['DocumentName']
                                                                                            item['DocumentPrice'] = temp['DocumentPrice']
                                                                                            self.save_info(item)


                                                                                    def save_info(self, info_dict):
                                                                                        collection = self.mongo_client['py_spider']['dou_ding']
                                                                                        collection.insert_one(info_dict)
                                                                                        print('保存成功:', info_dict)




                                                                                if __name__ == '__main__':
                                                                                    dou_ding = DouDing()
                                                                                    dou_ding.get_info()

                                                                                文件下载

                                                                                DrissionPage内置下载器,无需手动构建open()文件对象

                                                                                官网说明:https://www.drissionpage.cn/download/intro

                                                                                  import os
                                                                                  from DrissionPage import SessionPage




                                                                                  url = 'https://www.lpbzj.vip/allimg'
                                                                                  page = SessionPage()
                                                                                  page.get(url)
                                                                                  element_div = page.s_eles("xpath://div[@id='posts']")[0]
                                                                                  detail_url_list = element_div.s_eles("xpath:.//div[@class='img']/a")


                                                                                  save_path = './美女写真/'
                                                                                  os.makedirs(save_path, exist_ok=True)  # 确保保存目录存在


                                                                                  for detail_url in detail_url_list:
                                                                                      page.get(detail_url.attr('href'))
                                                                                      div_element = page.s_eles("xpath://div[@class='article-content clearfix']")[0]
                                                                                      image_url_list = div_element.s_eles("xpath:.//img")
                                                                                      for image_url in image_url_list:
                                                                                          img_src = image_url.attr('src')


                                                                                          # 同步下载
                                                                                          # res = page.download(img_src, save_path)
                                                                                          # print('task status:', res)


                                                                                          # 添加下载任务并发下载
                                                                                          page.download.add(img_src, save_path)
                                                                                          print(f"Downloading image from: {img_src}")


                                                                                  项目实战

                                                                                  唯品会接口数据抓取

                                                                                    import json
                                                                                    from DrissionPage.common import By
                                                                                    from DrissionPage import ChromiumPage


                                                                                    page = ChromiumPage()
                                                                                    url = 'https://category.vip.com/suggest.php?keyword=%E7%94%B5%E8%84%91&ff=235%7C12%7C1%7C1&tfs_url=%2F%2Fmapi-pc.vip.com%2Fvips-mobile%2Frest%2Fshopping%2Fpc%2Fsearch%2Fproduct%2Frank&page=1'
                                                                                    page.listen.start('vips-mobile/rest/shopping/pc/product/module/list/v2')
                                                                                    page.get(url)


                                                                                    for item in page.listen.steps():
                                                                                        response_body = item.response.body


                                                                                        try:
                                                                                            # 提取 JSON 字符串部分
                                                                                            start_index = response_body.find('{')
                                                                                            end_index = response_body.rfind('}') + 1
                                                                                            json_str = response_body[start_index:end_index]


                                                                                            info_dict = json.loads(json_str)


                                                                                            for temp in info_dict['data']['products']:
                                                                                                shop_info = dict()
                                                                                                shop_info['商品名称'] = temp['title']
                                                                                                shop_info['商品品牌'] = temp['brandShowName']
                                                                                                shop_info['商品价格'] = temp['price']['salePrice']
                                                                                                print(shop_info)


                                                                                            button = page.ele((By.CLASS_NAME, 'cat-paging-next'), timeout=3)
                                                                                            if button:
                                                                                                button.click()
                                                                                            else:
                                                                                                print('爬虫结束...')
                                                                                                page.quit()
                                                                                        except AttributeError:
                                                                                            print('数据为空:', response_body)


                                                                                    小红书首页数据抓取
                                                                                      from DrissionPage import ChromiumPage


                                                                                      page = ChromiumPage()
                                                                                      page.listen.start('api/sns/web/v1/homefeed')
                                                                                      page.get('https://www.xiaohongshu.com/explore')


                                                                                      while True:
                                                                                          js_code = f"document.documentElement.scrollTop = document.documentElement.scrollHeight * {1000}"
                                                                                          page.run_js(js_code)


                                                                                          # 未获取返回false, 获取则返回列表, 列表元素类型为DataPacket
                                                                                          is_api_list = page.listen.wait(count=5, timeout=1)
                                                                                          print('数据状态:', is_api_list)
                                                                                          if is_api_list:
                                                                                              for item in is_api_list:
                                                                                                  print(item.response.body)


                                                                                      补充 - 小红书自动评论脚本(自行研究)
                                                                                        import time
                                                                                        from DrissionPage import ChromiumPage


                                                                                        search = str(input("输入关键词:"))
                                                                                        content = str(input("输入评论内容:"))


                                                                                        page = ChromiumPage()
                                                                                        page.get('https://www.xiaohongshu.com/search_result?keyword=' + search + '&source=unknown&type=51')
                                                                                        print("网站加载成功!")
                                                                                        time.sleep(2)
                                                                                        for time_button in range(120):  # 下滑多少下 你就改多少下
                                                                                            time.sleep(2)
                                                                                            page.scroll.to_bottom()
                                                                                            print("当前下滑:", time_button, "次,剩余"20 - time_button, "次后,将会开始抓取数据...")
                                                                                        print("全部下滑完毕开始抓取页面的元素链接!")
                                                                                        my_list = list()
                                                                                        ele = page.eles('.cover ld mask')
                                                                                        name_ele = page.eles('.title')
                                                                                        for href, name in zip(ele, name_ele):
                                                                                            lian = href.link
                                                                                            na = name.text
                                                                                            print(na, lian)
                                                                                            my_list.extend(lian.split(','))


                                                                                        sums = 0


                                                                                        print("本次获取数据:"len(my_list), "条")
                                                                                        for like_list in my_list:
                                                                                            sums = sums + 1
                                                                                            print("序号:", sums, "链接:", like_list)
                                                                                            page.get(like_list)
                                                                                            time.sleep(1)
                                                                                            input_list1 = page.ele('.chat-wrapper').click()
                                                                                            input_list2 = page.ele('.content-input').input(content)
                                                                                            time.sleep(0.5)
                                                                                            button = page.ele('.btn submit').click()
                                                                                            print("发送成功:", content, "-")
                                                                                            time.sleep(2)
                                                                                        print("*" * 30)
                                                                                        input("主程序结束...")



                                                                                        文章转载自老柴杂货铺,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

                                                                                        评论