Python公开课 - 数据抓取之Selenium使用(下)

数据抓取之Selenium使用

前言

Selenium Python提供非常方便的API和浏览器进行交互,目前支持Python2.7和Python3版。

本章将从爬虫的视角来介绍Selenium的具体使用。

Selenium访问今日头条的简单使用

我们以今日头条的Web站点为例:

from selenium import webdriver
from selenium.webdriver.chrome.options import Options


options = Options()
options.binary_location = '/usr/bin/google-chrome'
options.add_argument('--headless')
options.add_argument('--disable-gpu')
options.add_argument('--no-sandbox')
driver = webdriver.Chrome(executable_path='./chromedriver', chrome_options=options)

driver.implicitly_wait(5)
driver.get("https://www.toutiao.com/")
print(driver.current_url)
print(driver.get_cookies())
print(driver.page_source)
driver.quit()

代码说明:

  • optiondriver的选项参数,效果和直接在命令行中键入参数是一样的
    • --headless标明不需要图形展示,适合程序和命令行方式,因为不用人工去看
    • --disable-gpu 禁用GPU加速,因为不用图形化显示,所以这个选项可以加上,减小对GPU的使用
    • --no-sandbox 沙盒是chrome浏览器的的一个安全技术,指在Windows上构造一个和外界绝缘的空间来禁止用户行为的一种技术手段,这里涉及到网络和系统安全,我们不过多研究。
  • chromedriver也就是下载浏览器驱动的位置,见数据抓取之Selenium使用(上)安装Goolge Chrome Drive章节
  • driver.implicitly_wait(5) 标明需要隐式等待5秒页面加载
  • driver.get("https://www.toutiao.com/") 控制浏览器访问今日头条
  • driver.current_url, driver.get_cookies(), driver.page_source分别为获取页面的URL地址、cookies信息和当前经过javascript运行后的页面代码
  • driver.quit() 控制浏览器退出,否则浏览器将一直运行,占用系统资源

查找单个元素方法

1. 通过ID查找元素

页面的元素id,可以通过find_element_by_id方法来快速定位, 例如我们需要定位百度的搜索框。

百度

可以通过如下代码实现:

#coding=utf8
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.common.keys import Keys

options = Options()
options.binary_location = '/usr/bin/google-chrome'
options.add_argument('--headless')
options.add_argument('--disable-gpu')
options.add_argument('--no-sandbox')
driver = webdriver.Chrome(executable_path='./chromedriver', chrome_options=options)

driver.implicitly_wait(5)
driver.get("https://www.baidu.com/")
q_form = driver.find_element_by_id('kw')
q_form.send_keys("兔子先生-技术栈")
q_form.send_keys(Keys.ENTER)

search_btn = driver.find_element_by_id('su')
search_btn.click()

wait = WebDriverWait(driver, 20)

print(driver.current_url)
driver.save_screenshot('test.png')

driver.quit()

程序运行后,页面截图如下:

搜索结果

可以看到,我们通过对浏览器直接操作,可以很方便的实现我们想要的结果。

2. 通过Name查找元素

我们选择一个示例页面,HTML如下:

<html>
 <body>
  <h1>Welcome</h1>
  <form id="login">
   <input name="username" type="text" />
   <input name="password" type="password" />
   <input name="continue" type="submit" value="Login" />
  </form>
  <a href="forget.html">forget password</a>
  <p class="xtuz">兔子先生-技术栈</p>
 </body>
<html>

除了id以外,我们也可以根据元素的name,通过find_element_by_name来定位,方法如下:

item = driver.find_element_by_name('username')

3. 通过XPath查找元素

XPath是XML文档中查找结点的语法, 见页面解析之Xpath,我们查找HTML页面中的第一个form元素,语法如下:

item = driver.find_element_by_xpath("//form[1]")

4. 通过链接文本获取超链接

当你确定了目标链接的文本内容时,可以考虑这个方法。

forget_link = driver.find_element_by_link_text('forget')
forget_link = driver.find_element_by_partial_link_text('for')

