爬虫 - Selenium 和 PhantomJS

Selenium 是什么?

  • Selenium 是一个用于 Web 应用程序测试的工具。Selenium 测试直接运行在浏览器中,就像真正的用户在操作一样。支持的浏览器包括 IE(7, 8, 9, 10, 11),Mozilla Firefox,Safari,Google Chrome,Opera 等。这个工具的主要功能包括:测试与浏览器的兼容性 — 测试你的应用程序看是否能够很好得工作在不同浏览器和操作系统之上。测试系统功能 — 创建回归测试检验软件功能和用户需求。支持自动录制动作和自动生成 .Net、Java、Perl 等不同语言的测试脚本。
  • Selenium 是一个 Python 的一个第三方库,对外提供的接口可以操作你的浏览器,然后让浏览器完成自动化的操作。

使用 Selenium

操控浏览器

  • 打开网站

    启动浏览器后你要做的第一件事就是打开你的网站。这可以通过一行代码实现:

    1
    driver.get("https://selenium.dev")
  • 获取当前 URL

    您可以从浏览器的地址栏读取当前的 URL,使用以下代码:

    1
    driver.current_url
  • 后退

    按下浏览器的后退按钮:

    1
    driver.back()
  • 前进

    按下浏览器的前进键:

    1
    driver.forward()
  • 刷新

    刷新当前页面:

    1
    driver.refresh()
  • 获取标题

    从浏览器中读取当前页面的标题:

    1
    driver.title
  • 获得当前窗口的窗口句柄

    WebDriver 没有区分窗口和标签页。如果你的站点打开了一个新标签页或窗口,Selenium 将允许您使用窗口句柄来处理它。 每个窗口都有一个唯一的标识符,该标识符在单个会话中保持持久性。你可以使用以下方法获得当前窗口的窗口句柄:

    1
    driver.current_window_handle
  • 切换窗口或标签页

    • 单击 <a href="https://seleniumhq.github.io" target="_blank"> 在新窗口中打开链接,则屏幕会聚焦在新窗口或新标签页上,但 WebDriver 不知道操作系统认为哪个窗口是活动的。 要使用新窗口,您需要切换到它。 如果只有两个选项卡或窗口被打开,并且你知道从哪个窗口开始,则你可以遍历 WebDriver,通过排除法可以看到两个窗口或选项卡,然后切换到你需要的窗口或选项卡。
    • 不过,Selenium 4 提供了一个新的 api NewWindow 它创建一个新选项卡 (或) 新窗口并自动切换到它。
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      from selenium import webdriver
      from selenium.webdriver.support.ui import WebDriverWait
      from selenium.webdriver.support import expected_conditions as EC

      # 启动驱动程序
      with webdriver.Firefox() as driver:
      # 打开网址
      driver.get("https://seleniumhq.github.io")

      # 设置等待
      wait = WebDriverWait(driver, 10)

      # 存储原始窗口的 ID
      original_window = driver.current_window_handle

      # 检查一下,我们还没有打开其他的窗口
      assert len(driver.window_handles) == 1

      # 单击在新窗口中打开的链接
      driver.find_element(By.LINK_TEXT, "new window").click()

      # 等待新窗口或标签页
      wait.until(EC.number_of_windows_to_be(2))

      # 循环执行,直到找到一个新的窗口句柄
      for window_handle in driver.window_handles:
      if window_handle != original_window:
      driver.switch_to.window(window_handle)
      break

      # 等待新标签页完成加载内容
      wait.until(EC.title_is("SeleniumHQ Browser Automation"))
  • 创建新窗口 (或) 新标签页并且切换

    • 创建一个新窗口 (或) 标签页,屏幕焦点将聚焦在新窗口或标签在上。您不需要切换到新窗口 (或) 标签页。如果除了新窗口之外, 您打开了两个以上的窗口 (或) 标签页,您可以通过遍历 WebDriver 看到两个窗口或选项卡,并切换到非原始窗口。
    • 注意:该特性适用于 Selenium 4 及其后续版本。
      1
      2
      3
      4
      5
      # 打开新标签页并切换到新标签页
      driver.switch_to.new_window('tab')

      # 打开一个新窗口并切换到新窗口
      driver.switch_to.new_window('window')
  • 关闭窗口或标签页

    当你完成了一个窗口或标签页的工作时,并且它不是浏览器中最后一个打开的窗口或标签页时,你应该关闭它并切换回你之前使用的窗口。 假设您遵循了前一节中的代码示例,您将把前一个窗口句柄存储在一个变量中。把这些放在一起,你会得到:

    1
    2
    3
    4
    5
    #关闭标签页或窗口
    driver.close()

    #切回到之前的标签页或窗口
    driver.switch_to.window(original_window)

    如果在关闭一个窗口后忘记切换回另一个窗口句柄,WebDriver 将在当前关闭的页面上执行,并触发一个 No Such Window Exception 无此窗口异常。必须切换回有效的窗口句柄才能继续执行。

  • 在会话结束时退出浏览器

    当你完成了浏览器会话,你应该调用 quit 退出,而不是 close 关闭:

    1
    driver.quit()

    Python 的 WebDriver 现在支持 Python 上下文管理器,当使用 with 关键字时,可以在执行结束时自动退出驱动程序。

    1
    2
    3
    4
    with webdriver.Firefox() as driver:
    # WebDriver 代码…

    # 在此缩进位置后 WebDriver 会自动退出
  • 使用 WebElement

    使用 WebElement 进行切换是最灵活的选择。您可以使用首选的选择器找到框架并切换到它。

    1
    2
    3
    4
    5
    6
    7
    8
    # 存储网页元素
    iframe = driver.find_element(By.CSS_SELECTOR, "#modal > iframe")

    # 切换到选择的 iframe
    driver.switch_to.frame(iframe)

    # 单击按钮
    driver.find_element(By.TAG_NAME, 'button').click()
  • 使用 name 或 id

    如果您的 frame 或 iframe 具有 id 或 name 属性,则可以使用该属性。如果 name 或 id 在页面上不是唯一的, 那么将切换到找到的第一个。

    1
    2
    3
    4
    5
    # 通过 id 切换框架
    driver.switch_to.frame('buttonframe')

    # 单击按钮
    driver.find_element(By.TAG_NAME, 'button').click()
  • 使用索引

    还可以使用 frame 的索引,例如:可以使用 JavaScript 中的 window.frames 进行查询。

    1
    2
    3
    4
    5
    # 基于索引切换到第 2 个 iframe
    iframe = driver.find_elements_by_tag_name('iframe')[1]

    # 切换到选择的 iframe
    driver.switch_to.frame(iframe)
  • 离开框架

    离开 iframe 或 frameset,切换回默认内容,如下所示:

    1
    2
    # 切回到默认内容
    driver.switch_to.default_content()
  • 获取窗口大小

    获取浏览器窗口的大小 (以像素为单位)。

    1
    2
    3
    4
    5
    6
    7
    8
    # 分别获取每个尺寸
    width = driver.get_window_size().get("width")
    height = driver.get_window_size().get("height")

    # 或者存储尺寸并在以后查询它们
    size = driver.get_window_size()
    width1 = size.get("width")
    height1 = size.get("height")
  • 设置窗口大小

    恢复窗口并设置窗口大小。

    1
    driver.set_window_size(1024, 768)
  • 最大化窗口

    扩大窗口。对于大多数操作系统,窗口将填满屏幕,而不会阻挡操作系统自己的菜单和工具栏。

    1
    driver.maximize_window()
  • 最小化窗口

    最小化当前浏览上下文的窗口。这种命令的精准行为将作用于各个特定的窗口管理器。
    最小化窗口通常将窗口隐藏在系统托盘中。
    注意:此功能适用于 Selenium 4 以及更高版本。

    1
    driver.minimize_window()
  • 全屏窗口

    填充整个屏幕,类似于在大多数浏览器中按下 F11。

    1
    driver.fullscreen_window()
  • 屏幕截图

    用于捕获当前浏览上下文的屏幕截图。WebDriver 端点 屏幕截图 返回以 Base64 格式编码的屏幕截图。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    from selenium import webdriver

    driver = webdriver.Chrome()

    # Navigate to url
    driver.get("http://www.example.com")

    # Returns and base64 encoded string into image
    driver.save_screenshot('./image.png')

    driver.quit()
  • 元素屏幕截图

    用于捕获当前浏览上下文的元素的屏幕截图。WebDriver 端点 屏幕截图 返回以 Base64 格式编码的屏幕截图。常用来截取验证码图片。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    from selenium import webdriver
    from selenium.webdriver.common.by import By

    driver = webdriver.Chrome()

    # Navigate to url
    driver.get("http://www.example.com")

    ele = driver.find_element(By.CSS_SELECTOR, 'h1')

    # Returns and base64 encoded string into image
    ele.screenshot('./image.png')

    driver.quit()
  • 执行脚本

    在当前 frame 或者窗口的上下文中,执行 JavaScript 代码片段。

    1
    2
    3
    4
    5
    # Stores the header element
    header = driver.find_element(By.CSS_SELECTOR, "h1")

    # Executing JavaScript to capture innerText of header element
    driver.execute_script('return arguments[0].innerText', header)

