【爬虫】7.1. JavaScript动态渲染界面爬取-Selenium

JavaScript动态渲染界面爬取-Selenium的简单学习

文章目录

  • JavaScript动态渲染界面爬取-Selenium的简单学习
    • 1. Selenium准备工作
    • 2. Selenium简单用法
      • 2.1. 初始化浏览器对象-webdriver.Chrome()
      • 2.2. 访问界面-browser.get()
      • 2.3. 查找节点-find_element()
      • 2.4. 节点交互-send_keys()、clear()、click()
      • 2.5. 动作链-ActionChains()
      • 2.6. 运行JavaScript-execute_script()
      • 2.7. 获取节点信息-get_attribute()、text、id、location、tag_name、size
      • 2.8. 切换Frame-switch_to.frame()
      • 2.9. 延时等待
        • 2.9.1. 隐式等待-implicitly_wait()
        • 2.9.2. 显式等待-WebDriverWait()
      • 2.10. 前进和后退-forward()、back()
      • 2.11. Cookie-add_cookie()、delete_all_cookies()
      • 2.12. 选项卡管理-execute_script()
    • 3. 反屏蔽
    • 4. 无头模式

引言:在学习这一章之前,若之前对于Ajax数据的分析和爬取有过了解的会知道,Ajax是JavaScript动态渲染界面的一种情形,通过直接分析Ajax,使我们仍然可以借助requests或urllib实现数据爬取。不过JavaScript动态渲染的界面不止Ajax一种,而且在实际中Ajax接口中会含有很多加密参数,比如说xhr中request url的链接中含有token参数使我们难以找到规律,所以很难直接通过分析Ajax爬取数据。

​ Python提供了许多模拟浏览器运行的库,例如Selenium、Splash、Pyppetter、Playwright等,可以帮我们实现所见皆所爬,就不用再为如何爬取动态渲染的界面发愁了。

1. Selenium准备工作

Selenium是一个自动化测试工具,利用它可以驱动浏览器完成特定的操作,例如点击、下拉等,你还可以利用这个工具来恶搞别人浏览不良网站!!!言归正传,你可以利用它获取浏览器当前呈现的页面源代码,做到所见皆所爬,对于一些JavaScript动态渲染的界面来说,这种爬取方式非常有效。 本节以Chrome浏览器为例来讲解Selenium。首先先安装好Chrome和Selenium库。

首先来看看Selenium的功能:

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
import timebrowser = webdriver.Chrome()
try:browser.get('https://www.baidu.com')input = browser.find_element(By.ID, 'kw')input.send_keys('Python')input.send_keys(Keys.ENTER)wait = WebDriverWait(browser, 10)wait.until(EC.presence_of_element_located((By.ID, 'content_left')))print(browser.current_url)print(browser.get_cookies())print(browser.page_source)time.sleep(1000)
finally:browser.close()

运行代码后,会自动弹出一个Chrome浏览器,接着浏览器会跳转到百度界面并在搜索框中输入Python,就会自动跳转到搜索结果页。输出页面源代码,此处省略源代码,可以知道,我们得到的当前URL、Cookie和页面源代码都是真实内容,而用requests请求的源代码却和使用Selenium的源代码不一样。所以说,用Selenium驱动浏览器加载的页面可以直接拿到JavaScript渲染的结果,无须关心是什么加密系统。

2. Selenium简单用法

2.1. 初始化浏览器对象-webdriver.Chrome()

Selenium支持的浏览器非常多,既有Chrome、Firefox、Edge、Safari等电脑端的浏览器,也有Android、BlackBerry等手机端的浏览器。下面是初始化浏览器对象:

from selenium import webdriver
browser1 = webdriver.Chrome()
# browser2 = webdriver.Firefox()
# browser3 = webdriver.Edge()
print(type(browser1))  # <class 'selenium.webdriver.chrome.webdriver.WebDriver'>
browser1.close()

2.2. 访问界面-browser.get()

