动态网页处理

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.7libsite-packagesseleniumwebdriverphantomjswebdriver.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 来驱动浏览器工作,而浏览器是一个个独立的浏览器进程。

   

原文地址:https://www.cnblogs.com/JerryZao/p/10103456.html