查找元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 查找一个元素
find_element_by_id 通过ID查找元素
find_element_by_name 通过Name查找元素
find_element_by_xpath 通过XPath查找元素
find_element_by_link_text 通过链接文本获取超链接
find_element_by_partial_link_text 通过链接部分文本获取超链接(模糊查找)
find_element_by_tag_name 通过标签名查找元素
find_element_by_class_name 通过Class name定位元素
find_element_by_css_selector 通过CSS选择器查找元素

# 查找多个元素(这些方法会返回一个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

find_element_by_* 命令 已弃用,请改用 find_element()
find_elements_by_* 命令 已弃用,请改用 find_elements()

下面是 By 类的一些可用属性

1
2
3
4
5
6
7
8
ID = "id"
XPATH = "xpath"
LINK_TEXT = "link text"
PARTIAL_LINK_TEXT = "partial link text"
NAME = "name"
TAG_NAME = "tag name"
CLASS_NAME = "class name"
CSS_SELECTOR = "css selector"

等待页面加载完成 (Waits)

  • 简介

    • 现在的大多数的 Web 应用程序是使用 Ajax 技术。当一个页面被加载到浏览器时,该页面内的元素可以在不同的时间点被加载。这使得定位元素变得困难,如果元素不再页面之中,会抛出 ElementNotVisibleException 异常。使用 waits,我们可以解决这个问题。waits 提供了一些操作之间的时间间隔 - 主要是定位元素或针对该元素的任何其他操作。
    • Selenium Webdriver 提供两种类型的 waits - 隐式和显式。 显式等待会让 WebDriver 等待满足一定的条件以后再进一步的执行。而隐式等待让 Webdriver 等待一定的时间后再去查找某元素。除此之外还有一种 waits - 流畅等待 (FluentWait),它定义了等待条件的最长时间,以及检查条件的频率。
  • 显式等待

    • Selenium 中的显式等待(Explicit Wait)是一种智能等待方式,它允许你写出条件,然后等待这个条件在指定时间内成立之后再继续执行后续代码。与隐式等待全局性地影响 WebDriver 的寻找元素行为不同,显式等待针对的是某个特定的条件和元素。
    • 使用显式等待时,你需要指定一个最大等待时间,如果在这段时间内条件成立,WebDriver 就会停止等待并继续执行。如果条件在最大时间内没有成立,WebDriver 则会抛出一个 TimeoutException
    • 显式等待通常与 WebDriverWait 类和 expected_conditions 工具一起使用,其中 WebDriverWait 负责实现等待逻辑,expected_conditions 提供了一组标准的条件,如元素可见、元素可点击等。
    • 下面是一个使用 Python Selenium 实现显式等待的简单例子:
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      from selenium import webdriver
      from selenium.webdriver.common.by import By
      from selenium.webdriver.support.ui import WebDriverWait
      from selenium.webdriver.support import expected_conditions as EC

      # 创建WebDriver实例
      driver = webdriver.Chrome()

      # 打开网页
      driver.get("http://example.com")

      # 创建WebDriverWait实例,最大等待时间设为10秒
      wait = WebDriverWait(driver, 10)

      # 设置显式等待条件,等待直到元素可见
      element = wait.until(EC.visibility_of_element_located((By.ID, "myElementId")))

      # 之后可以与该元素进行交云
      element.click()

      # 完成后,关闭浏览器
      driver.quit()

    • 在上述代码中,WebDriverWait 对象会针对 driver 实例进行最多 10 秒的等待,until 方法会不断地评估后面的条件 EC.visibility_of_element_located,一旦条件满足,即元素变得可见,until 方法就会返回这个元素对象,随后你就可以与它进行交互(如点击)。如果 10 秒内条件一直不满足,until 方法将会抛出 TimeoutException
    • WebDriverWait 默认的轮询时间(即检查条件是否满足的频率)依赖于使用的编程语言和 Selenium 的版本,但通常默认的轮询时间是 0.5 秒。这意味着默认情况下,WebDriver 会每半秒检查一次条件是否成立。
    • 自动化的 Web 浏览器中一些常用的预期条件
      1. title_is:检查页面标题是否精确等于预期字符串。
      2. title_contains:检查页面标题是否包含预期字符串。
      3. presence_of_element_located:检查元素是否存在于 DOM 中并且可定位,不一定可见。
      4. visibility_of_element_located:检查元素是否存在于 DOM 中并且可见,可见意味着元素不仅显示在 DOM 中,而且高度和宽度都大于 0。
      5. visibility_of:与 visibility_of_element_located 类似,但它是针对已定位的元素而言。
      6. element_to_be_clickable:检查元素是否可见并且可点击。
      7. element_to_be_selected:检查元素是否已被选中。
      8. presence_of_all_elements_located:检查是否至少有一个符合定位条件的元素存在于 DOM 中。
      9. text_to_be_present_in_element:检查某个元素的文本内容中是否包含预期的字符串。
      10. text_to_be_present_in_element_value:检查某个元素的 value 属性中是否包含预期的字符串。
      11. frame_to_be_available_and_switch_to_it:检查 frame 是否可用,并切换到它。
      12. invisibility_of_element_located:检查元素是否不存在于 DOM 或者不可见。
      13. element_to_be_stale:等待一个元素从 DOM 中移除。
      14. alert_is_present:检查页面是否出现了 alert 弹框。
  • 隐式等待

    • Selenium 的隐式等待(Implicit Wait)是一种全局等待方式,设置一次即对整个 WebDriver 实例的生命周期内所有元素定位操作都有效。当使用隐式等待时,如果 WebDriver 在查找一个元素时没有立即发现它,WebDriver 就会等待一段指定的时间,直到元素出现为止。如果在这段时间结束前元素被找到了,WebDriver 就会继续执行代码。如果时间耗尽元素仍未出现,则会抛出 NoSuchElementException
    • 隐式等待的关键特点是它会在尝试执行任何元素定位之前被设置,对后续的所有元素定位调用都有效。这意味着隐式等待只需要设置一次,而不需要针对每个元素重复设置。
    • 在 Python 中使用 Selenium WebDriver 时,可以这样设置隐式等待:
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      from selenium import webdriver

      # 创建WebDriver实例
      driver = webdriver.Chrome()

      # 设置隐式等待时间为10秒
      driver.implicitly_wait(10)

      # 执行元素定位操作
      element = driver.find_element_by_id("myElementId")

      # 其他Selenium操作...

      # 完成后,关闭WebDriver会话
      driver.quit()

    • 在这个例子中,driver.implicitly_wait(10) 设置了一个 10 秒的等待时间。当尝试定位 myElementId 这个元素时,如果元素不立即可用,WebDriver 将等待最多 10 秒的时间。一旦元素在 10 秒内被找到,代码会立即继续执行。如果 10 秒钟过去了元素还未被找到,就会抛出异常。
    • 假如设置隐式等待 10s,如果元素在 5s 内被找到,WebDriver 就不会再等待剩下的 5s,而是直接继续执行。隐式等待的时间是一个最长等待时间,而不是一个固定的等待时长。
    • 工作机制:当你尝试定位一个元素时,如果 WebDriver 不能立即找到它,它将等待更长的时间(直到你设定的时间到达)来查找该元素。在这段时间内,WebDriver 会不断地尝试定位元素,直到元素出现或者超出设定的最大等待时间。
    • 需要注意的是,隐式等待和显式等待(Explicit Waits)不同。显式等待会指定等待某个条件成立,然后再继续执行代码,它更灵活,但需要编写更多的代码。隐式等待相对简单,只需设定一个等待时间即可。然而,在某些复杂的自动化脚本中,通常推荐使用显式等待,因为它可以针对元素的不同状态设置不同的等待条件。
  • 流畅等待

    • 在 Selenium 中,流畅等待(Fluent Wait)是显式等待(Explicit Wait)的一种特殊类型,它允许你为等待条件设置最大等待时间以及检查条件的频率。与简单的隐式等待不同,流畅等待允许你定义等待条件,以及在条件未满足时,等待多久再次检查(轮询间隔)。此外,它还允许你忽略特定类型的异常,直到达到最大等待时间为止。
    • 在 Python 中使用 Selenium WebDriver 进行流畅等待的基本方法如下:
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      from selenium import webdriver
      from selenium.webdriver.common.by import By
      from selenium.webdriver.support.ui import WebDriverWait
      from selenium.webdriver.support import expected_conditions as EC
      from selenium.common.exceptions import NoSuchElementException
      from selenium.webdriver.support.wait import WebDriverWait

      # 创建WebDriver实例
      driver = webdriver.Chrome()

      # 设置最大等待时长和轮询间隔
      wait = WebDriverWait(driver, timeout=10, poll_frequency=1, ignored_exceptions=[NoSuchElementException])

      # 使用until()方法等待特定条件成立
      element = wait.until(EC.presence_of_element_located((By.ID, 'element-id')))

    • 在这个例子中,WebDriverWait 被配置为最多等待 10 秒钟,并且每 1 秒钟检查一次条件是否满足(例如元素是否已经出现在 DOM 中)。同时,ignored_exceptions 参数指定了一组异常,在等待期间如果抛出这些异常,将不会立即导致测试失败,而是忽略它们直到下次轮询。
    • 流畅等待非常灵活,它可以让你根据自动化测试的需求精确地指定等待策略。这种类型的等待机制在处理复杂的页面交互和状态变化时非常有用,尤其是当元素可能会因为各种原因在不同时间呈现不同状态时。