上面我们已经初始化了浏览器对象,接下来就是要调用browser,执行各个方法模拟浏览器操作。访问界面:

from selenium import webdriver
url = "https://www.taobao.com/"
browser1 = webdriver.Chrome()
browser1.get(url)
browser1.close()

2.3. 查找节点-find_element()

我们想从淘宝页面提取搜索框这个节点,那就进入开发者选项快捷搜索就行了。

from selenium import webdriver
from selenium.webdriver.common.by import By
url = "https://www.taobao.com/"
browser1 = webdriver.Chrome()
browser1.get(url)
input_first = browser1.find_element(By.ID, "q")
print(input_first)
# <selenium.webdriver.remote.webelement.WebElement (session="dc29f31092c770c57925bbd74839af9d", element="C15004B057068D353AA2B162C5D9F24E_element_2")>
browser1.close()

但是这种方法只会查找第一个匹配的节点,要是想要查找多个节点那就使用find_elements(),这时返回的内容是列表类型的,列表里面每一个元素都是WebElement类型的。

2.4. 节点交互-send_keys()、clear()、click()

Selenium可以驱动浏览器执行一些操作。比较常见的用法有:用send_keys方法输入文字,用clear方法清空文字,用click方法点击按钮:

from selenium import webdriver
from selenium.webdriver.common.by import By
import time
url = "https://www.taobao.com/"
browser1 = webdriver.Chrome()
browser1.get(url)
# 查找对话框,按钮
input_first = browser1.find_element(By.ID, "q")
button = browser1.find_element(By.CLASS_NAME, "btn-search")
# 输入文字
input_first.send_keys("IPad")
time.sleep(3)
# 清空文字
input_first.clear()
# 输入文字
input_first.send_keys("HUAWEI")
# 点击按钮
button.click()
time.sleep(3)
browser1.close()

更多操作请见官方文档

https://selenium-python.readthedocs.io/api.html#module-selenium.webdriver.remote.webelement

2.5. 动作链-ActionChains()

在上面示例中,交互操作都是针对某一个节点来执行的。其实还有一些操作,他们没有特定的执行对象,比如鼠标拖拽、按键键盘等,这些操作需要另一种方式执行,那就是动作链。例如可以这样实现拖拽节点的操作:

from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By
import timebrowser = webdriver.Chrome()
url = 'http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable'
browser.get(url)
# 切换到名为 'iframeResult' 的 iframe 内容(这个网页被分为很多个框架)
browser.switch_to.frame('iframeResult')
# 找到要拖拽的源元素和目标元素
source = browser.find_element(By.CSS_SELECTOR, '#draggable')
target = browser.find_element(By.CSS_SELECTOR,'#droppable')
# 创建 ActionChains 对象来执行操作
actions = ActionChains(browser)
# 进行拖拽操作
actions.drag_and_drop(source, target)
# 执行
actions.perform()
time.sleep(5)

更多的动作链请参考官方文档的介绍:

https://selenium-python.readthedocs.io/api.html#module-selenium.webdriver.common.action_chains

2.6. 运行JavaScript-execute_script()

还有一些操作,Selenium没有提供API,例如下拉进度条,面对这种情况可以模拟运行JavaScript,此时使用execute_script方法可以实现,代码如下:

from selenium import webdriverbrowser = webdriver.Chrome()
browser.get('https://www.zhihu.com/explore')
browser.execute_script('window.scrollTo(0, document.body.scrollHeight)')
browser.execute_script('alert("To Bottom")')

2.7. 获取节点信息-get_attribute()、text、id、location、tag_name、size

当我们选中一个节点时候,我们可以获取它的属性、文本、ID、位置、标签名和大小:

  • get_attribute():获取属性,参数传入属性名
  • text:获取文本
  • id:获取id
  • location:获取位置
  • tag_name:获取标签名
  • size:获取大小

2.8. 切换Frame-switch_to.frame()

