动态渲染页面爬取 【selenium】
一.Selenium使用
Selenium是一个自动化测试工具,利用它可以驱动浏览器执行特定的动作,如点击、下拉等
操作,同时还可以获取浏览器当前呈现的页面的源代码,做到可见即可爬。对于一些Javascript
动态渲染的页面来说,此种抓取方式非常有效。
二.配置
1.下载对应浏览器chromedrive将环境变量配置
2.验证安装
安装selenium
pip3 install selenium
三.基本使用
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("http://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'))) current_url = browser.current_url cookie = browser.get_cookies() print(browser.page_source) finally: browser.close()
四.步骤
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("http://www.baidu.com") #输出页面的源代码 print(browser.page_source) #关闭浏览器 browser.close()
3.查找节点
1.单个节点
from selenium import webdriver #操作谷歌浏览器 browser = webdriver.Chrome() #打开网站 browser.get("http://www.baidu.com") #查找元素三种方式, #查找元素 input_first = browser.find_element_by_id("kw") #选择器查找 input_second = browser.find_element_by_css_selector("#kw") #xpath方式查找 input_third = browser.find_element_by_xpath('//*[@id="kw"]') #输出 print(input_first,input_second,input_third) #输出页面的源代码 print(browser.page_source) #关闭浏览器 browser.close()
2.多个节点
1.节点操作
查找的元素如果就唯一,那么单个节点有效,但是多个就需要多个节点
from selenium import webdriver from selenium.webdriver.common.by import By #操作谷歌浏览器 browser = webdriver.Chrome() #打开网站 browser.get("http://www.taobao.com") #查找元素 lis = browser.find_elements_by_css_selector('.service-bd li') #也可以使用通用方法 lis = browser.find_elements(By.CSS_SELECTOR,'.service-bd li') #输出页面的源代码 print(browser.page_source) #关闭浏览器 browser.close()
2.节点交互
selenium可以驱动浏览器来执行一些操作,也就是说可以让浏览器模拟执行一些动作。
更多动作:http://selenium-python.readthedocs.io/api.html#moudle-selenium.webdriver.remote.webelement
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
from selenium import webdriver import time #打开浏览器 browser = webdriver.Chrome() url = "http://www.baidu.com" browser.get(url) #找到输入框 input = browser.find_element_by_id("kw") #输入 input.send_keys("草泥马") #等待1s time.sleep(1) #清除 input.clear() input.send_keys("多么可爱") #点击百度一下按钮 button = browser.find_element_by_class_name("s_btn") button.click()
3.动作链
只有点击和输入还是不够的,还需要模拟鼠标的拖动,键盘按键等
更多动作链:https://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" #打开网站 browser.get(url)
#框架iframe的id browser.switch_to.frame('iframeResult') #找到起点和终点 source = browser.find_element_by_css_selector("#draggable") target = browser.find_element_by_css_selector("#droppable") #浏览器加载动作链 actions = ActionChains(browser) #创建起始位置和终点位置路径 action.drag_and_drop(source,target) #执行拖拽 actions.perform()
webDriver只能在一个页面上对元素识别和定位,对于frame/iframe表单内嵌页面上的元素无法直接定位,此时就需要通过switch_to.frame()方法将当前定位的主题切换为iframe表单的内嵌页面中。
4.执行JavaScript
对于某些操作,selenium API并没有提供。比如,下拉进度条,它可以直接模拟运行JavaScript,此时使用
execute_script()方法即可实现。
from selenium import webdriver #导入动作链 from selenium.webdriver import ActionChains browser = webdriver.Chrome() url = "http://www.zhihu.com/explore" #打开网站 browser.get(url) browser.execute_script('window.scrollTo(0,document.body.scrollHeight)') browser.execute_script('alert("到底端了")')
5.获取节点信息
1.获取属性
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
from selenium import webdriver #导入动作链 from selenium.webdriver import ActionChains browser = webdriver.Chrome() url = "http://www.baidu.com" #打开网站 browser.get(url) #找到logo id的节点 logo = browser.find_element_by_id("lg") #输出属性 print(logo) print(logo.get_attribute('class'))
2.获取文本
获取文本相当于Beautifulsoup的get_text(),pyquery的text()
from selenium import webdriver #导入动作链 from selenium.webdriver import ActionChains browser = webdriver.Chrome() url = "http://www.baidu.com" #打开网站 browser.get(url) #找到logo id的节点 btn = browser.find_element_by_class_name("s_btn") #文本 print(btn.text)
3.获取id、位置、标签名和大小
from selenium import webdriver #导入动作链 from selenium.webdriver import ActionChains browser = webdriver.Chrome() url = "http://www.baidu.com" #打开网站 browser.get(url) #找到logo id的节点 btn = browser.find_element_by_class_name("s_btn") #获取id 位置 标签名和大小 print(btn.id) print(btn.location) print(btn.tag_name) print(btn.size)
6.切换Frame
我们知道网页种有一种节点叫做iframe,也就是子Frame,相当于页面的子网页,它
的结构和外部网页的结构完全一致。selenium打开页面后,它默认是在父级Frame里面
操作,而此时如果页面中还有子Frame,它是不能获取到子Frame里面的节点的。这时
就需要使用switch_to.frame()方法来切换Frame
import time from selenium import webdriver from selenium.common.exceptions import NoSuchElementException #启动webdriver 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 logo = browser.find_element_by_class_name('logo') except NoSuchElementException: print('No Logo') #切换到父级frame browser.switch_to.parent_frame() #找到类名为logo logo = browser.find_element_by_class_name('logo') print(logo) print(logo.text)
7.延时等待
在Selenium中,get()方法会在网页框架加载结束后结束执行,此时如果获取page_source,可能并不是浏览器完全加载完成的页面,如果某些页面有额外的Ajax请求,我们在网页源代码中也不一定能成功获取到。所以,这里需要延时等待一定时间,确保节点已经加载出来。
1)隐式等待
当使用隐式等待执行测试的时候,如果selenium没有在DOM中找到节点,将继续等待,超出设定时间后,则抛出找不到节点的异常,话句话说,当查找节点而节点并没有立即出现的时候,隐式等待将等待一段时间再查找DOM,默认的时间是0
from selenium import webdriver#启动webdriver browser = webdriver.Chrome() #访问地址 url = "http://www.zhihu.com/explore" #使用implicitly_wait实现隐式等待 browser.implicitly_wait(10) browser.get(url) input = browser.find_element_by_class_name('ExploreHomePage-ContentSection-header') print(input)
2)显式等待
隐式等待的效果其实并没有那么好,因为我们只规定了一个固定的时间,而页面的加载时间会受到网络条件的影响。这里还有一种更合适的显式等待方法,它指定要查找的节点,然后指定一个最长等待时间。如果在规定时间内加载出来了这个节点,就返回查找的节点;如果到了规定时间依然没有加载出该节点,则抛出超时异常
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 ##from selenium.common.exceptions import NoSuchElementException #启动webdriver browser = webdriver.Chrome() #访问地址 url = "http://www.taobao.com/" browser.get(url) #引入WebDriverWait对象,指定最长等待时间 wait = WebDriverWait(browser,10) #使用until()方法传入等待条件,节点 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'))) print(input,button)
显式等待和隐式等待的区别?
8.前进和后退
import time from selenium import webdriver browser = webdriver.Chrome() browser.get("http://www.baidu.com") browser.get("http://www.taobao.com") browser.get("http://www.zhihu.com") #返回 browser.back() time.sleep(1) #前进 browser.forward() browser.close()
9.Cookie
使用selenium,还可以方便地对cookie进行操作,例如获取、添加、删除Cookies等。
from selenium import webdriver browser = webdriver.Chrome() browser.get("http://www.zhihu.com/explore") #打印cookie print(browser.get_cookies()) #添加cookie browser.add_cookie({'name':'name','domain':'www.zhihu.com','value':'germey'}) #获取cookie print(browser.get_cookies()) #删除cookie browser.delete_all_cookies() print(browser.get_cookies())
10.选项卡管理
在访问网页的时候,会开启一个个选项卡。在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")
11.异常处理
在使用selenium的过程中,难免会遇到一些异常,例如超时、节点未找到等错误,一旦出现此类错误,程序便不会继续执行了。这里我们可以
使用try except语句来捕获各种异常。
from selenium import webdriver from selenium.common.exceptions import TimeoutException,NoSuchElementException browser = webdriver.Chrome() try: browser.get("https://www.baidu.com") except TimeoutException: print("超时") try: browser.find_element_by_id('hello') except NoSuchElementException: print("没有此节点") finally: browser.close()