消息弹窗

  • 简介

    WebDriver 提供了一个 API,用于处理 JavaScript 提供的三种类型的原生消息弹窗。这些弹出窗口由浏览器设置样式并提供有限的自定义。

  • Alerts 警告框

    • 其中最基本的称为警告框,它显示一条自定义消息,以及一个用于关闭该警告的按钮,在大多数浏览器中标记为确定(OK)。在大多数浏览器中,也可以通过按关闭(close) 按钮将其关闭,但这始终与确定按钮执行相同的操作。
    • WebDriver 可以从弹窗获取文本并接受或关闭这些警告。
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      # Click the link to activate the alert
      driver.find_element(By.LINK_TEXT, "See an example alert").click()

      # Wait for the alert to be displayed and store it in a variable
      alert = wait.until(expected_conditions.alert_is_present())

      # Store the alert text in a variable
      text = alert.text

      # Press the OK button
      alert.accept()

  • Confirm 确认框

    • 确认框类似于警告框,不同之处在于用户还可以选择取消消息。
    • 此示例还显示了实现警报框的不同方法:
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      # Click the link to activate the alert
      driver.find_element(By.LINK_TEXT, "See a sample confirm").click()

      # Wait for the alert to be displayed
      wait.until(expected_conditions.alert_is_present())

      # Store the alert in a variable for reuse
      alert = driver.switch_to.alert

      # Store the alert text in a variable
      text = alert.text

      # Press the Cancel button
      alert.dismiss()

  • Prompt 提示框

    提示框与确认框相似,不同之处在于它们还包括文本输入。与处理表单元素类似,您可以使用 WebDriver 的 sendKeys 来填写响应。这将完全替换占位符文本。按下取消按钮将不会提交任何文本。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    # Click the link to activate the alert
    driver.find_element(By.LINK_TEXT, "See a sample prompt").click()

    # Wait for the alert to be displayed
    wait.until(expected_conditions.alert_is_present())

    # Store the alert in a variable for reuse
    alert = Alert(driver)

    # Type your message
    alert.send_keys("Selenium")

    # Press the OK button
    alert.accept()

