04- 动态渲染页面爬取
文章目录
4-1 Selenium的安装
Selenium是一个自动化测试工具,利用它可以驱动浏览器执行特定的动作,如点击、下拉等操作,同时还可以获取浏览器当前呈现的页面的源代码,做到可见即可爬。对于一些JavaScipt
动态渲染的页面来说,此种抓取方式非常有效。
4 -2 Selenium相关链接
- 官方网站 :https://www.selenium.dev/
- GitHub : https://github.com/SeleniumHQ/selenium/tree/master/py
- 官方文档 : https://selenium-python.readthedocs.io/
- 中文文档 :https://selenium-python-zh.readthedocs.io/en/latest/
4-3 pip 安装
pip install selenium
4-4 ChromeDriver 的安装
安装ChromeDriver。因为只有安装ChromeDriver.才能驱动Chrom浏览器完成相对应的操作
4-5 ChromeDriver 的相关链接
- 下载地址 : https://chromedriver.storage.googleapis.com/index.html
- 下载要对应自己谷歌浏览器的版本
4-6 ChromeDriver环境配置
在Windows下,建议直接将chromedriver.exe文件拖到Python的根目录下
在配置Python的时候系统会自动把Python配置到环境中,到时候我们可以直接使用驱动就可以不用写路径问题
4-7 Selenium声明浏览器对象
Selenium支持多种的浏览器,如chrome、Firefox、Edge等
# @Time : 2020/5/11 15:01
# @Author : SmallJ
# 支持的浏览器
from selenium import webdriver
browser = webdriver.Chrome()
borwser = webdriver.Android()
borwser = webdriver.Firefox()
borwser = webdriver.Ie()
4-8 Selenium访问页面
我们可以用get()
方法来请求网页,参数传入链接URL即可。
- get : 请求的网址
- page_source : 为反映页面源代码
- close : 为关闭浏览器
# @Time : 2020/5/11 15:01
# @Author : SmallJ
# 支持的浏览器
from selenium import webdriver
# 实例化浏览器
browser = webdriver.Chrome()
# 用browser这个对象来发送请求
url = 'https://www.taobao.com/'
browser.get(url)
# page_source 为页面源代码
# 用browser这个对象来获取页面源代码
html = browser.page_source
print(html)
# close 为关闭浏览器
browser.close()
4-9 Selenium查找节点
- 单个节点
语法 | 描述 |
---|---|
find_element_by_id | 根据页面中的id属性来查找值 |
find_element_by_xpath | 根据xpath语法来进行查找值 |
find_element_by_link_text | 根据文本来进行查询 |
find_element_by_partial_link_text | 根据文本进行查询模糊查询 |
find_element_by_name | 根据name属性来进行查询 |
find_element_by_class_name | 根据class属性来进行查询 |
find_element_by_css_selector | 根据css语法来进行查找 |
- 多个节点
- 注意 : 多节点在这个方法的名称中,elment多了一个s。注意区分
Selenium可以驱动浏览器完成各种操作,比如填充表单、模拟点击等。比如,我们想要完成向某个输入框输入文字的操作,总需要知道
from selenium import webdriver
import time
browser = webdriver.Chrome()
url = 'https://www.taobao.com/'
browser.get(url)
# 根据id来进行查找
first_input = browser.find_element_by_id('q')
# 根据css来进行查找
second_input = browser.find_element_by_css_selector('#q')
# 根据Xpath来进行查找
three_input = browser.find_element_by_xpath('//*[@id="q"]')
# 关闭浏览器
browser.close()
这里我们使用3种方式获取输入框,分别是根据ID、CSS选择器、XPath获取
另外,Selenium还提供了通过方法find_element()
,它需要传入两个参数:查找方式和By值。实际上,它就是find_element_by_id()
这种方法的通过函数版本,比如 **find_element_by_id(id)
** 等价于 **find_element(By.ID)
**两者的结果是一样。
京东
from selenium import webdriver
from selenium.webdriver.common.by import By
import time
# 实例化对象
browser = webdriver.Chrome()
# 请求url
url = 'https://www.jd.com/'
browser.get(url)
time.sleep(3)
# 单节点查找
# 查找京东的搜索框
browser.find_element(By.ID, 'key').send_keys('Python人工智能')
# 查找点击按钮并进行点击事件
browser.find_element(By.XPATH, '//*[@id="search"]/div/div[2]/button/i').click()
time.sleep(5)
# 关闭浏览器
browser.close()
淘宝
from selenium import webdriver
import time
browser = webdriver.Chrome()
url = 'https://www.taobao.com/'
browser.get(url)
time.sleep(5)
# 单个节点
# 查找节点采用find来进行查找
# 在输入框输入Python send_keys 为输入内容
browser.find_element_by_css_selector('#q').send_keys('Python')
# 定位到搜索框,并进行点击事件 click为点击事件
browser.find_element_by_xpath('//*[@id="J_TSearchForm"]/div[1]/button').click()
time.sleep(5)
browser.close()
4-10 Selenium节点交互
Selenium可以驱动浏览器来执行一些操作,也就是说可以让浏览器去模拟人的行为去执行一些操作。比较常见的操作用法有:输入文字时用send_keys()
方法,清空文字时用clear()
方法,点击按钮用click()
方法
from selenium import webdriver
from selenium.webdriver.common.by import By
import time
browser = webdriver.Chrome()
url = 'https://www.taobao.com/'
browser.get(url)
time.sleep(2)
input = browser.find_element(By.ID, 'q')
# 输入内容
input.send_keys('Python')
# 清空内容
input.clear()
# 强制停止两秒
time.sleep(2)
input.send_keys('Python人工智能')
button = browser.find_element(By.XPATH, '//*[@id="J_TSearchForm"]/div[1]/button')
# 进行点击事件
button.click()
# 强制等待
time.sleep(2)
# 关闭浏览器
browser.close()
4-11 Selenium动作链
在上面的实例中,一些交互动作都是针对某个节点执行的。比如,对于输入框,我们就调用它的输入文字和清空文字方法;对于按钮,就调用它的点击方法。其实,还有另外一些操作,它们没有特定的执行对象,比如鼠标拖拽、键盘按钮等,这些动作用另外一种方式来执行,那就是动作链。
drag_and_drop(source, target)
:- drop :中文意思起点
- drag : 中文意思结束
- source : 为要拖拽元素的起点
- target : 为要拖拽元素的终点
perform(self)
- 该方法为执行动作
# @Time : 2020/5/11 20:50
# @Author : SmallJ
from selenium import webdriver
from selenium.webdriver import ActionChains
import time
# ActionChains为动作链
url = 'https://www.runoob.com/try/try.php?filename=jqueryui-api-droppable'
browser = webdriver.Chrome()
browser.get(url)
# 该请求的页面中存在页面嵌套所以需使用switch_to.frame
# switch_to.frame 为页面嵌套 根据id来取值
# 切换到页面嵌套
browser.switch_to.frame('iframeResult')
# 元素定位
# 请拖住我 source 中文意思 源代码
source = browser.find_element_by_css_selector('#draggable')
# 元素定位
# 请放置到这里 target 中文意思 目标
target = browser.find_element_by_css_selector('#droppable')
time.sleep(3)
# 进行实例化动作行为链
actions = ActionChains(browser)
# drag_and_drop
# source : 为拖拽元素的起点
# target : 为拖拽元素的终点
actions.drag_and_drop(source, target)
# perform 为方法执行动作
actions.perform()
首先,打开网页中的一个拖拽实例,然后依次选中要拖拽的节点和拖拽到目标节点,接着声明ActionChains对象并将其赋值为actions变量的drag_and_drop()
方法,再调用perform()
方法执行动作,此时就完成了拖拽操作。
4-12 Selenium执行JavaScript
对于某些操作,Selenium API并没有提供。比如,下拉进度条,它可以直接模拟运行JavaScipt此时使用execute_script()
方法即可实现
# @Time : 2020/5/12 0:31
# @Author : SmallJ
from selenium import webdriver
url = 'https://www.zhihu.com/explore'
browser = webdriver.Chrome()
browser.get(url)
browser.execute_script('window.scrollTo(0, document.body.scrollHeight)')
browser.execute_script('alert("TO Bottom")')
4-13 Selenium获取节点信息
语法 | 描述 |
---|---|
get_attribute() | 获取属性值 |
get_text() | 获取文本值 |
get_id | 获取节点 |
get_location | 获取节点在页面中的相对位置 |
tag_name | 获取标签名称 |
size | 获取节点大小 |
前面说过,通过page_source
属性可以获取网页源代码可以获取网页的源代码,接着就可以使用解析库(如正则表达式、Beautiful Soup
、pyquery
等)来提取信息
不过,既然Selenium
已经提供了选择节点的方法,返回的是WebElement
类型,那么它也有相关的方法和属性来直接提取节点信息,如属性、文本等。这样的话,我们就可以不用通过解析源代码来提取信息了。
- 获取属性
我们可以使用get_attribute()
方法来获取节点的属性,但是其前提是先选其中的这个节点。
# @Time : 2020/5/12 14:53
# @Author : SmallJ
# ActionChains 为动作行为链
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By
browser = webdriver.Chrome()
url = 'https://www.zhihu.com/explore'
# 请求该网页
browser.get(url)
# 查找属性
logo = browser.find_element(By.CLASS_NAME, 'Input')
print(logo)
print(logo.get_attribute('placeholder'))
4-14 Selenium切换Frame
我们知道网页中有一种节点叫作iframe
,也就是子Frame,相当于页面的子页面,它的结构和外部网页内容的结构完全一致。Selenium打开页面后,它的默认是在父级Frame里面的操作,而此时如果页面中还有子Frame,它是不能获取子Frame里面的节点。这时就需要使用switch_to.frame()
方法来切换Frame。
# @Time : 2020/5/12 15:21
# @Author : SmallJ
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.common.exceptions import NoSuchElementException
url = 'https://www.runoob.com/try/try.php?filename=jqueryui-api-droppable'
browser = webdriver.Chrome()
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然后再次重新获取节点。
3-15 延时等待
隐式等待
当使用隐式等待执行测试的时候,如果Selenium没有在DOM中找到节点,将继续等待,超出设定时间后,则抛出找不到节点的异常。换句话说,当查找节点而节点并没有立即出现的时候,隐式等待将等待一段时间再查找DOM,默认的时间为0秒
# @Time : 2020/5/12 16:02
# @Author : SmallJ
from selenium import webdriver
browser = webdriver.Chrome()
url = 'https://www.baidu.com/'
# 隐式等待
# 隐式等待的含义就是超出时间的范围的时候就不会继续查找,抛出异常
# time_to_wait : 为时间
browser.implicitly_wait(10)
browser.get(url)
input = browser.find_element_by_id('wrapper_wrapper')
print(input)
显示等待
隐式等待的效果并不是很好,因为我们在规定了一个固定时间,而页面的加载时间会受到网络条件的影响
这里还有一种更合适的显示等待方法,它指定要查找的节点,然后指定一个最长的等待时间。如果在规定时间内加载出来了这个节点;如果到规定时间依然没有加载出来该节点,则抛出异常。
# 显式等待
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()
url = 'https://www.taobao.com/'
browser.get(url)
# WebDriverWait 里面传递两个参数
# driver 引擎
# timeout 为超时时间
wait = WebDriverWait(browser, 10)
input_data = 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_data, button)
- 这里首先引入WebDriverWait这个对象,指定最长等待时间,然后调用它的
until()
方法,传入要等待条件expected_conditions
。比如,这里传入了presence_of_element_located
这个条件,代表节点出现的意思,其参数是节点的定位元组,也就是ID为q
的节点搜索。 - 这样可以做到的效果就是,在10秒内如果ID为
element_to_clickable
,也就是可点击,所以查找按钮时查找CSS选择器为.btn-search
的按钮,如果10内它是可点击的,也就是成功加载出来了,也就是返回这个按钮节点。 - 如果超过10秒还不可以点击,就抛出异常。