网页中有一种节点叫做iframe,也就是子Frame,相当于页面中的子页面,它的结构和外部网页的结构完全一致。Selenium打开一个页面之后,默认是在父Frame里操作,此时如果页面中含有子Frame,是不能在子Frame中操作的,这时就需要使用switch_to.frame方法切换Frame。

import time
from selenium import webdriver
from selenium.common.exceptions import NoSuchElementExceptionbrowser = webdriver.Chrome()
url = 'http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable'
browser.get(url)
browser.switch_to.frame('iframeResult')
try:logo = browser.find_element_by_class_name('logo')
except NoSuchElementException:print('NO LOGO')
browser.switch_to.parent_frame()
logo = browser.find_element_by_class_name('logo')
print(logo)
print(logo.text)

2.9. 延时等待

在Selenium中,get方法在网页框架结束后才会结束执行,如果我们尝试在get方法执行完毕时获取网页源代码,可能结果不是浏览器加载完全的页面,因为某些页面需要额外的Ajax请求还会经过JavaScript渲染,所以有必要让浏览器延时一段时间。这里的等待方式有两种,一种是隐式等待,一种是显式等待。

2.9.1. 隐式等待-implicitly_wait()

使用隐式等待执行测试时,在查找节点而节点没有立即出现时,隐式等待会先等待一段时间再查找DOM,默认的等待时间为0

from selenium import webdriver
from selenium.webdriver.common.by import Bybrowser = webdriver.Chrome()
# 设置隐式等待时间
browser.implicitly_wait(10)
browser.get("https://spa2.scrape.center/")
input_first = browser.find_element(By.CLASS_NAME, "logo-image")
print(input_first.get_attribute("src"))

2.9.2. 显式等待-WebDriverWait()

隐式等待的效果其实并不好,因为我们只规定了一个固定时间,而页面加载时间会受网络条件的影响。还有一种更合适的等待方法——显式等待,这种方式会指定查找的节点和最长等待时间,如果在规定时间内加载出了要查找的节点,就返回这个节点;如果到规定时间内依然没有加载出节点,就抛出超时异常。

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 ECbrowser = webdriver.Chrome()
browser.get("https://taobao.com")
# 设定wait对象,指定最长等待时间
wait = WebDriverWait(browser, 10)
# 调用wait的until方法,传入等待条件
input = wait.until(EC.presence_of_element_located((By.ID, "q")))
# 等待条件:代表按钮式可点击的
button = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, ".btn-search")))
print(input, button)

下面表格列出了所有等待条件(应该)

等待条件(Expected Conditions)描述
EC.presence_of_element_located元素出现在 DOM 中。
EC.visibility_of_element_located元素在页面上可见。
EC.visibility_of元素在页面上可见。
EC.invisibility_of_element_located元素在页面上不可见。
EC.element_to_be_clickable元素可被点击。
EC.element_to_be_selected元素被选中。
EC.element_located_to_be_selected元素被选中。
EC.text_to_be_present_in_element在元素中出现特定文本。
EC.text_to_be_present_in_element_value在元素的值中出现特定文本。
EC.frame_to_be_available_and_switch_to_it切换到指定的 iframe 或 frame 中。
EC.element_to_be_located元素出现在 DOM 中。
EC.staleness_of元素不再附加到 DOM 上(已过时)。
EC.element_located_selection_state_to_be元素的选中状态与给定状态匹配。
EC.element_selection_state_to_be元素的选中状态与给定状态匹配。
EC.alert_is_present存在警报。
EC.title_contains页面标题包含指定文本。
EC.title_is页面标题等于指定文本。
EC.url_contains页面 URL 包含指定文本。
EC.url_to_be页面 URL 完全等于指定 URL。
EC.url_matches页面 URL 匹配指定的正则表达式。
EC.invisibility_of_element_located元素在页面上不可见。

更多等待条件和参数及其用法可以参考官方文档:

https://selenium-python.readthedocs.io/api.html#module-selenium.webdriver.support.expected_conditions

