python处理Ajax技术之Selenium库

1 Ajax和动态HTML

如果提交表单之后,或从服务器获取信息之后,网站的页面不需要重新刷新,那么你访问的网站就在用 Ajax 技术。Ajax 其实并不是一门语言,而是用来完成网络任务(可以认为它与网络数据采集差不多)的一系列技术。Ajax 全称是 Asynchronous JavaScript and XML(异步 JavaScript 和 XML),网站不需要使用单独的页面请求就可以和网络服务器进行交互(收发信息)。

和 Ajax 一样,动态 HTML(dynamic HTML,DHTML)也是一系列用于解决网络问题的技术集合。DHTML 是用客户端语言改变页面的 HTML 元素。

1.1 在Python中用Selenium执行JavaScript

Selenium(http://www.seleniumhq.org/)是一个强大的网络数据采集工具,其最初是为网站自动化测试而开发的。近几年,它还被广泛用于获取精确的网站快照,因为它们可以直接运行在浏览器上。Selenium 可以让浏览器自动加载页面,获取需要的数据,甚至页面截屏,或者判断网站上某些动作是否发生。

https://pypi.org/simple/selenium/ 可以下载 Selenium 库,Selenium 自己不带浏览器,它需要与第三方浏览器结合在一起使用。可以使用 PhantomJS(http://phantomjs.org/download.html)的工具代替真实的浏览器。把 Selenium 和 PhantomJS 结合在一起,就可以运行一个非常强大的网络爬虫。

from selenium import webdriver
import time

driver = webdriver.PhantomJS(executable_path='/phantomjs-1.9.8-macosx/bin/phantomjs')#自己程序的路径
driver.get("http://pythonscraping.com/pages/javascript/ajaxDemo.html")
time.sleep(3)
print(driver.find_element_by_id('content').text)
driver.close()

这段代码用 PhantomJS 库创建了一个新的 Selenium WebDriver,首先用 WebDriver 加载页面,然后暂停执行 3 秒钟,再查看页面获取(希望已经加载完成的)内容。

1.2 Selenium 的选择器

在这个例子中,我们用的选择器是 find_element_by_id,下面的选择器也可以获取同样的结果:

driver.find_element_by_css_selector("#content")
driver.find_element_by_tag_name("div")

选择页面上具有同样特征的多个元素,可以用 elements (换成复数)来返回一个 Python 列表:

driver.find_elements_by_css_selector("#content")
driver.find_elements_by_css_selector("div")

用 BeautifulSoup 来解析网页内容,可以用 WebDriver 的 page_source 函数返回页面的源代码字符串。

pageSource = driver.page_source
bsObj = BeautifulSoup(pageSource)
print(bsObj.find(id="content").get_text())

1.3 隐式等待

隐式等待是等 DOM 中某个状态发生后再继续运行代码;显式等待明确设置了等待时间。在 Selenium库里面元素被触发的期望条件(expected condition)有很多种,包括:

  • 弹出一个提示框
  • 一个元素被选中(比如文本框)
  • 页面的标题改变了,或者某个文字显示在页面上或者某个元素里
  • 一个元素在 DOM 中变成可见的,或者一个元素从 DOM 中消失了

大多数的期望条件在使用前都需要你先指定等待的目标元素。元素用定位器(locator)指定,定位器是一种抽象的查询语言,用 By 对象表示,可以用于不同的场合,包括创建选择器。

创建选择器,配合 WebDriver 的 find_element 函数使用:

print(driver.find_element(By.ID, "content").text)
等同于 print(driver.find_element_by_id("content").text)

下面的程序用 id 是 loadedButton 的按钮检查页面是不是已经完全加载:

from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

driver = webdriver.PhantomJS(executable_path='/phantomjs-1.9.8-macosx/bin/phantomjs')
driver.get("http://pythonscraping.com/pages/javascript/ajaxDemo.html")
try:
    element = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.ID, "loadedButton")))
finally:
    print(driver.find_element_by_id("content").text)
    driver.close()

定位器通过 By 对象进行选择的策略:

•  ID
在上面的例子里用过;通过 HTML 的 id 属性查找元素。

•  CLASS_NAME
通过 HTML 的 class 属性来查找元素。

•  CSS_SELECTOR
通过 CSS 的 class 、 id 、 tag 属性名来查找元素,用 #idName 、 .className 、 tagName
表示。

•  LINK_TEXT
通过链接文字查找 HTML 的  标签。例如,如果一个链接的文字是“Next”,就可以
用 (By.LINK_TEXT, "Next") 来选择。

•  PARTIAL_LINK_TEXT
与 LINK_TEXT 类似,只是通过部分链接文字来查找。

•  NAME
通过 HTML 标签的 name 属性查找。这在处理 HTML 表单时非常方便。

•  TAG_NAME
通过 HTML 标签的名称查找。

•  XPATH
用 XPath 表达式(语法在下面介绍)选择匹配的元素。

XPATH语法简介:

XPath(XML Path,XML 路径)是在 XML 文档中导航和选择元素的查询语言。它由W3C 于 1999 年创建,在 Python、Java 和 C# 这些语言中有时会用 XPath 来处理 XML文档。

在 XPath 语法中有四个重要概念:

  • • 根节点和非根节点

♦/div 选择 div 节点,只有当它是文档的根节点时
♦//div 选择文档中所有的 div 节点(包括非根节点)

  • • 通过属性选择节点

♦//@href 选择带 href 属性的所有节点
♦//a[@href='http://google.com'] 选择页面中所有指向 Google 网站的链接

  • • 通过位置选择节点

♦//a[3] 选择文档中的第三个链接
♦//table[last()] 选择文档中的最后一个表
♦//a[position() < 3] 选择文档中的前三个链接

  • • 星号( * )匹配任意字符或节点,可以在不同条件下使用

♦//table/tr/* 选择所有表格行 tr 标签的所有的子节点(这很适合选择 th 和 td 标签)
♦//div[@*] 选择带任意属性的所有 div 标签

1.4 处理重定向

客户端重定向是在服务器将页面内容发送到浏览器之前,由浏览器执行 JavaScript 完成的页面跳转,而不是服务器完成的跳转。服务器端重定向一般都可以轻松地通过 Python 的 urllib 库解决,不需要使用 Selenium客户端重定向。

Selenium 可以执行 JavaScript 重定向,我们可以用一种智能的方法来检测客户端重定向是否完成,首先从页面开始加载
时就“监视”DOM 中的一个元素,然后重复调用这个元素直到 Selenium 抛出一个StaleElementReferenceException 异常;也就是说,元素不在页面的 DOM 里了,说明这时网站已经跳转:

from selenium import webdriver
import time
from selenium.webdriver.remote.webelement import WebElement
from selenium.common.exceptions import StaleElementReferenceException

def waitForLoad(driver):
    elem = driver.find_element_by_tag_name("html")
    count = 0
    while True:
        count += 1
        if count > 20:
            print("Timing out after 10 seconds and returning")
            return
        time.sleep(.5)
        try:
            elem == driver.find_element_by_tag_name("html")
        except StaleElementReferenceException:
            return

driver = webdriver.PhantomJS(executable_path='/phantomjs-1.9.8-macosx/bin/phantomjs')
driver.get("http://pythonscraping.com/pages/javascript/redirectDemo1.html")
waitForLoad(driver)
print(driver.page_source)

 

你可能感兴趣的:(python)