zoukankan      html  css  js  c++  java
  • python3编写网络爬虫14-动态渲染页面爬取

    一、动态渲染页面爬取

    上节课我们了解了Ajax分析和抓取方式,这其实也是JavaScript动态渲染页面的一种情形,
    通过直接分析Ajax,借助requests和urllib实现数据爬取

    但是javaScript动态渲染布置Ajax一种 例如中国青年网(http://news.youth.cn/gn/)分页部分由js生成,
    并非原始HTML代码,这其中并不包含ajax请求 比如ECharts官方示例(http://echarts.baidu.com/demo.html#bar-negative)
    图形都是经过js计算生成的,再有淘宝 即便是ajax请求 但是接口很多都是加密参数,很难找到规律,也很难直接分析ajax抓取

    python提供了很多模拟浏览器运行的库,例如Selenium Splash,PyV8 Ghost等。


    1. Selenium的使用

    selenium是一个自动化测试工具,利用它可以驱动浏览器执行特定的动作,例如 点击 下拉等操作,
    同时还可以获取浏览器当前呈现的页面的源代码,做到可见既可爬。
    对于一些js动态渲染的页面来说,此种爬取方式非常有效

    1.1 安装

    安装:python的Selenium库

    pip install selenium

    验证:python命令行 import selenium
    无报错信息表示安装成功

    安装Google浏览器并配置ChromeDriver

    点击Google菜单 帮助 -> 关于Google Chrome -> 查看版本号 (版本 71.0.3578.98(正式版本) (64 位))

    下载ChromeDriver

    官网地址:

    https://sites.google.com/a/chromium.org/chromedriver

    下载地址:

    https://chromedriver.storage.googleapis.com/index.html

    对比自己浏览器版本下载相应版本

    解压后把文件放到 python的script目录下 例如 'C:UsersadminAppDataLocalProgramsPythonPython36Scripts'

    验证: cmd命令行 执行 chromedriver 输出如下信息:

    Starting ChromeDriver 2.45.615291 (ec3682e3c9061c10f26ea9e5cdcf3c53f3f74387) on port 9515
    Only local connections are allowed.

    表示安装 ChromeDriver配置好了

    测试 在python程序中执行

    from selenium import webdriver
    browser = webdriver.Chrome()

    程序运行后 弹出空白的Chrome浏览器 说明我们之前配置都没有问题

    没有弹出重新配置 闪退可能是版本不兼容

    1.2 基本作用

    示例如下:

    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()
    
    try:
      browser.get('https://www.baidu.com')
      input = browser.find_element_by_id('kw')
      input.send_keys('Python')
      input.send_keys(Keys.ENTER)
      wait = WebDriverWait(browser,10)
      wait.until(EC.presence_of_element_located((By.ID,'content_left')))
      print(browser.current_url)
      print(browser.get_cookies())
      print(browser.page_source)
    finally:
      browser.close()

    可以看到自动弹出浏览器 首先跳转百度 然后搜索框输入Python 接着跳转搜索结果页

    搜索结果出来后 控制台输出当前URL Cookies 网页源代码

    使用selenium 驱动浏览器加载网页就可以拿到js渲染结果了 不用担心什么加密系统


    1.3 声明浏览器对象

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

    1.4 访问页面

    get() 方法请求页面 参数 传入链接URL 例如访问淘宝

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

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


    1.5 查找节点

    Selenium 可以驱动浏览器完成各种操作,例如填充表单,模拟点击等
    例如想要完成某个输入框输入文字操作 需要查找输入框位置

    单个节点:
    例如淘宝页面提取搜索框节点

    id是q name是q

    利用
    find_element_by_name() 获取name值
    find_element_by_id() 获取id
    还可以根据xpath CSS选择器等获取方式

    示例如下:

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

    返回WebElement类型

    获取单个节点的方法:

    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() 需要传入两个参数:1.查找方式 2.值
    例如:find_element(By.ID,id) 等价于 find_element_by_id(id)

    示例如下:

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

    多个节点:
    find_elements() 查找所有满足条件的节点

    示例: 查找淘宝左侧导航条的所有条目

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

    返回列表 每个元素是WebElement类型

    获取多个节点的方法:

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

    1.6 节点交互

    send_keys() 输入文字
    clear() 清空文字
    click() 点击按钮

    示例:

    from selenium import webdriver
    import time
    
    browser = webdriver.Chrome()
    browser.get('http://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()

    首先打开淘宝 获取输入框 输入iphone文字 等待一秒 清空输入框 输入ipad 说去搜索按钮 点击按钮

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

    1.7 动作链

    例如鼠标拖拽 键盘按键等动作

    示例:

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

    首先打开网页中一个拖拽实例,然后依次选中要拖拽的节点和拖拽的目标节点
    声明ActionChains对象并将其赋值为actions变量,然后通过调用actions变量的 drag_and_drop()方法
    在调用 perform()方法执行动作,此时就完成了拖拽操作

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


    1.8 执行JavaScript

    对于某些操作selenium API 并没有提供 例如下拉进度条 可以使用 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提示框

    1.9 获取节点信息

    获取属性
    get_attribute() 方法 获取节点属性 前提是选中这个节点

    示例:驱动浏览器打开知乎页面 获取知乎log节点 打印出class

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

    获取文本值
    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)

    获取 ID 位置 标签名和大小

    id属性可以获取id location属性获取该节点在页面中相对位置,tag_name属性获取标签名 size获取节点大小(宽高)

    示例: 获得“提问”按钮节点 调用id location tag_name size属性分别获取对应的属性值

    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)

    1.10 切换frame

    页面中有一种节点iframe 也就是frame 相当于当前页面的子页面 结构和外部网页结构完全一致
    selenium 打开页面默认是在父级frame里面操作 如果里面还子页面是获取不到里面节点的
    需要使用 switch_to.frame() 方法切换子frame

    示例:获取动作链接操作网页的logo

    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')#切换到子frame
    try:
      logo = browser.find_element_by_class_name('logo')
    except NoSuchElementException:
      print('NO LOGO')
    browser.switch_to.parent_frame()#切换到父frame
    logo = browser.find_element_by_class_name('logo')
    print(logo)
    print(logo.text)

    1.11 延时等待

    selenium中get方法会在网页框架加载结束后结束执行 如果此时获取page_source 可能并不是网页加载完全的页面
    如果某些页面存在ajax加载 网页源代码也不一定能获取的到 所以需要延时等待一定时间,确保节点已经加载出来

    两种方式 隐式等待 显式等待

    隐式等待

    当使用隐式等待时 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)

    显式等待 until() 方法

    如果页面加载受网络条件影响 隐式效果就不是很好

    from selenium import webdriver
    from selenium.webdriver.common.by import By
    from selenium.webdriver.support import expected_conditions as EC
    from selenium.webdriver.support.wait import WebDriverWait#引入 WebDriverWait对象
    
    browser = webdriver.Chrome()
    browser.get('https://www.taobao.com/')
    wait = WebDriverWait(browser,10)
    input = wait.until(EC.presence_of_element_located((By.ID,'q')))#调用until方法 节点出现
    button = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR,'.btn-search')))#调用until方法 按钮可点击
    print(input,button)

    更多等待条件

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

    更多参考官方文档 http://selenium-python.readthedocs.io/api.html#module-selenium.webdriver.support.expected_conditions

    1.12 前进和后退

    forward() 方法前进 back()方法后退

    示例:

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

    1.13 Cookies

    获取 get_cookies()
    添加 add_cookie()
    删除 delete_all_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':'wwww.zhihu.com','value':'germery'})
    print(browser.get_cookies())
    browser.delete_all_cookies()
    print(browser.get_cookies())

    1.14 选项卡管理

    在访问网页时会出现一个个选项卡 selenium可以对选项卡进行操作

    示例:

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

    1.15 异常处理

    在使用selenium的过程中 难免会出现一些异常 例如 超时 节点未找到 一旦出现此类错误程序就不会执行了
    使用 try except 捕获异常

    示例:节点未找到

    from selenium import webdriver
    
    browser = webdriver.Chrome()
    browser.get('https:www.baidu.com')
    browser.find_element_by_id('hello')

    报错 NoSuchElementException

    防止程序遇到异常中断 捕获异常示例:

    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.webdriver.common.exceptions

  • 相关阅读:
    angularjs 学习笔记(一)
    iconfont项目成员添加不进去的问题
    服务器webapi集成极光推送学习笔记
    winform closing事件注册
    asp.net core webapi 似乎未安装在 IIS 中承载 .NET Core 项目所需的 AspNetCoreModule。请尝试修复 Visual Studio 以纠正该问题。
    css 行内元素设置宽高
    透过浏览器看HTTP缓存[转载]
    矢量字体图标
    HTML5新特性之WebRTC[转]
    一个前后端分离方案[转载]
  • 原文地址:https://www.cnblogs.com/liuxiaosong/p/10363961.html
Copyright © 2011-2022 走看看