页面加载策略

  • 简介

    定义当前会话的页面加载策略。默认情况下,当 Selenium WebDriver 加载页面时,遵循 normal 的页面加载策略。当在页面加载缓慢时,始终建议您停止下载其他资源(如图片、css、js)。

  • normal

    • 此配置使 Selenium WebDriver 等待整个页面的加载。设置为 normal 时,Selenium WebDriver 将保持等待,直到返回 load 事件。
    • 默认情况下,如果未设置页面加载策略,则设置 normal 为初始策略。
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      from selenium import webdriver
      from selenium.webdriver.chrome.options import Options

      options = Options()
      options.page_load_strategy = 'normal'
      driver = webdriver.Chrome(options=options)
      # Navigate to url
      driver.get("http://www.google.com")
      driver.quit()

  • eager

    • 这将使 Selenium WebDriver 保持等待,直到完全加载并解析了 HTML 文档,该策略无关样式表,图片和 subframes 的加载。
    • 设置为 eager 时,Selenium WebDriver 保持等待,直至返回 DOMContentLoaded 事件。
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      from selenium import webdriver
      from selenium.webdriver.chrome.options import Options

      options = Options()
      options.page_load_strategy = 'eager'
      driver = webdriver.Chrome(options=options)
      # Navigate to url
      driver.get("http://www.google.com")
      driver.quit()

  • none

    设置为 none 时,Selenium WebDriver 仅等待至初始页面下载完成。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    from selenium import webdriver
    from selenium.webdriver.chrome.options import Options

    options = Options()
    options.page_load_strategy = 'none'
    driver = webdriver.Chrome(options=options)
    # Navigate to url
    driver.get("http://www.google.com")
    driver.quit()

