• Python爬虫:selenium动态加载HTML的常用方法【汇总笔记】


    前言

            Selenium 是一个用于Web应用程序测试的工具

            Selenium 测试直接运行在浏览器中,就像真正的用户在操作一样。支持的浏览器包括IE(7, 8, 9, 10, 11),Mozilla FirefoxSafariGoogle ChromeOpera,Edge等。

            这个工具的主要功能包括:

    • 浏览器兼容性测试:测试应用程序看是否能够很好的工作在不同浏览器和操作系统之上;
    • 系统功能测试:创建回归测试检验软件功能和用户需求;
    • 支持自动录制动作和自动生成.Net、JavaPerl等不同语言的测试脚本。

            通过本篇,你将学会使用 selenium 动态加载HTML的技巧,包括:操作输入框,键盘,下拉条,页面跳转,标签内容读取...。


    正文

            Selenium 是浏览器自动测试框架,模拟浏览器,驱动浏览器执行特定的动作,并可获取浏览器当前呈现的页面的源代码,可见即可爬。正是利用了这一特点,Python 可以实现对动态页面的渲染,做到可见即可爬。

    一、chromedriver 驱动安装

            Selenium 相当于机器人,可以模拟人在浏览器中的行为,并自动处理浏览器中的行为,如:单击、翻页、输入数据、回车和删除cookie操作。 而 Chromedriver 是 Chrome 浏览器的驱动程序,可以移动浏览器。

    1. 驱动程序介绍

            驱动器因浏览器而异,案例以 Chrome 浏览器为例,以下是各种浏览器及其相应的驱动程序:

    浏览器驱动地址
    Chromehttp://chromedriver.storage.googleapis.com/index.html
    Edgehttps://developer.Microsoft.com/en-us/Microsoft-edge/tools/web驱动程序/
    Firefoxhttps://github.com/Mozilla/gecko driver/releases
    Safarihttps://WebKit.org/blog/6900/web驱动程序- support-in-safari-10

    2. 驱动程序安装

            注意:Chromedriver 要下载与本地 Chrome 浏览器相对应的版本。

            建议:直接使用 Chromedriver 驱动的绝对路径,这样做能规避很多坑,听我的没错。

    1. from selenium import webdriver
    2. # 指定chromedriver的绝对路径
    3. driver_path = r'C:\Users\Administrator\Desktop\chromedriver.exe'
    4. # 初始化driver
    5. drive = webdriver.Chrome(executable_path=driver_path)
    6. # 请求页面,打开网页
    7. drive.get("https://www.baidu.com/")
    8. # 通过page_source获取网页源代码
    9. print(drive.page_source)
    10. # 关闭网页
    11. drive.close()

            Chromedriver 主要负责爬取动态页面的前面部分 -- 打开HTML页面,后面页面的渲染和操作,就是 Selenium 的工作内容了。


    二、Selenium 插件安装

            在【Terminal】控制台"pip install selenium "命令导入,或者在导航栏下【Pycharm - Settings - Python Interpreter 】自动导入插件,以后者为例:


    三、Selenium 常用方法

    1. 获取节点信息

            据说旧版本是使用【find_element_by_xx】方法获取节点,新版本已经不可用了,我目前使用的 Selenium 为【4.4.3】版本:

    • 获取单个节点信息(多个则匹配第一个):find_element(By.xx, 'xx')
    • 获取多个节点信息(加S):find_elements(By.xx, 'xx')

    常用方法

    描述

    By.ID根据id值获取对应的节点
    By.NAME根据name值获取对应的单个或多个节点
    By.TAG_NAME根据节点名获取节点
    By.CLASS_NAME根据class值获取节点
    By.LINK_TEXT根据链接文本获取对应的节点
    By.PARTIAL_LINK_TEXT根据部分链接文本获取对应的节点
    By.CSS_SELECTOR根据CSS选择器获取节点,对应的value字符串字符串CSS位置
    By.XPATH根据By.XPATH获取节点,对应的value字符串节点位置
    • 案例:
    1. from selenium import webdriver # 浏览器驱动
    2. from selenium.webdriver.common.by import By # 节点定位
    3. driver = webdriver.Chrome()
    4. driver.get('https://www.jd.com/')
    5. # 通过id属性获取节点
    6. driver.find_element(By.ID, 'key').send_keys("华为mate50")
    7. # 通过class属性获取节点,并触发点击事件
    8. driver.find_element(By.CLASS_NAME, 'button').click()
    9. time.sleep(5)
    10. driver.close()
    • HTML说明:输入框和按钮的属性分别是【id="key"】和【class="button"】

    2. 获取元素属性

    常用方法

    描述

    get_attribute(xx)获取当前节点xx属性
    id获取当前节点id
    location获取当前节点位置
    tag_name获取当前节点名称
    size获取当前节点大小
    text获取当前节点文本
    • 案例:
    1. from selenium import webdriver
    2. driver = webdriver.Chrome()
    3. driver.get('https://www.jd.com/')
    4. el_div = driver.find_element(By.ID, 'key')
    5. print(el_div)
    6. print(el_div.get_attribute("class")) # class属性
    7. print(el_div.id) # id
    8. print(el_div.location) # 位置
    9. print(el_div.tag_name) # 标签名
    10. print(el_div.size) # 大小
    11. print(el_div.text) # 文本

    3. 页面交互:搜索框输入,上下滚动下拉条,页面前进和后退

    常用方法描述
    send_keys(var str)标签栏输入 str,需要先获取标签位置

    send_keys(Keys.PAGE_UP)

    翻页键上(Page Up),需要先获取标签位置

    send_keys(Keys.PAGE_DOWN)

    翻页键下(Page Down),需要先获取标签位置

    execute_script('window.scrollTo(0,document.body.scrollHeight)')向下滚动到底部
    execute_script('window.scrollTo(0,0)')向上滚动到顶部
    execute_script('window.scrollTo(0,int n)')

    向下滚动 n px 位置

    script = "arguments[0].scrollIntoView();";
    driver.execute_script(script, driver.find_element(By.xx, 'xx'))
    向下滚动到目标元素位置,如:ID = xx
    • 案例:
    1. import time # 时间控制
    2. from selenium import webdriver # 浏览器驱动
    3. from selenium.webdriver import Keys # 键盘驱动
    4. from selenium.webdriver.common.by import By # 节点定位
    5. driver = webdriver.Chrome()
    6. driver.get('https://www.jd.com/')
    7. # 根据id属性获取【输入框】
    8. _input = driver.find_element(By.ID, 'key')
    9. # 标签内输入搜索内容
    10. _input.send_keys('华为mate50')
    11. # 标签内操作向上,向下翻页
    12. _input.send_keys(Keys.PAGE_DOWN)
    13. _input.send_keys(Keys.PAGE_UP)
    14. # 根据class属性获取【搜索】按钮,触发点击事件
    15. driver.find_element(By.CLASS_NAME, 'button').click()
    16. # 向下滚动到底部
    17. driver.execute_script('window.scrollTo(0,document.body.scrollHeight)')
    18. # 向上滚动到顶部
    19. driver.execute_script('window.scrollTo(0,0)')
    20. # 向下滚动1000位置
    21. driver.execute_script('window.scrollTo(0,1000)')
    22. time.sleep(2)
    23. # 向下滚动目标元素位置
    24. script = "arguments[0].scrollIntoView();";
    25. driver.execute_script(script, driver.find_element(By.ID, 'J_bottomPage'))
    26. time.sleep(2)
    27. driver.get('https://www.baidu.com/')
    28. driver.back()
    29. time.sleep(2)
    30. driver.forword()
    31. time.sleep(2)
    32. driver.close()
    • 输入+点击的代码可以简化一下:
    driver.find_element(By.ID, 'key').send_keys("华为mate50")

    4. 页面等待:显式,隐式

            当进入一个新的网页时,有时网页的加载并没有那没快,当网速很慢时尤其明显,特别是针对商品列表,图片类的信息,这时候是爬不到完整数据的,所以,我们需要等待页面加载完成。

            等待的方式有3种:

    • 强制等待:必须等这么久,没有任何前提条件,和页面有没有渲染无关;
    • 隐性等待:设置一个时间,在设置的时间内,如果页面加载完成了就进行下一步;如果没有加载完成,则会报超时异常;
    • 显式等待:设置一个等待时间,一个间隔时间,每隔一段时间执行下util中的方法,直到等待时间结束。

            注意:虽然 time.sleep(n) 简单,但是有时设置的睡眠时间过长,干等很浪费效率的,所以一般只用在想要暂停代码查看页面效果的地方,就像案例中一样。

    使用方法描述
    强制time.sleep(int n)强制等待 n 秒,不关注页面渲染情况
    隐式driver.implicitly_wait(int n)等待 n 秒,如果页面加载出来就继续,否则报异常
    显式wait = WebDriverWait(driver, int n, int m)
    wait.until(EC.presence_of_element_located((By.By.xx, 'xx')))

    等待 n 秒,每隔 m 秒 加载一下 until 方法,如果 until 方法内的属性加载出来则继续,否则循环,直到 n 秒结束继续执行。

    注:xx代表标签属性

    • 案例:
    1. import time # 时间控制
    2. from selenium import webdriver # 浏览器驱动
    3. from selenium.webdriver.common.by import By # 节点定位
    4. driver = webdriver.Chrome()
    5. driver.get('https://www.jd.com/')
    6. # 根据id属性获取【搜索框】位置,输入搜索内容
    7. driver.find_element(By.ID, 'key').send_keys("华为mate50")
    8. # 根据class属性获取【搜索】按钮位置,触发点击事件
    9. driver.implicitly_wait(5)
    10. driver.find_element(By.CLASS_NAME, 'button').click()
    11. wait = WebDriverWait(driver, 10, 0.2)
    12. wait.until(EC.presence_of_element_located((By.CLASS_NAME, "p-img")))
    13. # 向下滚动到底部
    14. driver.execute_script('window.scrollTo(0,document.body.scrollHeight)')
    15. time.sleep(3)
    16. # 向上滚动到顶部
    17. driver.execute_script('window.scrollTo(0,0)')
    18. time.sleep(3)
    19. driver.close()

    5. 键盘事件

    代码

    含义

    Keys.BACK_SPACE

    回退键(BackSpace)

    Keys.TAB

    制表键(Tab)

    Keys.ENTER

    回车键(Enter)

    Keys.SHIFT

    大小写转换键(Shift)

    Keys.CONTROL

    Control键(Ctrl)

    Keys.ALT

    ALT键(Alt)

    Keys.ESCAPE

    返回键(Esc)

    Keys.SPACE

    空格键(Space)

    Keys.PAGE_UP

    翻页键上(Page Up)

    Keys.PAGE_DOWN

    翻页键下(Page Down)

    Keys.END

    行尾键(End)

    Keys.HOME

    行首键(Home)

    Keys.LEFT

    方向键左(Left)

    Keys.UP

    方向键上(Up)

    Keys.RIGHT

    方向键右(Right)

    Keys.DOWN

    方向键下(Down)

    Keys.INSERT

    插入键(Insert)

    DELETE

    删除键(Delete)

    NUMPAD0 ~ NUMPAD9

    数字键1-9

    F1 ~ F12

    F1 - F12键

    (Keys.CONTROL, ‘a’)

    组合键Control+a,全选

    (Keys.CONTROL, ‘c’)

    组合键Control+c,复制

    (Keys.CONTROL, ‘x’)

    组合键Control+x,剪切

    (Keys.CONTROL, ‘v’)

    组合键Control+v,粘贴

    6. selenium转BeautifulSoup

            根据小编的开发经验,selenium 很擅长模拟和测试,它的特性是BeautifulSoup不具备的,但是对于取值操作,简单的还好,复杂点的比如循环

  • 标签这种操作,我还是觉得BeautifulSoup更方便。

            在爬虫的世界里,大量有价值的数据都是循环展现的,比如:某排行榜,某商品列表等...所以,selenium+BeautifulSoup的操作必不可少。

    • 核心代码
    1. from selenium import webdriver # 浏览器驱动
    2. from bs4 import BeautifulSoup # 解析html
    3. driver = webdriver.Chrome()
    4. driver.get('https://www.jd.com/')
    5. # 获取完整渲染的网页源代码
    6. pageSource = driver.page_source
    7. soup = BeautifulSoup(pageSource,'html.parser')
    8. # ...

    四、注意事项

    4.1 no such element: Unable to locate element

            在某些场景下使用 selenium 的 driver.find_element(By.CLASS_NAME,'xxxx') 定位web元素的时候,会提示找不到定位元素的异常,比如:我们案例中要定位的包含 class="button cw-icon" 属性的按钮。

    • 异常原文

    selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {"method":"css selector","selector":".button cw-icon"}

    • 原因分析

            经过认真检查,发现从web上获取的元素的class_name并没有错,问题的原因只能是多个属性间的空格“ ”不能被 find_element() 识别造成的。

    • 解决办法

            针对前端代码一个标签内使用多个属性值的情况,我们只需要把class_name里面的空格间隔符替换成英文的“.”就可以了。

    1. # 注释掉的为原方法,未注释的是修改以后的方法
    2. # driver.find_element(By.CLASS_NAME,'button cw-icon').click()
    3. driver.find_element(By.CLASS_NAME,'button.cw-icon').click()

    4.2 其他 ...


  • 相关阅读:
    Google 开源库Guava详解(集合工具类)—Maps、Multisets、Multimaps
    JAVA基于web的学校工资管理系统计算机毕业设计Mybatis+系统+数据库+调试部署
    腾讯薪酬制度改革引争议:升职后不立即加薪,还有可能被降薪?
    计算机毕设 SpringBoot+Vue校园网课管理系统 网上选课系统 疫情网课管理系统Java Vue MySQL数据库 远程调试 代码讲解
    Arthas使用指北——命令、原理及案例
    Xcode 15.3 Archive失败
    (附源码)spring boot学业指导系统 毕业设计 030958
    选择文件如何控制,已经选择了一个文件再选时就必须也在当前文件夹选 js
    CloudKit提示Permission Failure:Invalid bundle ID for container 错误的超详细解决
    每天40min,我们一起用70天稳扎稳打学完《JavaEE初阶》——33/70 第三十三天【JavaScript(webapi)】
  • 原文地址:https://blog.csdn.net/weixin_44259720/article/details/127101693