• Selenium的使用


    直接使用模拟浏览器运行的方式来实现,这样我们就可以做到浏览器看到是什么样,抓取的源码就是什么样,也就是可见即可爬。这样我们就不用再去管网页内部的 JavaScript 用了什么算法渲染页面,不用管网页后台的 Ajax 接口到底有哪些参数,利用模拟浏览器的方式我们都可以直接获取 JavaScript 渲染的最终结果,只要能在浏览器中看到,我们都能抓取

    1.环境配置

    使用chrome浏览器,下载跟chrome浏览器版本相匹配的chromedriver.exe,放到当前使用的python环境的Scripts目录下

    然后在命令行里执行chromedriver,出现如下画面则说明配置成功

    2.声明浏览器对象

    Selenium 支持非常多的浏览器,如 Chrome、Firefox、Edge 等,还有手机端的浏览器 Android、BlackBerry 等,另外无界面浏览器 PhantomJS 也同样支持。

    使用其他的浏览器也需要做相应的环境配置才行。

    可以用如下的方式初始化:

    from selenium import webdriver
    
    browser = webdriver.Chrome()

     # browser = webdriver.Firefox()
    # browser = webdriver.Edge()
    # browser = webdriver.PhantomJS()
    # browser = webdriver.Safari()
    3.访问页面

    弹出Chrome 浏览器,自动访问了淘宝,然后控制台输出了淘宝页面的源代码,随后浏览器关闭

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

    4.查找节点

    Selenium 可以驱动浏览器完成各种操作,比如填充表单、模拟点击等等,但是前提是需要知道节点所在的位置

    4.1单个节点

    所有获取单个节点的方法:
    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_element() 方法,它需要传入两个参数,一个是查找的方式 By,另一个就是值,实际上它就是 find_element_by_id() 这种方法的通用函数版本,比如 find_element_by_id(id) 就等价于 find_element(By.ID, id)

    4.2多个节点

    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

    也可以直接 find_elements() 方法来选择,所以也可以这样来写:lis = browser.find_elements(By.CSS_SELECTOR, '.service-bd li')

    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()

    5.节点交互

    比较常见的用法有:
    输入文字用 send_keys() 方法,
    清空文字用 clear() 方法,
    按钮点击用 click() 方法

    官方文档的交互动作介绍:http://selenium-python.readthedocs.io/api.html#module-selenium.webdriver.remote.webelement

    import time
    
    from selenium import webdriver
    
    browser = webdriver.Chrome()
    try:
        browser.get('https://www.taobao.com')
        input = browser.find_element_by_id('q')
        input.send_keys('iPhone')
        time.sleep(1)
        input.clear()
        input.send_keys('iPad')
        button = browser.find_element_by_class_name('btn-search')
        button.click()
    finally:
        browser.close()

    6.动作链

    还有另外一些操作它是没有特定的执行对象的,比如鼠标拖拽、键盘按键等操作。这些动作用另一种方式来执行,那就是动作链

    更多的动作链操作可以参考官方文档的动作链介绍:http://selenium-python.readthedocs.io/api.html#module-selenium.webdriver.common.action_chains

    from selenium import webdriver
    from selenium.webdriver import ActionChains
    
    browser = webdriver.Chrome()
    url = 'http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable'
    try:
        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()
    finally:
        browser.close()

    7.执行JavaScript

    对于某些操作,Selenium API 是没有提供的,如下拉进度条等,可以直接模拟运行 JavaScript,使用 execute_script() 方法即可实现

    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")')

    利用了 execute_script() 方法将进度条下拉到最底部,然后弹出 alert 提示框

    8.获取节点信息

    8.1获取属性

    使用 get_attribute() 方法来获取节点的属性,那么这个的前提就是先选中这个节点

    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)
    print(logo.get_attribute('href'))

    8.2获取文本值

    每个 WebEelement 节点都有 text 属性,我们可以通过直接调用这个属性就可以得到节点内部的文本信息了,就相当于 BeautifulSoup 的 get_text() 方法、PyQuery 的 text() 方法

    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.text)

    8.3.获取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)

    9.切换Frame

    在网页中有这样一种节点叫做 iframe,也就是子Frame,相当于页面的子页面,它的结构和外部网页的结构是完全一致的。
    Selenium 打开页面后,它默认是在父级Frame 里面操作,而此时如果页面中还有子 Frame,它是不能获取到子 Frame 里面的节点的。所以这时候我们就需要使用 switch_to.frame() 方法来切换 Frame。

    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')
    try:
        logo = browser.find_element_by_class_name('logo')
    except NoSuchElementException:
        print('NO LOGO')
    browser.switch_to.parent_frame()
    logo = browser.find_element_by_class_name('logo')
    print(logo)
    print(logo.text)

    我们先通过 switch_to.frame() 方法切换到子 Frame 里面,然后我们尝试获取父级 Frame 里的 LOGO 节点,是不能找到的,找不到的话就会抛出 NoSuchElementException 异常,异常被捕捉之后就会输出 NO LOGO,接下来我们重新切换回父Frame,然后再次重新获取节点,发现就可以成功获取了。

    所以说当页面中包含子 Frame 时,如果我们想获取子Frame 中的节点,需要先调用 switch_to.frame() 方法切换到对应的 Frame,然后再进行操作即可

    10.延时等待

    在 Selenium 中,get() 方法会在网页框架加载结束之后就结束执行,此时如果获取 page_source 可能并不是浏览器完全加载完成的页面,如果某些页面有额外的 Ajax 请求,我们在网页源代码中也不一定能成功获取到。所以这里我们需要延时等待一定时间确保节点已经加载出来。

    在这里等待的方式有两种,一种隐式等待,一种显式等待

    10.1 隐式等待

    如果 Selenium 没有在DOM 中找到节点,将继续等待,超出设定时间后则抛出找不到节点的异常, 默认的时间是 0

    用 implicitly_wait() 方法实现了隐式等待

    from selenium import webdriver
    
    browser = webdriver.Chrome()
    browser.implicitly_wait(10)
    browser.get('https://www.zhihu.com/explore')
    input = browser.find_element_by_class_name('zu-top-add-question')
    print(input)

    10.2 显式等待

    指定好要查找的节点,然后指定一个最长等待时间。如果在规定时间内加载出来了这个节点,那就返回查找的节点,如果到了规定时间依然没有加载出该节点,则会抛出超时异常。

    from selenium import webdriver
    from selenium.webdriver.common.by import By
    from selenium.webdriver.support import expected_conditions as EC
    from selenium.webdriver.support.ui import WebDriverWait
    
    browser = webdriver.Chrome()
    browser.get('https://www.taobao.com/')
    wait = WebDriverWait(browser, 0.01)
    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)

    首先引入了 WebDriverWait 这个对象,指定好最长等待时间,然后调用它的 until() 方法,传入要等待条件 expected_conditions,比如在这里我们传入了 presence_of_element_located 这个条件,就代表节点出现的意思,其参数是节点的定位元组,也就是 ID 为 q 的节点搜索框。所以这样可以做到的效果就是,在 10 秒内如果 ID 为 q 的节点即搜索框成功加载出来了,那就返回该节点,如果超过10 秒还没有加载出来,那就抛出异常。

    对于按钮,可以更改一下等待条件,比如改为 element_to_be_clickable,也就是可点击,所以查找按钮时是查找 CSS 选择器为 .btn-search 的按钮,如果 10 秒内它是可点击的也就是成功加载出来了,那就返回这个按钮节点,如果超过 10 秒还不可点击,也就是没有加载出来,那就抛出异常。

    所有的加载条件:

    等待条件

    含义

    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

    更多详细的等待条件的参数及用法介绍可以参考官方文档:http://selenium-python.readthedocs.io/api.html#module-selenium.webdriver.support.expected_conditions

    11.前进后退

    在Selenium中使用 back() 方法可以后退,forward() 方法可以前进

    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()
    time.sleep(1)
    browser.forward()
    browser.close()

    连续访问三个页面,然后调用 back() 方法就可以回到第二个页面,接下来再调用 forward() 方法又可以前进到第三个页面

    12.cookies

    使用 Selenium 还可以方便地对 Cookies 进行操作,例如获取、添加、删除 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())

    首先我们访问了知乎,然后加载完成之后,浏览器实际上已经生成了 Cookies 了,我们调用 get_cookies() 方法就可以获取所有的 Cookies,然后我们添加一个 Cookie,传入一个字典,有 name、domain、value 等内容。接下来我们再次获取所有的 Cookies,可以发现结果就多了这一项 Cookie。最后我们调用 delete_all_cookies() 方法,删除所有的 Cookies,再重新获取,结果就为空了。

    13.选项卡管理

    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')

    我们访问了百度,然后调用了 execute_script() 方法,传入 window.open() 的 JavaScript 语句新开启一个选项卡,然后接下来我们想切换到该选项卡,可以调用 window_handles 属性获取当前开启的所有选项卡,返回的是选项卡的代号列表,要想切换选项卡只需要调用 switch_to.window() 方法,传入选项卡的代号即可。在这里我们将第二个选项卡代号传入,即跳转到了第二个选项卡,然后接下来在第二个选项卡下打开一个新的页面,然后切换回第一个选项卡可以重新调用 switch_to.window() 方法,再执行其他操作即可

    14.异常处理

    在使用 Selenium 过程中,难免会遇到一些异常,例如超时、节点未找到等错误,一旦出现此类错误,程序便不会继续运行了,所以异常处理在程序中是十分重要的

    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()

    更多的异常可以参考官方文档:http://selenium-python.readthedocs.io/api.html#module-selenium.common.exceptions

  • 相关阅读:
    SQL server 插入不同IP的数据库
    SQL Server中的循环例子(网摘)
    C#小型数据库只能查询
    vue.prototype和vue.use的区别和注意点
    Ajax+PHP简单入门教程
    smarty在windows下的安装
    docker安装mysql镜像和容器
    Linux导出未越狱Iphone10.3QQ聊天记录
    记一次Struts中文乱码
    Ubuntu设置服务开机启动
  • 原文地址:https://www.cnblogs.com/sanduzxcvbnm/p/10338812.html
Copyright © 2020-2023  润新知