网络元素

  • Find Element

    此方法用于查找元素并返回第一个匹配的单个 WebElement 引用,该元素可用于进一步的元素操作。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    from selenium import webdriver
    from selenium.webdriver.common.by import By

    driver = webdriver.Firefox()

    driver.get("http://www.google.com")

    # Get search box element from webElement 'q' using Find Element
    search_box = driver.find_element(By.NAME, "q")

    search_box.send_keys("webdriver")

  • Find Elements

    Find Element 相似,但返回的是匹配 WebElement 列表。要使用列表中的特定 WebElement,您需要遍历元素列表以对选定元素执行操作。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    from selenium import webdriver
    from selenium.webdriver.common.by import By

    driver = webdriver.Firefox()

    # Navigate to Url
    driver.get("https://www.example.com")

    # Get all the elements available with tag name 'p'
    elements = driver.find_elements(By.TAG_NAME, 'p')

    for e in elements:
    print(e.text)

  • Find Element From Element

    此方法用于在父元素的上下文中查找子元素。为此,父 WebElement 与 findElement 链接并访问子元素。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    from selenium import webdriver
    from selenium.webdriver.common.by import By

    driver = webdriver.Firefox()
    driver.get("http://www.google.com")
    search_form = driver.find_element(By.TAG_NAME, "form")
    search_box = search_form.find_element(By.NAME, "q")
    search_box.send_keys("webdriver")

  • Find Elements From Element

    此方法用于在父元素的上下文中查找匹配子 WebElement 的列表。为此,父 WebElement 与 findElements 链接并访问子元素。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    from selenium import webdriver
    from selenium.webdriver.common.by import By

    driver = webdriver.Chrome()
    driver.get("https://www.example.com")

    # Get element with tag name 'div'
    element = driver.find_element(By.TAG_NAME, 'div')

    # Get all the elements available with tag name 'p'
    elements = element.find_elements(By.TAG_NAME, 'p')
    for e in elements:
    print(e.text)

  • 获取元素标签名

    此方法用于获取在当前浏览上下文中具有焦点的被引用元素的 TagName

    1
    2
    3
    4
    5
    6
    # Navigate to url
    driver.get("https://www.example.com")

    # Returns TagName of the element
    attr = driver.find_element(By.CSS_SELECTOR, "h1").tag_name

  • 获取元素尺寸信息

    用于获取参考元素的尺寸和坐标。

    1
    2
    3
    4
    5
    6
    # Navigate to url
    driver.get("https://www.example.com")

    # Returns height, width, x and y coordinates referenced element
    res = driver.find_element(By.CSS_SELECTOR, "h1").rect

    提取的数据主体包含以下详细信息:

    • 元素左上角的 X 轴位置
    • 元素左上角的 y 轴位置
    • 元素的高度
    • 元素宽度
  • 获取元素 CSS 值

    获取当前浏览上下文中元素的特定计算样式属性的值。

    1
    2
    3
    4
    5
    6
    # Navigate to Url
    driver.get('https://www.example.com')

    # Retrieves the computed style property 'color' of linktext
    cssValue = driver.findElement(By.LINK_TEXT, "More information...").value_of_css_property('color')

  • 获取元素文本

    获取特定元素渲染后的文本。

    1
    2
    3
    4
    5
    6
    # Navigate to url
    driver.get("https://www.example.com")

    # Retrieves the text of the element
    text = driver.find_element(By.CSS_SELECTOR, "h1").text

  • 获取元素的给定属性

    • get_attribute(name)
      • 该方法将首先尝试返回具有给定名称的属性的值。如果具有该名称的属性不存在,则返回具有相同名称的属性的值。如果没有这个名称的属性,则返回 None
      • 被认为为真值的值,即等于 “真” 或 “假” 的值,将作为布尔值返回。所有其他非 None 值将作为字符串返回。对于不存在的属性,返回 None
      • 要获得属性或属性的确切值,请分别使用 get_dom_attribute()get_property() 方法。
      • 示例
        1
        title_url = title.find_element(By.XPATH, './a').get_attribute('href')
    • get_dom_attribute(name)
      • 获取元素的给定属性。与 get_attribute() 不同,该方法只返回在元素的 HTML 标记中声明的属性。
      • 示例
        1
        title_url = title.find_element(By.XPATH, './a').get_dom_attribute('href')
    • get_property(name)
      • 获取元素的给定属性。
      • 示例
        1
        title_url = title.find_element(By.XPATH, './a').get_property('href')
  • 获取元素 标签 + 文本

    1
    article_content = driver.find_element(By.XPATH, '//div[@id="downloadContent"]').get_attribute('innerHTML')