2.10. 前进和后退-forward()、back()

平时使用浏览器时也有前进和后退的功能,用Selenium也可以完成这个操作。

from selenium import webdriver
import timebrowser = webdriver.Chrome()
browser.get("https://www.baidu.com/")
browser.get("https://www.taobao.com/")
browser.get("https://www.python.org")
browser.back()
time.sleep(3)
browser.forward()
time.sleep(3)
browser.close()

2.11. Cookie-add_cookie()、delete_all_cookies()

使用selenium还可以对Cookie进行操作

from selenium import webdriverbrowser = webdriver.Chrome()
browser.get("https://www.zhihu.com/explore")
print(browser.get_cookies())
cookie = {'name': 'AJ', 'value': 'BJ'}
browser.add_cookie(cookie)
print(browser.get_cookies())
browser.delete_all_cookies()  # 去掉all也可以指定删除哪一个
print(browser.get_cookies())

2.12. 选项卡管理-execute_script()

访问网页的时候,会开启一个个选项卡。在Selenium中,我们也可以对选项卡进行操作:

import time
from selenium import webdriverbrowser = webdriver.Chrome()
browser.get("https://www.baidu.com/")
# 打开一个新的选项卡
browser.execute_script("window.open()")
print(browser.window_handles)
# 切换到新的选项卡
browser.switch_to.window(browser.window_handles[1])
browser.get("https://www.taobao.com")
time.sleep(2)
# 切换回去
browser.switch_to.window(browser.window_handles[0])
browser.get("https://python.org")

3. 反屏蔽

现在有很多网站增加了对Selenium的检测,防止一些爬虫的恶意爬取,如果检测到有人使用Selenium打开浏览器就会直接屏蔽。大多数情况下,检测的基本原理时检测当前浏览器窗口下的window.navigator对象中是否包含webdriver属性。是因为正常使用浏览器时,这个属性应该是undefined,一旦使用了Selenium。它就会给window.navigator对象设置为webdriver属性。很多网站会通过JavaScript语句判断是否存在webdriver属性。

在Selenium中,可以用CDP(即Chrome Devtools Protocol,Chrome 开发工具协议)解决这个问题,利用它可以实现在每个页面刚加载的时候就执行JavaScript语句,将webdriver属性置空。这里执行的CDP方法叫做Page.addScriptToEvaluateOnNewDocument,将上面的JavaScript语句传入其中即可。另外,还可以加入几个选项来隐藏WebDriver提示条和自动化扩展信息。

from selenium import webdriver
from selenium.webdriver import ChromeOptions
import timeoption = ChromeOptions()
option.add_experimental_option('excludeSwitches', ['enable-automation'])
option.add_experimental_option('useAutomationExtension', False)
browser = webdriver.Chrome(options=option)
browser.execute_cdp_cmd('Page.addScriptToEvaluateOnNewDocument', {'source': 'Object.defineProperty(navigator, "webdriver", {get: () => undefined})'
})
browser.get('https://antispider1.scrape.center/')
time.sleep(10)

4. 无头模式

上面的案例在运行的时候总会弹出一个浏览器窗口,我们也可以把它去掉,这样可以减少一些资源的加载:

from selenium import webdriver
from selenium.webdriver import ChromeOptionsoption = ChromeOptions()
option.add_argument("--headless")
browser = webdriver.Chrome(options= option)
browser.set_window_size(1366, 768)
browser.get("https://www.baidu.com")
browser.get_screenshot_as_file("preview.png")

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/64508.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

多线程练习-使用两个线程来累加 count 的值

题目 有20个线程&#xff0c;需要同时启动。 每个线程按0-19的序号打印&#xff0c;如第一个线程需要打印0 请设计代码&#xff0c;在main主线程中&#xff0c;等待所有子线程执行完后&#xff0c;再打印 ok 代码以及注释 public class Soultion {public static void main…

QUdpSocket Class

