JavaScript动态渲染页面,他的分页部分有js生成,并不是原始的HTML代码css
如淘宝使用request只能请求到页面大体框架,没法拿到商品数据,或部分网站换页时url不发生变化。html
或者使用Ajax开发的网站(现在日头条),他的接口有不少加密处理(搜索信息后信息URL通过加密处理,很难找到规律)python
Python中提供了不少模拟浏览器的库,selenium ,pyV8等,来解决动态渲染的页面。web
selenium是一个自动化测试工具,利用它能够驱动浏览器执行特定的动做,如点击、下拉等操做。同时也能够获取浏览器当前呈现的页面渲染,作到可见便可爬。用于动态页面爬取(通过js渲染的页面)ajax
以谷歌浏览器为例,了解selenium的使用chrome
须要安装好谷歌浏览器,并配置好ChromeDriverapi
先去谷歌浏览器看版本,下载Chromedriver:http://chromedriver.storage.googleapis.com/index.html浏览器
配置环境变量:将下载好的可执行文件放入python的Scripts目录下,添加至环境变量网络
验证:在cmd中执行ChromeDriver,会返回版本号session
解决安装报错问题: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)) #<selenium.webdriver.remote.webelement.WebElement (session="af859fdfb659b14f954adaec944bb0ef", element="0.7941017431137989-1")> #<class 'selenium.webdriver.remote.webelement.WebElement'> 返回结果为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