简单示例 1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
from time import sleep

from selenium import webdriver
from selenium.webdriver.common.keys import Keys


def main():
# 模拟创建一个浏览器驱动对象,然后通过对象去操作浏览器
driver = webdriver.Chrome()
url = 'https://www.baidu.com/'
# driver.get方法将打开URL中填写的地址,WebDriver将等待,直到页面完全加载完毕(其实是等到“onload”方法执行完毕),然后返回继续执行你的脚本。 值得注意的是,如果你的页面使用了大量的Ajax加载, WebDriver可能不知道什么时候页面已经完全加载
driver.get(url)
# 用assert的方式确认标题是否包含“百度”一词
assert '百度' in driver.title
# 查找包含name属性的input输入框
elem = driver.find_element(by='name', value='wd')
# 清除input输入框中的任何预填充的文本,从而避免我们的搜索结果受影响
elem.clear()
# 在input输入框中填写文字,如:美女
elem.send_keys('美女')
sleep(1)
# 通过Keys类输入特殊的按键(回车)
elem.send_keys(Keys.RETURN)
sleep(2)
# 关闭浏览器窗口,你还可以使用quit方法代替close方法,quit将关闭整个浏览器,而close只会关闭一个标签页,如果你只打开了一个标签页,大多数浏览器的默认行为是关闭浏览器
driver.close()