继承自 QAbstractSocket 类 QUdpSocket类提供UDP套接字。 UDP(用户数据报协议)是一种轻量级、不可靠、面向数据报、无连接的协议。它可以在可靠性不重要的情况下使用。QUdpSocket是QAbstractSocket的一个子类&#xff0c;它允许您发送和接收UDP数据报。 使用这个类最常见的方法…

C++STL字符串string知识汇总,恶补!

基础不牢&#xff0c;地动山摇。 今天小米的笔试编程题&#xff0c;输入格式是一整个字符串&#xff0c;需要从字符串中分割出数据&#xff0c;同时还需要将字符串转换为int数值。 本来用C写&#xff0c;写到一般想起来了C中没有split()函数&#xff0c;想到在java中有这个函数…

Linux安装包deb格式安装方法

deb格式介绍 DEB是Debian软件包格式的文件扩展名&#xff0c;跟Debian的命名一样&#xff0c;DEB也是因Debra Murdock而得名&#xff0c;她是Debian创始人Ian Murdock的太太。 安装方法 主要有两种: apt: 支持离线在线的结合安装,主要解决部分安装包依赖不全的问题dpkg: 纯…

【探索SpringCloud】服务发现-Nacos服务端数据结构和模型

前言 上一文中&#xff0c;我们从官方的图示了解到Nacos的服务数据结构。但我关心的是&#xff0c;Nacos2.x不是重构了吗&#xff1f;怎么还是这种数据结构&#xff1f;我推测&#xff0c;必然是为了对Nacos1.x的兼容&#xff0c;实际存储应该不是这样的。于是&#xff0c;沿着…

VueRouter的基本使用

路由的基本使用 文章目录 路由的基本使用01-VueRouterVueRouter的使用 &#xff08; 5 2&#xff09;综合代码 拓展&#xff1a;组件存放问题 什么是路由呢&#xff1f; 在生活中的路由&#xff1a;设备和IP的映射关系 在Vue中&#xff1a;路径 和 组件 的 映射 关系。 01-Vu…

怎么从0到1创建一个PHP框架-1?

写在前面 本人开发的框架在2021年年初开发完成&#xff0c;后面没有再做过任何维护和修改。是仅供大家参考交流的学习项目&#xff0c;请勿使用在生产环境&#xff0c;也勿用作商业用途。 框架地址&#xff1a; https://github.com/yijiebaiyi/fast_framework 整体思路 开发…

SpringBoot第45讲:SpringBoot定时任务 - Timer实现方式

SpringBoot第45讲:SpringBoot定时任务 - Timer实现方式 定时任务在实际开发中有着广泛的用途,本文是SpringBoot第45讲,主要帮助你构建定时任务的知识体系,同时展示Timer 的schedule和scheduleAtFixedRate例子;后续的文章中我们将逐一介绍其它常见的定时任务,并与SpringBo…

并发测试工具 apache-jmeter使用发送post请求JSON数据

目录 1 下载安装 2 汉化 3 创建高并发测试 配置线程组 创建web请求 创建监听器 结果树 汇总报告 为web请求添加token 添加Content-Type用于发送json 4 启动测试 5 查看结果 1 下载安装 官网Apache JMeter - Download Apache JMeter 解压运行 2 2 汉化 打开软件…

【Mysql系列】(一)MySQL语句执行流程

首发博客地址 首发博客地址 系列文章地址 参考文章 MySQL 逻辑架构 连接器 连接命令一般是这么写的 mysql -h$ip -P$port -u$user -p 那么 什么是连接器&#xff1f; MySQL 连接器&#xff08;MySQL Connector&#xff09;是用于连接和与 MySQL 数据库进行交互的驱动程序。它提…

远程管理通道安全SSH协议主机验证过程

可以使用SSH协议进行远程管理通道安全保护&#xff0c;其中涉及的主要安全功能包括主机验证、数据加密性和数据完整性保护。 这里要注意的是【主机验证】和【身份验证】的区别&#xff0c;主机验证是客户端确认所访问的服务端是目标访问对象&#xff0c;比如从从客户端A(192.16…

