1、概述:
很多网站都采用AJAX 技术,SPA技术,部分都是异步动态加载的,可以提高用户体验,减少不必要的流浪,方便CDN 加速
但是,对于爬虫程序爬到的HTML页面相当于页面的模板,动态内容不在其中
解决办法之一:如果能构造一个包含js引擎的浏览器,让他加载网页并和网站交互,我们编程从这个浏览器获取内容包括动态内容,这个浏览器不需要和用户交互的界面,只要你能支持HTTP ,HTTPS 协议 和服务器交互,能解析HTML CSS JS 就行
2、PhantomJS
它是一个headless无头浏览器,支持js, 可以运行在windows, Linux, MacOS
所谓无头浏览器,就是包含JS引擎,浏览器排版引擎等核心组件,但是没有和用户交互的界面的浏览器
官网:http://phantomjs.org/
官方文档:http://phantomjs.org/documentation/
下载:http://phantomjs.org/download.html
下载对应操作系统的PhantomJS ,解压就可以使用
测试:
编写test.js ,执行: $ phantomjs/bin/phantomjs.exe test.js
3、Selenium
它是一个WEB 自动化测试工具,它可以直接运行在浏览器中,支持主流的浏览器,包括PhantomJS(无界面浏览器)
安装:
$ pip install selenium
官网:https://www.seleniumhq.org/
4、开发实战
不同浏览器都会提供操作的接口,Selelnium 就是使用这些接口来操作浏览器的。
Selenium 最核心的对象就是webdriver, 通过它 就可以操作浏览器,截图,HTTP 访问,解析HTML 等
处理异步请求:
bing的查询结果是通过异步请求返回结果,所以直接访问页面不能直接获取到搜索结果。
测试:
1 # 查询bing查询数据 2 from selenium import webdriver # 核心对象 3 import datetime 4 import random 5 import time 6 from urllib import parse 7 8 # 指定PhantomJS 的执行文件路径 9 driver = webdriver.PhantomJS('f:/phantomjs-2.1.1-windows/phantomjs-2.1.1-windows/bin/phantomjs.exe') 10 # 设置窗口大小 11 driver.set_window_size(1280,1024) # 12 13 # 打开浏览器GET 方法,模拟浏览器地址输入网址 14 url = 'http://cn.bing.com/search?' +parse.urlencode({ 15 'q':'张三' 16 }) 17 18 driver.get(url) 19 20 # 保存图片 21 def savepic(): 22 base_dir = 'f:/' 23 filename = "{}{:%Y%m%d%H%M%S}{:03}.png".format( 24 base_dir, 25 datetime.datetime.now(), 26 random.randint(1,100) 27 ) 28 29 driver.save_screenshot(filename) 30 31 savepic() 32 33 MAXRETRIEX = 5 # 最大重试次数 34 for i in range(MAXRETRIEX): 35 time.sleep(1) 36 try: 37 ele = driver.find_element_by_id('b_results')#如果查询结果来了,就会有这个id的标签 38 if not ele.is_displayed(): # 等待数据显示出来 39 continue 40 print('ok') 41 savepic() 42 break 43 except: 44 pass 45 46 driver.quit()
可能结果未必能看到,说明数据回来了,而且组织好了,但是没有显示出来,DOM 树没有渲染
可以增加判断元素是否显示的代码,直到等待的数据显示在页面上
5、下拉框处理
Selenium 专门提供了select类来处理网页中的下拉框
不过下拉框用的页面越来越少,本次使用:https://www.oschina.net/search?q=python&scope=project&fromerr=fYWMOvs4
(这种页面很笨重,每选一下,重新发起请求,但是很多东西 css等可以缓存,所以,还有使用)
这个下拉框影响下一个 下拉框:所有子类, 下面就模拟来操作下拉框,需要使用:
selenium.webdriver.suport.select.Select
测试代码:
1 # 查询bing查询数据 2 from selenium import webdriver # 核心对象 3 import datetime 4 import random 5 import time 6 from urllib import parse 7 from selenium.webdriver.support.ui import Select 8 9 # 指定PhantomJS 的执行文件路径 10 driver = webdriver.PhantomJS('f:/phantomjs-2.1.1-windows/phantomjs-2.1.1-windows/bin/phantomjs.exe') 11 # 设置窗口大小 12 driver.set_window_size(1280,1024) # 13 14 # 保存图片 15 def savepic(): 16 base_dir = 'f:/' 17 filename = "{}{:%Y%m%d%H%M%S}{:03}.png".format( 18 base_dir, 19 datetime.datetime.now(), 20 random.randint(1,100) 21 ) 22 23 driver.save_screenshot(filename) 24 25 # 打开浏览器GET 方法,模拟浏览器地址输入网址 26 url = "https://www.oschina.net/search?q=python&scope=project" 27 driver.get(url) 28 29 ele = driver.find_element_by_name('tag1') # 获取元素 30 print(ele.tag_name) # 标签名 31 print(driver.current_url)# 当前的url 32 savepic() 33 34 s = Select(ele) 35 s.select_by_index(1) 36 # s.select_by_value('309') 37 print(driver.current_url) #新页面 38 39 driver.quit()
结果:
1 D:\python3.7\lib\site-packages\selenium\webdriver\phantomjs\webdriver.py:49: UserWarning: Selenium support for PhantomJS has been deprecated, please use headless versions of Chrome or Firefox instead 2 warnings.warn('Selenium support for PhantomJS has been deprecated, please use headless ' 3 select 4 https://www.oschina.net/search?q=python&scope=project&fromerr=4VrMLlrv 5 https://www.oschina.net/search?q=python&scope=project&tag1=309&tag2=0&lang=0&os=0
||
||
6、模拟键盘操作(模拟登录)
webdriver 提供了一系列的 find 方法,用户获取一个网页中的元素,元素对象可以使用send_keys 模拟键盘输入
oschina的登录页,登录成功后,会跳转到首页,首页右上角会显示会员信息,如果未登录,无此信息。
测试:
1 # 查询bing查询数据 2 from selenium import webdriver # 核心对象 3 import datetime 4 import random 5 import time 6 from urllib import parse 7 from selenium.webdriver.support.ui import Select 8 9 # 指定PhantomJS 的执行文件路径 10 driver = webdriver.PhantomJS('f:/phantomjs-2.1.1-windows/phantomjs-2.1.1-windows/bin/phantomjs.exe') 11 # 设置窗口大小 12 driver.set_window_size(1280,1024) # 13 14 # 保存图片 15 def savepic(): 16 base_dir = 'f:/' 17 filename = "{}{:%Y%m%d%H%M%S}{:03}.png".format( 18 base_dir, 19 datetime.datetime.now(), 20 random.randint(1,100) 21 ) 22 23 driver.save_screenshot(filename) 24 25 # 打开浏览器GET 方法,模拟浏览器地址输入网址 26 url = "https://www.oschina.net/home/login" 27 driver.get(url) 28 savepic() 29 30 # 模拟输入用户名和密码 31 username = driver.find_element_by_id('userMail') # 获取元素 32 username.send_keys("wei.xu@magedu.com") 33 password = driver.find_element_by_id('userPassword') #获取元素 34 password.send_keys('magedu.com18') 35 savepic() 36 37 MAXRETRIEX = 5 # 最大重试次数 38 for i in range(MAXRETRIEX): 39 time.sleep(1) 40 print(i, driver.current_url) 41 try: 42 # 登录后右上角的元素 class = "box user-info" 43 userinfo = driver.find_element_by_class_name('user-info') 44 savepic() 45 break 46 except: 47 pass
结果:
1 0 https://www.oschina.net/home/login 2 1 https://www.oschina.net/home/login 3 2 https://www.oschina.net/home/login 4 3 https://www.oschina.net/home/login 5 4 https://www.oschina.net/home/login
登录后:
截图:
获得cookies后,可以继续后面的爬虫操作:
测试:
1 # 查询bing查询数据 2 from selenium import webdriver # 核心对象 3 import datetime 4 import random 5 import time 6 from urllib import parse 7 from selenium.webdriver.support.ui import Select 8 9 # 指定PhantomJS 的执行文件路径 10 driver = webdriver.PhantomJS('f:/phantomjs-2.1.1-windows/phantomjs-2.1.1-windows/bin/phantomjs.exe') 11 # 设置窗口大小 12 driver.set_window_size(1280,1024) # 13 14 # 保存图片 15 def savepic(): 16 base_dir = 'f:/' 17 filename = "{}{:%Y%m%d%H%M%S}{:03}.png".format( 18 base_dir, 19 datetime.datetime.now(), 20 random.randint(1,100) 21 ) 22 23 driver.save_screenshot(filename) 24 25 # 打开浏览器GET 方法,模拟浏览器地址输入网址 26 url = "https://www.oschina.net/home/login" 27 driver.get(url) 28 savepic() 29 30 # 模拟输入用户名和密码 31 username = driver.find_element_by_id('userMail') # 获取元素 32 username.send_keys("wei.xu@magedu.com") 33 password = driver.find_element_by_id('userPassword') #获取元素 34 password.send_keys('magedu.com18') 35 savepic() 36 37 MAXRETRIEX = 5 # 最大重试次数 38 for i in range(MAXRETRIEX): 39 time.sleep(1) 40 print(i, driver.current_url) 41 try: 42 userinfo = driver.find_element_by_class_name('user-info') 43 savepic() 44 break 45 except: 46 pass 47 48 49 ############### 登录后获得cookie ############### 50 cookies = driver.get_cookies() 51 print(cookies) 52 for c in cookies: 53 print(c) 54 print(type(c)) 55 56 import requests 57 from requests.cookies import RequestsCookieJar 58 59 jar = RequestsCookieJar() 60 for c in cookies: 61 jar.set(c.get('name'), c.get('value')) 62 63 print(jar) 64 headers = { 65 "User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3486.0 Safari/537.36" 66 } 67 68 print(' ============ 不带cookie ============') 69 response = requests.request('GET', url, headers= headers) 70 with response: 71 print('----', response.url) 72 73 print('================== 带cookie =============') 74 response = requests.request('GET', url, headers=headers, cookies=jar) 75 with response: 76 print('++++', response.url) 77 print(type(response.text)) 78 with open("f:/t.html", 'w', encoding='utf-8') as f: 79 f.write(response.text)
7、页面等待
越来越多的页面使用Ajax这样的异步加载技术,这就会导致代码中要访问的颜面元素,还没有被加载就被访问了。抛出异常。
方法1,线程休眠:
使用time.sleep() 来等待数据加载
配合循环一直等到数据被加载完成,可以解决很多页面动态加载或加载慢的问题,当然可以设置一个最大重试次数,以免一直循环下去,
方法2 ,Selenium 等待
Selenium 的等待分为:显示等待 和隐式等待
隐式等待: 等待指定的时间
显示等待:指定一个条件,一直等到这个条件成立后继续执行,也可以设置超时时间,超时会抛异常
参考:https://www.seleniumhq.org/docs/04_webdriver_advanced.jsp#explicit-and-implicit-waits
显示等待:
1 # 定位搜索框,搜索电影 2 from selenium import webdriver # 核心对象 3 import datetime 4 import random 5 6 from selenium.webdriver.common.by import By 7 # 键盘操作 8 from selenium.webdriver.common.keys import Keys 9 # WebDriverWait 负责循环的等待 10 from selenium.webdriver.support.wait import WebDriverWait 11 # expected_conditions 条件,负责条件触发 12 from selenium.webdriver.support import expected_conditions as EC 13 14 # 指定 PhantomJS的执行文件路径 15 driver = webdriver.PhantomJS('f:/phantomjs-2.1.1-windows/phantomjs-2.1.1-windows/bin/phantomjs.exe') 16 # 设置窗口大小 17 driver.set_window_size(1280,1024) # 18 19 # 保存图片 20 def savepic(): 21 base_dir = 'f:/' 22 filename = "{}{:%Y%m%d%H%M%S}{:03}.png".format( 23 base_dir, 24 datetime.datetime.now(), 25 random.randint(1,100) 26 ) 27 28 driver.save_screenshot(filename) 29 30 # 打开网页GET方法,模拟浏览器地址输入网址 31 url = 'https://movie.douban.com/' 32 driver.get(url) 33 34 try: 35 # element = WebDriverWait(driver,10).until( 36 # EC.presence_of_element_located( 37 # # 元素是否已经加载到DOM 中 38 # (By.ID,'inp-qurey') 39 # ) 40 # ) # 使用哪个drivel 等到什么条件ok, EC 就是等待的条件 41 42 element = WebDriverWait(driver, 10).until( 43 EC.presence_of_element_located((By.XPATH, "//input[@id='inp-qurey']")) 44 ) 45 46 element.send_keys('TRON') 47 element.send_keys(Keys.ENTER) 48 49 print(driver.current_url) 50 savepic() 51 print('============') 52 53 except Exception as e: 54 print(e) 55 finally: 56 driver.quit()
默认的查看频率是0.5 秒每天,当元素存在则立即返回这个元素
隐式等待:
如果出现No Such Element Exception 则智能的等待指定的时长,缺省值是0
1 # 定位搜索框,搜索电影 2 from selenium import webdriver # 核心对象 3 import datetime 4 import random 5 6 from selenium.webdriver.common.by import By 7 # 键盘操作 8 from selenium.webdriver.common.keys import Keys 9 # WebDriverWait 负责循环的等待 10 from selenium.webdriver.support.wait import WebDriverWait 11 # expected_conditions 条件,负责条件触发 12 from selenium.webdriver.support import expected_conditions as EC 13 14 # 指定 PhantomJS的执行文件路径 15 driver = webdriver.PhantomJS('f:/phantomjs-2.1.1-windows/phantomjs-2.1.1-windows/bin/phantomjs.exe') 16 # 设置窗口大小 17 driver.set_window_size(1280,1024) # 18 19 # 保存图片 20 def savepic(): 21 base_dir = 'f:/' 22 filename = "{}{:%Y%m%d%H%M%S}{:03}.png".format( 23 base_dir, 24 datetime.datetime.now(), 25 random.randint(1,100) 26 ) 27 28 driver.save_screenshot(filename) 29 30 # 打开网页GET方法,模拟浏览器地址输入网址 31 url = 'https://movie.douban.com/' 32 driver.get(url) 33 34 try: 35 element = driver.find_element_by_id('abcdfe') 36 37 except Exception as e: 38 print(e) 39 print(type(e)) 40 finally: 41 driver.quit()
总结:
Selenium的webdriver是其核心, 从Selenium2开始就是最重要的核心编程对象, 在Selenium3中更加是如此
和浏览器交互完全靠他, 他可以:
-
- 打开URL,可以跟踪跳转,可以返回当前页面的实际URL
- 获取页面的title
- 处理cookie
- 控制浏览器的操作, 例如 前进,后退,刷新,关闭,最大化等
- 执行JS 脚本
- 在DOM 中搜索页面 元素Web Element 指定的或一批,fing系方法
- 操作网页元素
- 模拟下拉框操作 Selelct(element)
- 在元素上模拟鼠标操作 click(
- 在元素上模拟键盘输入send_keys()
- 获取元素的文字text
- 获取元素的属性 get_attribute()
Selenium 通过Web Driver 来驱动浏览器工作,而浏览器是一个个独立的浏览器进程。