动态渲染页面爬取
JavaScript动态渲染页面,他的分页部分有js生成,并非原始的HTML代码
如淘宝使用request只能请求到页面大致框架,无法拿到商品数据,或部分网站换页时url不发生变化。
或者使用Ajax开发的网站(如今日头条),他的接口有很多加密处理(搜索信息后信息URL经过加密处理,很难找到规律)
Python中提供了很多模拟浏览器的库,selenium ,pyV8等,来解决动态渲染的页面。
selenium的使用
selenium是一个自动化测试工具,利用它可以驱动浏览器执行特定的动作,如点击、下拉等操作。同时也可以获取浏览器当前呈现的页面渲染,做到可见即可爬。用于动态页面爬取(经过js渲染的页面)
准备工作
以谷歌浏览器为例,了解selenium的使用
需要安装好谷歌浏览器,并配置好ChromeDriver
先去谷歌浏览器看版本,下载Chromedriver:http://chromedriver.storage.googleapis.com/index.html
配置环境变量:将下载好的可执行文件放入python的Scripts目录下,添加至环境变量
验证:在cmd中执行ChromeDriver,会返回版本号
安装selecnium库
解决安装报错问题:https://blog.csdn.net/ever_peng/article/details/80089095
from selenium import webdriver
brower = webdriver.Chrome()
#打开一个新的Crome页面则环境配置成功
基本使用
from selenium import webdriver#用于打开浏览器
from selenium.webdriver.support.wait import WebDriverWait#用于设置等待时间
from selenium.webdriver.common.keys import Keys#用于按键操作
from selenium.webdriver.common.by import By#用于匹配节点
from selenium.webdriver.support import expected_conditions as EC#用于等待时判断节点是否加载,如果没有,继续在规定的时间加载
#打开谷歌浏览器
brower = webdriver.Chrome()
try:
#请求百度网站
brower.get('https://www.baidu.com')
#获取ID属性为kw的节点,用于输入要搜索的信息
input = brower.find_element_by_id('kw')
#在搜索框输入python
input.send_keys('python')
input.send_keys(Keys.ENTER)#keys是获取键盘的按键相当于一个回车操作
wait = WebDriverWait(brower,10)#等待页面加载
#判断页面是否响应到id属性为content_left的内容
#写的时候是以元组形式 注意括号的个数
wait.until(EC.presence_of_element_located((By.ID, 'content_left')))
finally:
#关闭浏览器
#brower.close()
pass
声明浏览器对象
selenium支持多种浏览器,如chrome Firefox 也支持无界面的浏览器,如PhantomJS
from selenium import webdriver
brower = webdriver.Chrome()#谷歌
brower = webdriver.Firefox ()#火狐
brower = webdriver.PhantomJS()#phantomJS
#完成浏览器对象的初始化并将其赋值为brower这个对象。由此调用broweer对象,让浏览器执行对应的操作。
访问页面
使用get()方法来请求网页,参数传输链接url即可,如get方法访问淘宝页面,打印源代码
from selenium import webdriver
brower = webdriver.Chrome()
brower.get('https://www.taobao.com')
#获取响应到的网页源码
print(brower.page_source)
查找节点
selenium可以驱动浏览器完成各种操作,如填充表格、模拟点击等操作,如向某个输入框输入文本操作
单个节点
根据xpath css选择器进行选择
#获取id属性为“q”的节点
input_1 = brower.find_element_by_id('q')
input_2 = brower.find_element_by_css_selector('#q')
input_3 = brower.find_element_by_xpath('//*[@id='q']')
print(input_1)
print(type(input_1))
#
#
返回结果为webElement类型
所有获取单个节点的方法
browser.find_element_by_id
browser.find_element_by_name
browser.find_element_by_class_name
#使用class_name匹配节点时,如果该节点class属性有多个值时,只需要用其中一个值进行匹配,多个值同时匹配则产生异常
browser.find_element_by_tag_name
browser.find_element_by_link_text
browser.find_element_by_css_selector
browser.find_element_by_xpath
此外,selenium还提供了通用方法find_element()
他需要传入两个参数,查找方式By和值,实际为browser.find_element_by_id()的通用方法
browser.find_element(By.ID, 'q')
from selenium.webdriver.common.by import By
browser.find_element(By.ID, 'q')
多个节点
要匹配多个节点时使用find_element()只能获取到一个节点,所以此时需要find_elements()方法,两个之间的区别为匹配多个节点时要用elements
节点交互
selenium可以驱动浏览器做一系列操作,常见的send_keys()方法,清空文字是使用clear()方法,点击按钮click()
练习:使用selenium请求京东,在搜索框输入荣耀20,然后等页面加载出内容后,睡眠3秒,再去搜索华为p30
节点.clear() 节点.click() 节点.send_keys()
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.common.keys import Keys
from selenium import webdriver
import time
brower = webdriver.Chrome()
try:
brower.get('https://www.jd.com/')
input = brower.find_element_by_id('key')
input.send_keys('荣耀20')
input.send_keys(Keys.ENTER)
#按钮操作
#button = brower.find_element+by_class_name('button')
wait = WebDriverWait(brower,3)#等待页面加载
time.sleep(3)
print('3秒后')
input = brower.find_element_by_id('key')
input.clear()
input.send_keys('荣耀P30')
input.send_keys(Keys.ENTER)
finally:
pass
如果class属性里面有两个值,中间用空格隔开,用class_name匹配节点的时候只需要匹配其中一个,多了是找不到的
获取节点信息
通过page_source属性可以获取网页源代码,接着可以使用解析库(如正则,bs4等)来提取信息。
selenium也提供了节点选择方法,返回webElement类型,可以通过一些方法提取节点属性、文本等。
获取属性
可以使用get_attribute()方法来获取节点的属性,前提去先选中节点。
#获取猫眼网的图片链接
from selenium import webdriver
brower = webdriver.Chrome()
brower.get('https://maoyan.com/board/4')
input_2 = brower.find_elements_by_xpath('//img[@class="board-img"]')#注意这里是elements
print(type(input_2))
for i in input_2:
print(i.get_attribute('data-src'))
获取文本
每一个web element对象都有一个text属性,通过该属性可以获取节点的文本信息
#获取top100电影名称
name = browser.find_elements_by_xpath( '//p[@class="name"]/a') print(len(name))
for i in name:
print(i.text)
延时等待
selenium中get()方法会在网页框架加载结束后执行,此时如果获取page_source获取网页源码可能得到结果不是浏览器完全加载后的页面内容。
如果一些页面有额外的ajax请求,则在此处需要延时等待一段时间,确保信息已经加载出来。
延时等待分为:显式等待和隐式等待
隐式等待
使用隐式等待的时候,如果selenium没有在DOM中找到节点将继续等待,直到超时设定时间后抛出timeout异常,默认时间为0,以秒为单位。
from selenium import webdriver
brower = webdriver.Chrome()
brower.implicitly_wait(10)
brower.get('url')
获取淘宝首页内容,查看设置延时等待与不设置响应的内容是否是一致的
如果有延时等待,则程序在get()请求后开始在延时时给定的时间内加载数据,同时匹配网页内容。
from selenium import webdriver
browser = webdriver.Chrome()
browser.implicitly_wait(20)
browser.get('https://www.taobao .com/')
#获取信息
# print(browser.page_source)
print(len(browser.find_elements _by_xpath('//h4[@class="aall"]'))) browser.close()
显式等待
隐式等待效果一般,因为只规定了固定的时间,而页面加载信息时间会受到网络条件影响
显式等待它指定要查找的内容,然后指定时间进行等待。如果在规定时间加载到这个节 点则返回查找的节点,如果在规定时间依然没有加载到该节点数据,则抛出异常
移动右侧下拉条
#将下拉条从顶部拖拽到中间位置
brower.execute_script('window.scrollTo(0,document.body.scrollHeight/2)')
前进和后退
使用back()昂发进行后退,使用forward()方法进行前进
from selenium import webdriver
import time
browser=webdriver.Chrome()
browser.get('https://www.baidu.com/')
browser.get('https://www.taobao.com/')
browser.get('https://www.jd.com/')
browser.back()
time.sleep(10)
browser.forward()
捕获异常
from selenium.common.exceptions import TimeoutException
#导入异常
try :
pass
except TimeoutException:
pass
finally:
pass