51Testing软件测试论坛

 找回密码
 (注-册)加入51Testing

QQ登录

只需一步,快速开始

微信登录,快人一步

手机号码,快捷登录

查看: 679|回复: 0
打印 上一主题 下一主题

分享Selenium框架的爬虫遇到下拉框页面的解决方式

[复制链接]
  • TA的每日心情
    擦汗
    昨天 09:04
  • 签到天数: 1047 天

    连续签到: 5 天

    [LV.10]测试总司令

    跳转到指定楼层
    1#
    发表于 2023-3-16 13:40:02 | 只看该作者 回帖奖励 |正序浏览 |阅读模式
    背景
      最近有一个项目需要使用爬虫从某网站抓取全国的医院名称,等级,地址等信息。
      爬取的url为https://some/website/that/i/can/tell/you/sorry
      用浏览器打开这个url会发现,切换不同的省市需要点击左上角的下拉框进行选择。

      问题
      通常遇到这种下拉框页面,我们第一时间想到使用Selenium框架的Select类,这个类是Selenium框架专门用于处理页面下拉框的,使用方式如下:
      from selenium import webdriver
      from selenium.webdriver.common.by import By
      from selenium.webdriver.support.select import Select
      driver=webdriver.Chrome() #初始化浏览器驱动
      url='https://some/website/that/i/can/tell/you/sorry'#页面url
      driver.get(url)#访问相对应链接
      windows_start=driver.window_handles[0] #文档列表窗口名
      #定位省市
      ele=driver.find_element(By.XPATH,'//*[@id="Prov"]')
      select_ele = Select(ele)
      select_ele.select_by_visible_text("北京市")
      time.sleep(1)


      #输入医院名称
      driver.find_element(By.XPATH,'//*[@id="Unit_Name"]').send_keys('协和医院')


      但是Select类只能用于下拉框实现方式是基于html的select标签的情况,针对本项目,打开页面源码发现。

      该页面的下拉框使用的是input标签!!!!
      不慌!
      既然不能用Select类一步到位,那我们就老老实实的模拟鼠标点击等操作来实现爬取页面过程的省市切换,找到Xpath,调用click()方法,简直不要太简单,呵呵呵
      但是:

      报错信息no such element,意思是说找不到这个元素
      经过不断的排查发现这么一个现象:
      第一次打开的时候下拉框的Xpath:
      //*[@id="cascader-menu-7056-0-0"]/span/div
      第二次打开的时候下拉框的Xpath:
      //*[@id="cascader-menu-3644-0-0"]/span/div


      下拉框的Xpath每次打开页面是变化着的,也就是说开发这个页面的前端工程师还是做了一点反爬措施的,每次点开页面以后下拉框的id可能是随机生成的,这可如何是好?
      不慌!
      解决思路
      既然每次打开页面的时候Xpath是变化着的,主要是Xpath中间有个四位数的随机数
      第一次打开的时候下拉框的Xpath:
      //*[@id="cascader-menu-7056-0-0"]/span/div
      第二次打开的时候下拉框的Xpath:
      //*[@id="cascader-menu-3644-0-0"]/span/div


      我们不去管随机数,只关心当前页面,想办法拿到当前页面的源码,再从中解析出下拉框的Xpath,在模拟点击,则问题就迎刃而解!

      基于这个思路,我们不必关心每次生成的随机数具体是什么,早知道它是四位数,而且前面为//*[@id="cascader-menu-,后面为-0-0"]/span/div,那么使用正则表达式来解析简直不要太简单!
      正则表达式如下:
      #获取随机的ID
      bs = BeautifulSoup(driver.page_source, "html.parser") #解析页面源码
      xpath_id = re.findall(
              r'cascader-menu-[0-9]+-[0-9].*city-select-component-span',
              driver.page_source)[0]
      xpath_id = re.findall(r'cascader-menu-[0-9]+-[0-9]+', xpath_id)[0]
       xpath_id = re.findall(r'\d+', xpath_id)[0]


      完整代码
      def change_province(driver, province_id):
          """
          点击下拉框切换特定省市
          """
          #点击下拉框
          driver.find_element(
              By.XPATH,
              '//*[@id="app_main"]/div/form/div[1]/div/div/div/input').click()

          time.sleep(1)

          #获取随机的ID
          bs = BeautifulSoup(driver.page_source, "html.parser")
          xpath_id = re.findall(
              r'cascader-menu-[0-9]+-[0-9].*city-select-component-span',
              driver.page_source)[0]
          xpath_id = re.findall(r'cascader-menu-[0-9]+-[0-9]+', xpath_id)[0]
          xpath_id = re.findall(r'\d+', xpath_id)[0]

          #     点击切换固定id的省市
          driver.find_element(
              By.XPATH, '//*[@id="cascader-menu-{0}-0-{1}"]/span/div'.format(
                  xpath_id, province_id)).click()
          time.sleep(np.random.randint(1, 3))

      def next_page(driver):
          """
          点击切换下一页
          """
          driver.find_element(By.XPATH,'//*[@id="app_main"]/div/div[2]/div/button[2]/i').click()
          time.sleep(np.random.randint(1,3))

      def get_info(driver):
          """
          解析信息
          """
          info_list=[]
          for i in range(1,11):
              try:
                  info=driver.find_element(By.XPATH,'//*[@id="app_main"]/div/section/div[2]/div[3]/table/tbody/tr[{}]'.format(i)).text
                  info=info.split('\n')
                  info_list.append(info)
              except Exception as e:
                  break
          return info_list

      driver=webdriver.Chrome()
      ocr = ddddocr.DdddOcr()

      url='https://some/website/that/i/can/tell/you/sorry'#打开url
      driver.get(url)#访问相对应链接
      windows_start=driver.window_handles[0] #文档列表窗口名



      for province_id in range(0,32):
          change_province(driver,province_id) #顺序切换省市
          max_page=driver.find_element(By.XPATH,'//*[@id="app_main"]/div/div[2]/div/ul/li[6]').text #获取最大页数
          max_page=int(max_page)


          data=get_info(driver) #获取第一页的数据

          for i in range(0,max_page-1):
              next_page(driver)
              data_1=get_info(driver)
              data.extend(data_1)

          df_temp=pd.DataFrame(data,columns=['序号','医疗机构名称','医疗机构类型','医疗机构等级','详细地址','开通情况'])
          df_temp.to_excel("./{}.xlsx".format(province_id))



    分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
    收藏收藏
    回复

    使用道具 举报

    本版积分规则

    关闭

    站长推荐上一条 /1 下一条

    小黑屋|手机版|Archiver|51Testing软件测试网 ( 沪ICP备05003035号 关于我们

    GMT+8, 2024-11-16 13:25 , Processed in 0.065629 second(s), 23 queries .

    Powered by Discuz! X3.2

    © 2001-2024 Comsenz Inc.

    快速回复 返回顶部 返回列表