if __name__ == '__main__':
main()

简单示例 2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
from selenium import webdriver
from time import sleep

# 后面是你的浏览器驱动位置,记得前面加r'','r'是防止字符转义的
driver = webdriver.Chrome(r'C:\Users\ZBLi\Desktop\1801\day05\ziliao\chromedriver.exe')
# 用get打开百度页面
driver.get("http://www.baidu.com")
# 查找页面的“设置”选项,并进行点击
driver.find_elements_by_link_text('设置')[0].click()
sleep(2)
# # 打开设置后找到“搜索设置”选项,设置为每页显示50条
driver.find_elements_by_link_text('搜索设置')[0].click()
sleep(2)

# 选中每页显示50条
m = driver.find_element_by_id('nr')
sleep(2)
m.find_element_by_xpath('//*[@id="nr"]/option[3]').click()
m.find_element_by_xpath('.//option[3]').click()
sleep(2)

# 点击保存设置
driver.find_elements_by_class_name("prefpanelgo")[0].click()
sleep(2)

# 处理弹出的警告页面 确定accept() 和 取消dismiss()
driver.switch_to_alert().accept()
sleep(2)
# 找到百度的输入框,并输入“美女”
driver.find_element_by_id('kw').send_keys('美女')
sleep(2)
# 点击搜索按钮
driver.find_element_by_id('su').click()
sleep(2)
# 在打开的页面中找到“美女_百度图片”,并打开这个页面
driver.find_elements_by_link_text('美女_百度图片')[0].click()
sleep(3)

# 关闭浏览器
driver.quit()

PhantomJS 是什么?

  • PhantomJS 是一个基于 Webkit 的 “无界面”(headless) 浏览器,它会把网站加载到内存并执行页面上的 JavaScript,因为不会展示图形界面,所以运行起来比完整的浏览器要高效
  • 如果我们把 Selenium 和 PhantomJS 结合在一起,就可以运行一个非常强大的网络爬虫了,这个爬虫可以处理 JavaScrip、Cookie、headers,以及任何我们真实用户需要做的事情
  • Selenium + PhantomJS 就是爬虫终极解决方案
  • ⚠️PhantomJS 的 Selenium 支持已经被弃用,请使用 Chrome 或 Firefox 的无头版本

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
from time import sleep
from selenium import webdriver


def main():
# phantomjs路径
path = r'C:\Users\suyin\Desktop\review\爬虫\day05\phantomjs-2.1.1-windows\bin\phantomjs.exe'
# 模拟创建一个浏览器对象,然后通过对象去操作浏览器
browser = webdriver.PhantomJS(path)
# 打开百度
url = 'https://www.baidu.com/'
browser.get(url)
sleep(2)
# 拍照
browser.save_screenshot(r'phantomjs\baidu.png')

# 查找input输入框
my_input = browser.find_element_by_id('kw')
# 往搜索框里写文字
my_input.send_keys('美女')
sleep(1)
browser.save_screenshot(r'phantomjs\meinv.png')

# 查找“百度一下”按钮
button = browser.find_elements_by_class_name('s_btn')[0]
button.click()
sleep(1)
browser.save_screenshot(r'phantomjs\show.png')

# 关闭浏览器(退出浏览器)
browser.quit()


if __name__ == '__main__':
main()

下拉滚动条到底部

豆瓣电影下拉

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
from time import sleep
from selenium import webdriver


def main():
# phantomjs路径
path = r'C:\Users\suyin\Desktop\review\爬虫\day05\phantomjs-2.1.1-windows\bin\phantomjs.exe'
# 模拟创建一个浏览器对象,然后通过对象去操作浏览器
browser = webdriver.PhantomJS(path)
url = r'https://movie.douban.com/typerank?type_name=%E5%8A%A8%E4%BD%9C&type=5&interval_id=100:90&action='
browser.get(url)
sleep(2)
browser.save_screenshot(r'phantomjs\douban1.png')

# 让browser执行简单的js代码,模拟滚动条滚动到底部,仅对PhantomJS有用
js = 'document.body.scrollTop=10000'
browser.execute_script(js)
sleep(2)
browser.save_screenshot(r'phantomjs\douban2.png')

