美文网首页零基础-一起学爬虫
【零基础学爬虫】Selenium库详解

【零基础学爬虫】Selenium库详解

作者: 大菜鸟_ | 来源:发表于2019-03-24 17:26 被阅读6次

    什么是Selenium

    主要用于自动化测试工具,支持多浏览器:chrome,Firefox,Android浏览器等,主要用于驱动浏览器,给浏览器发一些指令,让浏览器执行各种动作:输入、跳转、点击、下拉等操作。它在爬虫中主要解决javaScript渲染问题,完全模拟网页的加载。

    在做爬虫的时候如果遇到Request、urllib无法正常获取网页内容,那么这可能是JavaScript渲染致使的问题,这时使用Selenium可以完成渲染,即模拟浏览器完整的操作,之后获取到的源代码就是网页渲染后的源代码,可以完全解决javaScript渲染问题。

    安装

    基本使用

    下面是一个简单实例代码:

    from selenium import webdriver#浏览器驱动对象
    from selenium.webdriver.common.by import By
    from selenium.webdriver.common.keys import Keys
    from selenium.webdriver.support import expected_conditions as EC
    from selenium.webdriver.support.wait import WebDriverWait
    
    browser = webdriver.Chrome()#chrom浏览器驱动对象
    try:
        browser.get('https://www.baidu.com')#传入url,此时会跳出浏览器,访问百度网址
        input = browser.find_element_by_id('kw') #找出id为kw元素
        input.send_keys('Python')#kw中发送python
        input.send_keys(Keys.ENTER)#回车
        wait = WebDriverWait(browser, 10)#等待加载完成
        wait.until(EC.presence_of_element_located((By.ID, 'content_left')))#等待content_left加载完成
        print(browser.current_url)
        #print(browser.get_cookies())
        #print(browser.page_source)
    finally:
        browser.close()
    

    输出的当前网页url其实就是我们搜索关键词时浏览器地址栏的地址:
    https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&rsv_idx=1&tn=baidu&wd=Python&rsv_pq=e7742729000658f1&rsv_t=cc28oZ5U7GMkpj%2FJdBtJXIrYy8IMIXVo35002Hb4hIvJpqwhNFLtlB9KzUw&rqlang=cn&rsv_enter=1&rsv_sug3=6&rsv_sug2=0&inputT=75&rsv_sug4=76

    pageSource太长了就没打印
    (1)声明浏览器对象

    from selenium import webdriver
    
    browser = webdriver.Chrome()
    browser = webdriver.Firefox()
    browser = webdriver.Edge()
    browser = webdriver.PhantomJS()
    browser = webdriver.Safari()
    

    (2) 访问页面

    from selenium import webdriver
    
    browser = webdriver.Chrome()
    browser.get('https://www.taobao.com')
    print(browser.page_source)
    browser.close()
    

    (3)查找单个元素
    获取到网页源码后,可能需要进行一些交互的操作:输入框、按钮点击之类的。

    from selenium import webdriver
    
    browser = webdriver.Chrome()
    browser.get('https://www.taobao.com')
    input_first = browser.find_element_by_id('q')
    input_second = browser.find_element_by_css_selector('#q')
    input_third = browser.find_element_by_xpath('//*[@id="q"]')
    print(input_first, input_second, input_third)#三个结果一样
    browser.close()
    

    输出的三个结果其实是一样的,也就是可以使用不同的方法找元素

    <selenium.webdriver.remote.webelement.WebElement (session="5e53d9e1c8646e44c14c1c2880d424af", element="0.5649563096161541-1")> 
    <selenium.webdriver.remote.webelement.WebElement (session="5e53d9e1c8646e44c14c1c2880d424af", element="0.5649563096161541-1")> 
    <selenium.webdriver.remote.webelement.WebElement (session="5e53d9e1c8646e44c14c1c2880d424af", element="0.5649563096161541-1")>
    

    常用的查找单个元素方法:

    • 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
      上面这些方法可以通过一个统一的方式使用:
    from selenium import webdriver
    from selenium.webdriver.common.by import By
    
    browser = webdriver.Chrome()
    browser.get('https://www.taobao.com')
    input_first = browser.find_element(By.ID, 'q')
    print(input_first)
    browser.close()
    

    (4)查找多个元素

    from selenium import webdriver
    
    browser = webdriver.Chrome()
    browser.get('https://www.taobao.com')
    lis = browser.find_elements_by_css_selector('.service-bd li')
    print(lis)
    browser.close()
    

    下面与上面方式一样:

    from selenium import webdriver
    from selenium.webdriver.common.by import By
    
    browser = webdriver.Chrome()
    browser.get('https://www.taobao.com')
    lis = browser.find_elements(By.CSS_SELECTOR, '.service-bd li')#列表
    print(lis)
    browser.close()
    

    常用的查找多个元素方法:

    • 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
      (5)元素的交互操作
    from selenium import webdriver
    import time
    
    browser = webdriver.Chrome()
    browser.get('https://www.taobao.com')
    input = browser.find_element_by_id('q')
    input.send_keys('iPhone')
    time.sleep(1)#等待1秒
    input.clear()
    input.send_keys('iPad')搜索IPad
    button = browser.find_element_by_class_name('btn-search')
    button.click()
    

    上面程序含义是:在淘宝中搜索“iPad”,那么为什么是find_element_by_id('q')呢?q又是从何而来的呢?我们打开淘宝首页,邮件,审查元素,鼠标点击淘宝的搜索框,如下图所示:



    这就是id为‘q’的由来。当我们在淘宝搜索iPhone时,再次点击邮件->检查,结果如下图所示:



    这就是‘q’的由来。
    另外,btn-search是怎么来的呢?

    另外,实际测试中发现填写:tb-bg也是可以的

    更多操作: http://selenium-python.readthedocs.io/api.html#module-selenium.webdriver.remote.webelement

    (6)交互动作
    和上面的元素交互动作是不同的:

    • 元素交互动作需要先获取一个特定的元素,调用相应的方法完成响应动作
    • 这里是将动作附加到动作链中串行执行
      比如人机验证时的拖拽:
    from selenium import webdriver
    from selenium.webdriver import ActionChains
    
    browser = webdriver.Chrome()
    url = 'http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable'
    browser.get(url)
    browser.switch_to.frame('iframeResult')
    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()
    

    上面的draggable和droppable都来自上图,执行后就将小方框拖动到大方框中了

    更多操作: http://selenium-python.readthedocs.io/api.html#module-selenium.webdriver.common.action_chains

    执行JavaScript

    from selenium import webdriver
    
    browser = webdriver.Chrome()
    browser.get('https://www.zhihu.com/explore')
    browser.execute_script('window.scrollTo(0, document.body.scrollHeight)')
    browser.execute_script('alert("To Bottom")')
    

    (7)获取元素属性、文本值

    from selenium import webdriver
    from selenium.webdriver import ActionChains
    
    browser = webdriver.Chrome()
    url = 'https://www.zhihu.com/explore'
    browser.get(url)
    logo = browser.find_element_by_id('zh-top-link-logo')
    print(logo.text)#文本值
    print(logo.get_attribute('class'))
    

    输出:

    知乎
    zu-top-link-logo

    获取ID、位置、标签名、大小

    from selenium import webdriver
    
    browser = webdriver.Chrome()
    url = 'https://www.zhihu.com/explore'
    browser.get(url)
    input = browser.find_element_by_class_name('zu-top-add-question')
    print(input.id)
    print(input.location)
    print(input.tag_name)
    print(input.size)
    

    输出:

    0.6822924344980397-1
    {'y': 7, 'x': 774}
    button
    {'height': 32, 'width': 66}

    Frame

    Frame在网页中可能出现比较频繁,但是如果出现了Frame,在做元素筛选的时候会导致一些不太方便的问题:有些Frame相对于一个独立的网页,在父级的Frame中,想查找子元素的Frame,实际上必须切换到Frame中才能进行查找,否则是不能完成元素的查找。

    比如之前拖拽案例中的源代码:


    整个拖拽是在一个iframe中,但是如果我们在这个iframe中想要获取外面的那些元素,获取时可能汇报错误,比如在拖拽那个iframe中尝试获取logo class,此时汇报找不到该元素的错误:

    import time
    from selenium import webdriver
    from selenium.common.exceptions import NoSuchElementException
    
    browser = webdriver.Chrome()
    url = 'http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable'
    browser.get(url)
    browser.switch_to.frame('iframeResult')#切换到拖拽那个iframe中
    source = browser.find_element_by_css_selector('#draggable')
    print(source.text)#
    try:
        logo = browser.find_element_by_class_name('logo')#尝试找外面的元素
    except NoSuchElementException:
        print('NO LOGO')#没找到
    browser.switch_to.parent_frame()#切换到父iframe查找
    logo = browser.find_element_by_class_name('logo')
    print(type(logo))
    print(logo.text)
    

    输出:
    请拖拽我!

    NO LOGO
    <class 'selenium.webdriver.remote.webelement.WebElement'>
    RUNOOB.COM
    

    不能在子frame查找父frame中的元素

    等待

    我们在爬取数据的时候可能会有一些Ajax请求,这些Ajax请求不会管Selenium是否完成了网页的加载,也就是说:Selenium只是把基本的框架给加载出来了,如果有一些后续的Ajax请求等其他的操作,可能会出现有部分元素没有加载完全,在没加载完时进行操作会导致一些问题的出现。所以,我们需要加一些等待,确保元素都完成加载后在进行一些操作,这样可以减少异常。

    等待分为两种:显式等待和隐式等待。
    (1)隐式等待
    当使用了隐式等待执行测试的时候,如果 WebDriver没有在 DOM中找到元素,将继续等待,超出设定时间后则抛出找不到元素的异常, 换句话说:当查找元素或元素并没有立即出现的时候,隐式等待将等待一段时间再查找 DOM,默认的时间是0

    from selenium import webdriver
    
    browser = webdriver.Chrome()
    browser.implicitly_wait(10)#隐式等待时间10秒
    browser.get('https://www.zhihu.com/explore')
    #当网速比较慢时会出现下面的元素没加载出来
    input = browser.find_element_by_class_name('zu-top-add-question')
    print(input)
    

    (2)显示等待

    • 指定一个等待条件
    • 指定一个最长等待时间
      在最长等待时间内判断条件是否成立,如果成立则立即返回;否则一直等待到最长等待时间,超时会抛出异常。
      常用的等待条件:

    title_is 标题是某内容
    title_contains 标题包含某内容
    presence_of_element_located 元素加载出,传入定位元组,如(By.ID, 'p')
    visibility_of_element_located 元素可见,传入定位元组
    visibility_of 可见,传入元素对象
    presence_of_all_elements_located 所有元素加载出
    text_to_be_present_in_element 某个元素文本包含某文字
    text_to_be_present_in_element_value 某个元素值包含某文字
    frame_to_be_available_and_switch_to_it frame加载并切换
    invisibility_of_element_located 元素不可见
    element_to_be_clickable 元素可点击
    staleness_of 判断一个元素是否仍在DOM,可判断页面是否已经刷新
    element_to_be_selected 元素可选择,传元素对象
    element_located_to_be_selected 元素可选择,传入定位元组
    element_selection_state_to_be 传入元素对象以及状态,相等返回True,否则返回False
    element_located_selection_state_to_be 传入定位元组以及状态,相等返回True,否则返回False
    alert_is_present 是否出现Alert

    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.get('https://www.taobao.com/')
    wait = WebDriverWait(browser, 10)#最长等待时间
    #等待条件
    input = wait.until(EC.presence_of_element_located((By.ID, 'q')))
    #等待条件
    button = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, '.btn-search')))
    print(input, button)
    

    详细等待条件介绍:http://selenium-python.readthedocs.io/api.html#module-selenium.webdriver.support.expected_conditions

    浏览器的前进和后退

    import time
    from selenium import webdriver
    
    browser = webdriver.Chrome()
    browser.get('https://www.baidu.com/')
    browser.get('https://www.taobao.com/')
    browser.get('https://www.python.org/')
    browser.back()
    browser.back()
    time.sleep(1)
    browser.forward()
    browser.close()
    

    cookies
    尤其在登陆后的爬取,设置登录的状态。

    from selenium import webdriver
    
    browser = webdriver.Chrome()
    browser.get('https://www.zhihu.com/explore')
    print(browser.get_cookies())
    browser.add_cookie({'name': 'name', 'domain': 'www.zhihu.com', 'value': 'germey'})
    print(browser.get_cookies())
    browser.delete_all_cookies()
    print(browser.get_cookies())
    

    浏览器选项卡的操作
    新增浏览器选项卡:最简单的就是通过js打开新的选项卡;另外就是通过模拟键盘按键(浏览器可以通过快捷键打开选项卡),不太通用,不同浏览器快捷方式不一样:

    import time
    from selenium import webdriver
    
    browser = webdriver.Chrome()
    browser.get('https://www.baidu.com')#第一个选项卡打开百度
    browser.execute_script('window.open()')
    print(browser.window_handles)#返回的所有窗口的引用
    browser.switch_to_window(browser.window_handles[1])#切换到第二个选项卡
    browser.get('https://www.taobao.com')#第二个选项卡切换到淘宝
    time.sleep(1)
    browser.switch_to_window(browser.window_handles[0])#切换第一个选项卡
    browser.get('https://python.org')#第一个选项卡切换到python
    

    异常处理
    例如:某个元素无法点击异常、加载超时异常、没有找到元素的异常,各类异常最好查看官方文档:

    from selenium import webdriver
    from selenium.common.exceptions import TimeoutException, NoSuchElementException
    
    browser = webdriver.Chrome()
    try:
        browser.get('https://www.baidu.com')
    except TimeoutException:#超时异常
        print('Time Out')
    try:
        browser.find_element_by_id('hello')
    except NoSuchElementException:#好不到元素的异常
        print('No Element')
    finally:
        browser.close()
    

    exception的详细介绍文档:
    http://selenium-python.readthedocs.io/api.html#module-selenium.common.exceptions


    扫描下方二维码,及时获取更多互联网求职面经javapython爬虫大数据等技术,和海量资料分享
    公众号菜鸟名企梦后台发送“csdn”即可免费领取【csdn】和【百度文库】下载服务;
    公众号菜鸟名企梦后台发送“资料”:即可领取5T精品学习资料java面试考点java面经总结,以及几十个java、大数据项目资料很全,你想找的几乎都有

    扫码关注,及时获取更多精彩内容。(博主今日头条大数据工程师)

    相关文章

      网友评论

        本文标题:【零基础学爬虫】Selenium库详解

        本文链接:https://www.haomeiwen.com/subject/manyvqtx.html