MongoDB 的简介

MongoDB 趋势 对于 MongoDB 的认识 Q&A QA什么是 MongoDB&#xff1f; 一个以 JSON 为数据模型的文档数据库一个以 JSON 为数据模型的文档数据库文档来自于“JSON Document”&#xff0c;并非我们一般理解的 PDF&#xff0c;WORD谁开发 MongDB&#xff1f; 上市公司 MongoD…

【USRP】产品型号、参数、架构全解析系列 1:B200 / B210 / B200mini / B205mini

一、 USRP 简介 通用软件无线电外设( USRP ) 是由 Ettus Research 及其母公司National Instruments设计和销售的一系列软件定义无线电。USRP 产品系列由Matt Ettus领导的团队开发&#xff0c;被研究实验室、大学和业余爱好者广泛使用。 大多数 USRP 通过以太网线连接到主机&a…

每日一题 1372二叉树中的最长交错路径

题目 给你一棵以 root 为根的二叉树&#xff0c;二叉树中的交错路径定义如下&#xff1a; 选择二叉树中 任意 节点和一个方向&#xff08;左或者右&#xff09;。如果前进方向为右&#xff0c;那么移动到当前节点的的右子节点&#xff0c;否则移动到它的左子节点。改变前进方…

flutter plugins插件【三】【Flutter Intl】

3、 Flutter Intl 多语言国际化 在Android Studio中菜单Tools找到flutter intl创建多语言配置。 创建后会在pubspec.yaml出现 flutter_intl:enabled: true 在工程的lib会生成l10n与generated文件夹 l10n包含 intl_en.arb intl_zn.arb 我们在intl_en.arb添加 { home: &quo…

青翼科技基于VITA57.1的16路数据收发处理平台产品手册

FMC211是一款基于VITA57.1标准规范的实现16路LVDS数据采集、1路光纤数据收发处理FMC子卡模块。 该板卡支持2路CVBS&#xff08;复合视频&#xff09;视频输入&#xff0c;能够自动检测标准的模拟基带电视信号&#xff0c;并将其转变为8位ITU-R.656接口信号或者4:2:2分量视频信…

Leetcode 面试题 17.01 不用加号的加法

设计一个函数把两个数字相加。不得使用 或者其他算术运算符。 示例: 输入: a 1, b 1 输出: 2 提示&#xff1a; a, b 均可能是负数或 0结果不会溢出 32 位整数 我的答案&#xff1a; 一、信息 1.设计一个函数把两个数相加 2.不得使用或者其他运算符 3.a,b均为负数或…

企业工程项目管理系统源码-专注项目数字化管理-Java工程管理-二次开发

工程项目各模块及其功能点清单 一、系统管理 1、数据字典&#xff1a;实现对数据字典标签的增删改查操作 2、编码管理&#xff1a;实现对系统编码的增删改查操作 3、用户管理&#xff1a;管理和查看用户角色 4、菜单管理&#xff1a;实现对系统菜单的增删改查操…

什么是 Web 应用程序安全测试?

Web 应用程序安全测试是一种严格的实践&#xff0c;旨在识别、分析和纠正基于 Web 的应用程序中的漏洞。 此过程涉及使用一套全面的工具和方法来评估 Web 应用程序的安全性和完整性。它包括渗透测试、漏洞评估和代码审查等实践。 Web 应用程序安全测试的主要目标是阻止潜在的…

C++ Primer阅读笔记--对象移动(右值引用、移动迭代器和引用限定符的使用)

目录 1--右值引用 2--std::move 3--移动构造函数 4--移动赋值运算符 5--移动迭代器 6--引用限定符 1--右值引用 右值引用必须绑定到右值的引用&#xff0c;通过 && 获得右值引用&#xff1b; 右值引用只能绑定到临时对象&#xff08;即将被销毁的对象&#xff09…