# 获取网页的代码,保存到文件中
html = browser.page_source
with open(r'phantomjs\douban.html', 'w', encoding='utf8') as fp:
fp.write(html)

# 关闭浏览器(退出浏览器)
browser.quit()


if __name__ == '__main__':
main()

Python 中 Selenium 操作下拉滚动条方法汇总
如何向下滚动到页面的底部?

图片加载

  • 图片懒加载
  • 获取网页的代码: browser.page_source
  • 示例
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    from selenium import webdriver
    import time

    path = r'C:\Users\ZBLi\Desktop\1801\day05\ziliao\phantomjs-2.1.1-windows\bin\phantomjs.exe'
    browser = webdriver.PhantomJS(path)

    url = 'http://sc.chinaz.com/tag_tupian/OuMeiMeiNv.html'

    browser.get(url)
    time.sleep(3)
    with open(r'phantomjs\tupian1.html', 'w', encoding='utf8') as fp:
    fp.write(browser.page_source)

    js = 'document.body.scrollTop=10000'
    browser.execute_script(js)
    time.sleep(3)

    with open(r'phantomjs\tupian2.html', 'w', encoding='utf8') as fp:
    fp.write(browser.page_source)

    browser.quit()

登录

  • 前面讲的登录过程:直接抓包找到 post 地址,发送过去即可登录成功
  • 现在的登录过程:直接抓包发送 post 不行,因为表单中有一些数据需要从网页中获取到,比如这里的 formhash。那么,现在的登录过程,就变成了,先发送 get 请求到登录页面,然后通过 xpath、bs 获取需要的表单令牌,然后再发送 post 请求,开始登录
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import urllib.request
import urllib.parse

'''
1、前面讲的登录过程:直接抓包找到post地址,发送过去即可登录成功
2、现在的登录过程:直接抓包发送post不行,因为表单中有一些数据需要从网页中获取到,比如这里的formhash。那么,现在的登录过程,就变成了,先发送get请求到登录页面,然后通过xpath、bs获取需要的表单令牌,然后再发送post请求,开始登录
'''

url = 'http://bbs.chinaunix.net/member.php?mod=logging&action=login&loginsubmit=yes&loginhash=LCGbY'

headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36'
}

formdata = {
# 表单令牌
'formhash': '7e549c64',
'referer': 'http://bbs.chinaunix.net/',
'username': 'wolfmonkey',
'password': 'lizhibin666',
'loginsubmit': 'true',
'return_type': '',
}

formdata = urllib.parse.urlencode(formdata).encode()
request = urllib.request.Request(url=url, headers=headers)

response = urllib.request.urlopen(request, data=formdata)

# print(response.read().decode('gbk'))
with open('unix.html', 'wb') as fp:
fp.write(response.read())

简介

  • Headless Chrome 是 Chrome 浏览器的无界面形态,可以在不打开浏览器的前提下,使用所有 Chrome 支持的特性运行你的程序。相比于现代浏览器,Headless Chrome 更加方便测试 web 应用,获得网站的截图,做爬虫抓取信息等。相比于出道较早的 PhantomJS,SlimerJS 等,Headless Chrome 则更加贴近浏览器环境。
  • 为什么使用它?因为 PhantomJS 现在都不维护了!
  • 目前在 Mac 和 Linux 上,Chrome 版本号在 59 + 以上,才支持这种模式;在 Windows 上,要求 Chrome 版本号在 60 + 以上,才支持这种模式!

使用 Headless Chrome

1
2
3
4
5
6
7
8
from selenium.webdriver.chrome.options import Options

# 创建一个参数对象,用来控制Chrome以无界面模式打开
options = Options()
# 以无界面模式运行Chrome
options.add_argument('--headless')
# --disable-gpu 主要是为了屏蔽现阶段可能触发的错误,在Windows上运行时需要
options.add_argument('--disable-gpu')

简单示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
from time import sleep
from selenium import webdriver
from selenium.webdriver.chrome.options import Options

# 创建一个参数对象,用来控制Chrome以无界面模式打开
options = Options()
# 以无界面模式运行Chrome
options.add_argument('--headless')
# --disable-gpu 主要是为了屏蔽现阶段可能触发的错误,在Windows上运行时需要
options.add_argument('--disable-gpu')
# 设置无界面浏览器尺寸
options.add_argument('--window-size=1920,1080')


def main():
# 模拟创建一个浏览器对象,然后通过对象去操作浏览器
driver = webdriver.Chrome(options=options)
url = 'https://www.baidu.com/'
driver.get(url)
# 关闭浏览器(退出浏览器)
sleep(2)
driver.save_screenshot('baidu.png')
driver.quit()


if __name__ == '__main__':
main()