【Python】第七章 JavaScript动态渲染页面爬取
目录
1. Selenium的使用
很大情况下Ajax请求会使用加密参数
token
sign
…
Ajax接口包含token数据
模拟Ajax请求的两种方式
绕过上方过程
将呈现的数据直接爬取下来
把token参数的构造逻辑完全找出
再用python代码复现
构造Ajax请求
深挖逻辑
直接模拟浏览器的运行(使用Selenium)
Selenium
点击
下拉
···
自动化测试工具
可以驱动浏览器完成特定的操作
获取浏览器当前呈现的页面源代码
1.1 准备工作
安装selenium
pip install selenium1
安装WebDriver
WebDriver配置
将WebDriver的.exe文件放入Python的根目录下
1.2 基本用法
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 browser = webdriver.Edge() try: browser.get('https://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) finally: browser.close()
1.3 初始化浏览器对象
电脑端浏览器
Chrome
Firefox
Edge
Safari
…
手机端浏览器
Android
BlackBerry
…
from selenium import webdriver browser = webdriver.Chrome() browser = webdriver.Firefox() browser = webdriver.Edge() browser = webdriver.Safari()
1.4 访问页面
page_source:获取网页源码
from selenium import webdriver browser = webdriver.Edge() browser.get("https://www.taobao.com") print(browser.page_source) browser.close()
1.5 查找节点
单个节点
获取淘宝网 - 淘!我喜欢 (taobao.com)的搜索框
观察源码分析获取
from selenium import webdriver from selenium.webdriver.common.by import By browser = webdriver.Edge() browser.get("https://www.taobao.com") input_first = browser.find_element(By.ID, "q") input_second = browser.find_element(By.CSS_SELECTOR, "#q") input_third = browser.find_element(By.XPATH, "//*[@id=\"q\"]") print(input_first, input_second, input_third) browser.close()
多个节点
获取淘宝网 - 淘!我喜欢 (taobao.com)左侧导航条的所有条目
from selenium import webdriver from selenium.webdriver.common.by import By browser = webdriver.Edge() browser.get("https://www.taobao.com") lis = browser.find_elements(By.CSS_SELECTOR, ".service-bd li") print(lis) browser.close()
1.6 节点交互
send_keys:输入文字
clear:清空文字
click:点击按钮
from selenium import webdriver from selenium.webdriver.common.by import By import time browser = webdriver.Edge() browser.get('https://taobao.com') input = browser.find_element(By.ID, 'q') input.send_keys('iPhone') time.sleep(1) input.clear() input.send_keys("iPad") button = browser.find_element(By.CLASS_NAME, "btn-search") button.click()
1.7 动作链
拖拽节点
from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver import ActionChains browser = webdriver.Edge() browser.get("https://www.runoob.com/try/try.php?filename=jqueryui-api-droppable") browser.switch_to.frame("iframeResult") source = browser.find_element(By.CSS_SELECTOR, "#draggable") target = browser.find_element(By.CSS_SELECTOR, "#droppable") actions = ActionChains(browser) actions.drag_and_drop(source, target) actions.perform()
1.8 运行JavaScript
from selenium import webdriver browser = webdriver.Edge() browser.get("https://www.zhihu.com/explore") browser.execute_script("window.scrollTo(0, document.body.scrollHeight)") browser.execute_script("alert(\"To Bottom\")")
1.9 获取节点信息
获取属性
from selenium import webdriver from selenium.webdriver.common.by import By browser = webdriver.Edge() browser.get("https://spa2.scrape.center/") logo = browser.find_element(By.CLASS_NAME, "logo-image") print(logo) print(logo.get_attribute("src"))
获取文本值
from selenium import webdriver from selenium.webdriver.common.by import By browser = webdriver.Edge() browser.get("https://spa2.scrape.center/") input = browser.find_element(By.CLASS_NAME, "logo-title") print(input.text)
获取ID、位置、标签名和大小
from selenium import webdriver from selenium.webdriver.common.by import By browser = webdriver.Edge() browser.get("https://spa2.scrape.center/") input = browser.find_element(By.CLASS_NAME, "logo-title") print(input.id) print(input.location) print(input.tag_name) print(input.size)
1.10 切换Frame
selenium打开网页后默认在父Frame中操作
如果此时页面中有子Frame(iframe)需要使用switch_to.frame方法切换Frame
from selenium import webdriver from selenium.webdriver.common.by import By from selenium.common.exceptions import NoSuchElementException browser = webdriver.Edge() browser.get("https://www.runoob.com/try/try.php?filename=jqueryui-api-droppable") 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)
1.11 延时等待
selenium的get方法在网页框架加载结束后才会结束执行
如果在get方法执行完毕时获取网页源代码,其结果可能不是浏览器完全加载完成的页面
额外的Ajax请求
JavaScript渲染
设置浏览器延时等待一定的时间,确保节点已经加载出来
隐式等待
如果selenium没有在DOM中找到节点,将继续等待,在超出设定时间后,抛出找不到节点的异常
在查找节点而节点没有立即出现时,隐式等待会先等待一段时间再查找DOM
from selenium import webdriver from selenium.webdriver.common.by import By browser = webdriver.Edge() browser.implicitly_wait(10) browser.get("https://spa2.scrape.center/") input = browser.find_element(By.CLASS_NAME, "logo-image") print(input)
显式等待
指定要查找的节点和最长等待时间
如果在规定时间内加载出了要查找的节点,就返回这个节点
如果找到了规定时间依然没有加载出来,就抛出超时异常
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 browser = webdriver.Edge() browser.get("https://www.taobao.com/") wait = WebDriverWait(browser, 10) 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)
等待条件
官方说明文档
EC包文件
详情见
等待条件 | 含义 |
---|---|
title_is | 标题是某内容 |
title_contains | 标题包含某内容 |
presence_of_element_located | 节点出现,参数为节点的定位元组 如(By.ID, “p”) |
visibility_of_element_located | 节点可见,参数为节点的定位元组 |
visibility_of | 可见,参数为节点对象 |
presence_of_all_elements_located | 所有节点都出现 |
text_to_be_present_in_element | 某个节点的文本值中包含某文字 |
text_to_be_present_in_element_value | 某个节点值中包含某文字 |
frame_to_be_available_and_switch_to_it | 加载并切换 |
invisibility_of_element_located | 节点不可见 |
element_to_be_clickable | 按钮可点击 |
staleness_of | 判断一个节点是否仍在DOM中 可知页面是否已经刷新 |
element_to_be_selected | 节点可选择,参数为节点对象 |
element_located_to_be_selected | 节点可选择,参数为节点的定位元组 |
element_selection_state_to_be | 参数为节点对象及状态 相等返回True,否则返回False |
element_located_selection_state_to_be | 参数为定位元组及状态 相等返回True,否则返回False |
alert_is_present | 是否出现警告提示框 |
1.12 前进和后退
forward():前进
back():后退
from selenium import webdriver import time browser = webdriver.Edge() browser.get("https://www.baidu.com/") browser.get("https://www.taobao.com/") browser.get("https://www.python.org/") browser.back() time.sleep(10) browser.forward() browser.close()
1.13 Cookie
from selenium import webdriver import time browser = webdriver.Edge() browser.get("https://www.zhihu.com/explore") print(browser.get_cookies()) browser.add_cookie({"name": "name", "domain": "www.zhihu.com", "value": "ABC"}) print(browser.get_cookies()) # 如果不sleep可能因为有部分cookie还未加载,导致清空cookies是有cookie残留 time.sleep(5) browser.delete_all_cookies() print(browser.get_cookies())
1.14 选项卡管理
from selenium import webdriver import time browser = webdriver.Edge() 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(1) browser.switch_to.window(browser.window_handles[0]) browser.get("https://python.org")
1.15 异常处理
节点未找到的异常
from selenium import webdriver from selenium.webdriver.common.by import By browser = webdriver.Edge() browser.get("https://www.baidu.com") browser.find_element(By.ID, "hello")
处理异常
from selenium import webdriver from selenium.webdriver.common.by import By from selenium.common.exceptions import TimeoutException ,NoSuchElementException browser = webdriver.Edge() try: browser.get("https://www.baidu.com") except TimeoutException: print("Time Out") try: browser.find_element(By.ID, "hello") except NoSuchElementException: print("No Element") finally: browser.close()
1.16 反屏蔽
很多网站会对selenium进行检测,防止一些爬虫的恶意爬取
检测原理
如果存在就直接屏蔽
在正常使用浏览器时,这个属性应该是undefined
一旦使用了selenium,它就会给window.navigator对象设置webdriver属性
检测当前浏览器窗口下的window.navigator对象中是否包含webdriver属性
很多网站通过JavaScript语句判断是否存在webdriver属性
示例网站:Scrape | Movie
访问示例网站
from selenium import webdriver browser = webdriver.Edge() browser.get("https://antispider1.scrape.center/")
直接使用JavaScipt语句把webdriver属性置空
from selenium import webdriver browser = webdriver.Edge() browser.get("https://antispider1.scrape.center/") browser.execute_script("Object.defineProperty(navigator, \"webdriver\", {get: () => undefined})")
确实将webdriver属性置空
但是execute_script方法是在页面加载之后才调用JavaScript语句的,此时网页早在页面渲染之前就已经检测webdriver属性了
使用CDP(Chrome Devtools Protocol,Chrome开发工具协议)解决
可以实现在每个页面加载的时候执行JavaScript语句,将webdriver属性置空
执行CDP的方法为Page.addScriptToEvaluateOnNewDocument
Edge Devtools Protocol是基于CDP的所以CDP使用方式在Edge Devtools Protocol上同样适用
from selenium import webdriver from selenium.webdriver import EdgeOptions option = EdgeOptions() # 隐藏提示条 option.add_experimental_option("excludeSwitches", ["enable-automation"]) # 隐藏自动化扩展信息 option.add_experimental_option("useAutomationExtension", False) browser = webdriver.Edge(options=option) browser.execute_cdp_cmd( "Page.addScriptToEvaluateOnNewDocument", { "source": "Object.defineProperty(navigator, \"webdriver\", {get: () => undefined})"}) browser.get("https://antispider1.scrape.center/")
1.17 无头模式
使网站运行时不会弹出窗口
减少一些资源的加载
使用EdgeOptions对象开启Edge浏览器的无头模式
from selenium import webdriver from selenium.webdriver import EdgeOptions option = EdgeOptions() option.add_argument("--headless") browser = webdriver.Edge(options=option) browser.set_window_size(1500, 800) browser.get("https://www.baidu.com") browser.get_screenshot_as_file("preview.png")
2. Splash的使用
猜你喜欢
- 【Python】如何在系统中安装pandas库
- 快速入门:Python安装pandas库的方法,需要具体代码示例一、概述Python是一种广泛使用的编程语言,它拥有强大的开发生态系统,其中包括许多实用的库。而pandas是其中一款非常受欢迎的数据分析库,它提供了高效的数据结构和数据分析工具,使得数据处理和分析变得更加简单。本文将介绍如何在Python中安装pandas库,并提供相应的代码示例。二、安装Python在安装pandas库之前,首先需要安装Python。Python官方网站提供了最新版本的Python的安装包,可以根据自己的操作系统
- 【Python】如何利用Python编写RSA加密算法
- 如何利用Python编写RSA加密算法?引言:RSA是一种非对称加密算法,被广泛应用于信息安全领域。在现代通信中,RSA加密算法常用于加密和解密敏感数据。本文将介绍如何使用Python编写RSA加密算法,并提供具体的代码示例。1. 安装Python库在开始编写RSA加密算法之前,需要安装Python的加密库。可以使用以下命令安装:pip install rsa2. 生成RSA密钥对在RSA加密算法中,存在公钥和私钥两个密钥。公钥用于加密数据,私钥用于解密数据。首先,我们需要生
- 【Python】学习Python人工智能库的核心技能,构建智能应用
- 打造智能应用:掌握Python人工智能库的核心技能,需要具体代码示例摘要:本文旨在介绍如何使用Python人工智能库开发智能应用。首先,我们将简要介绍Python人工智能库的重要性和应用领域。接下来,我们将重点介绍四个核心技能,包括数据处理、机器学习、深度学习和自然语言处理。我们将通过具体的代码示例和实践案例,深入讲解如何应用这些技能来打造智能应用。引言人工智能是当今科技界炙手可热的话题,而Python作为一种高效简洁的编程语言,拥有丰富的人工智能库,如NumPy、SciPy、TensorFlo
- 【Python】如何使用Python实现拓扑排序算法
- 如何使用Python实现拓扑排序算法?拓扑排序是图论中的一种排序算法,用于对有向无环图(DAG)进行排序。在拓扑排序中,图中的节点代表任务或事件,有向边表示任务或事件之间的依赖关系。在排序结果中,所有的依赖关系都被满足,每个节点都排在它的所有前驱节点之后。在Python中实现拓扑排序算法可以使用深度优先搜索(DFS)的思想来解决。下面是一个具体的代码示例:from collections import defaultdict class Gr
- 【Python】pycharm环境如何配置
- 配置教程:1、下载并安装PyCharm;2、选择Python解释器;3、配置虚拟环境;4、配置代码风格;5、配置调试器;6、配置版本控制工具;7、配置插件;8、配置Python路径和环境变量;9、配置其他选项。详细介绍:1、从PyCharm官网下载适合电脑操作系统的安装包,然后按照提示完成安装;2、在PyCharm中,可以选择已有的Python解释器或者添加新的解释器等等。本教程操作系统:windows10系统、Python3.11.4版本、Dell G3电脑。PyCharm环境配置教程如下:下
- 【Python】如何用Python编写K-均值聚类算法
- 如何用Python编写K-均值聚类算法?K-均值聚类算法是一种常用的数据挖掘和机器学习算法,能够将一组数据按照其属性进行分类和聚类。本文将介绍如何用Python编写K-均值聚类算法,并提供具体的代码示例。在开始编写代码之前,我们需要了解K-均值聚类算法的基本原理。K-均值聚类算法的基本步骤如下:初始化k个质心。质心是指聚类的中心点,每个数据点都会被归到与其最近的质心所代表的类别。根据每个数据点与质心的距离,将其分配到最近的质心所代表的类别。更新质心的位置,将其设置为该类别中所有数据点的平均值。重
- 【Python】如何使用Python中的时间和日期模块
- 如何使用Python中的时间和日期模块导言:在编程中,处理时间和日期是非常常见的任务。Python提供了强大的时间和日期模块,使得处理时间和日期的操作变得更加简单和方便。本文将介绍Python中的时间和日期模块,并提供具体的代码示例,帮助读者更好地理解和应用它们。一、引入时间和日期模块Python内置的时间和日期模块是datetime模块,我们需要先引入该模块才能使用其中的函数和类。示例代码如下:import datetime登录后复制二、获取当前日期和时间如果我们想要获取当前日期和时
- 【Python】如何使用Python实现冒泡排序算法
- 如何使用Python实现冒泡排序算法?冒泡排序算法是一种简单但有效的排序算法,它的思想是不断比较相邻的两个元素,如果它们的顺序不正确,就将它们交换位置,直到整个序列都排好序为止。下面将通过具体的代码示例来演示如何使用Python实现冒泡排序算法。def bubble_sort(arr): n = len(arr) # 外层循环控制比较的轮数 &nbs