5. 通过标签名查找元素

如果需要通过标签名查找元素时,使用find_element_by_tag_name,示例如下:

heading1 = driver.find_element_by_tag_name('h1')

6. 通过Class name定位元素

通过class name查找元素时使用find_element_by_class_name。使用该方法时,页面中第一个符合该class属性的元素会被匹配并返回。示例如下:

content = driver.find_element_by_class_name('xtuz')

7. 通过CSS选择器查找元素

当你打算通过CSS选择器查找元素时,可以使用find_element_by_css_selector, 示例如下:

content = driver.find_element_by_css_selector('p.xtuz')

注意:

如果元素的样式有多个,那么如何精准定位呢,这里可以参考Python Selenium find_element_by_css_selector 如何处理多个class

查找多个元素

当需要查找多个元素时,思路和上述一样,唯一区别的就是方法和返回不同,这些方法会返回一个list, 如果找不到,则该list为空。方法如下:

  • find_elements_by_name
  • find_elements_by_xpath
  • find_elements_by_link_text
  • find_elements_by_partial_link_text
  • find_elements_by_tag_name
  • find_elements_by_class_name
  • find_elements_by_css_selector

数据提取

1. 提取标签

通过元素的tag_name属性获取当前元素的标签名称:

item = driver.find_element_by_name('tj_trnews')
print(item.tag_name)

2. 提取文本

通过元素的text属性获取当前元素文本信息:

item = driver.find_element_by_name('tj_trnews')
print(item.text)

3. 提取元素的属性值

通过元素的get_attribute()方法获取当前元素的属性值:

item = driver.find_element_by_name('tj_trnews')
print(item.get_attribute('href'))

元素节点交互

1. 文本框输入填写

通过send_keys()来填写输入框:

item.send_keys("www.xtuz.net")

注意:

  • 如果传中文,应写为u"输入文本",
  • 如果是从文件读取,通过file=codecs.open('keywords.txt', 'r', 'utf-8')

2. 单选框输入

通过click()来填写输入框,示例代码如下:

all_options = element.find_elements_by_tag_name("option")
for option in all_options:
    print("Value is: %s" % option.get_attribute("value"))
    option.click()

3. 多选框输入

示例如下:

from selenium.webdriver.support.ui import Select
select = Select(driver.find_element_by_name('name'))
select.select_by_index(index)
select.select_by_visible_text("text")
select.select_by_value(value)

4. 窗口切换

如果有多个窗口,可以根据窗口的名称,通过switch_to_window()来切换,示例如下:

driver.switch_to_window("windowName")

5. 框架切换

如果页面嵌套frame, 则可以根据框架名称,通过switch_to_frame来切换:

driver.switch_to_frame("frameName")

并通过switch_to_default_content()返回父frame。

6. 浏览器前进与后退

如果你需要对浏览历史进行记录并操作,可以使用:

driver.forward()
driver.back()

7. 动作链

Action Chains类常用于模拟鼠标的行为,比如单击,双击,拖拽等行为,其中行为事件是存储在actionchains对象队列。当你使用perform(),事件按顺序执行

实现一个节点的拖曳操作,将某个节点从一处拖曳到另外一处,可以这样实现:

element = driver.find_element_by_name("source")
target = driver.find_element_by_name("target")

from selenium.webdriver import ActionChains
action_chains = ActionChains(driver)
action_chains.drag_and_drop(element, target).perform()

延时等待

对于动态页面,一般是需要等待页面全部加载完成后,内容才能正常显示,所以我们需要控制Selenium进行延时等待。这里又分为两种方式:

  1. 显式等待 显式等待是你在代码中定义等待一定条件发生后再进一步执行你的代码。
  2. 隐式等待 隐式等待执行测试的时候,如果Selenium没有在DOM中找到节点,将继续等待。如果超出设定时间后,则抛出异常。

具体可以参考Selenium文档-等待页面加载完成

小结

本章对Selenium的常规用法有了大体的了解,引入Selenium后,处理JavaScript动态页面不再困难。

相关阅读