【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】如何使用Python中的pickle和JSON进行对象序列化和反序列化
- 如何使用Python中的pickle和JSON进行对象序列化和反序列化Python是一种简单而强大的编程语言,其内置了许多有用的库和模块,使开发人员能够快速进行各种任务。其中,pickle和JSON是两个常用的模块,用于对象序列化和反序列化。本文将介绍如何使用这两个模块进行对象的序列化和反序列化,并提供详细的代码示例。使用pickle进行对象序列化和反序列化pickle是Python中的一个模块,通过它可以将对象转化为二进制数据以便于存储或传输,同时也可以将二进制数据还原为原始对象。首先,我们需
- 【Python】10个Python代码分析工具,助力高效编程
- 文章目录前言10. cProfile和profile8. Pytest9. Coverage6. Black7. isort1. Pylint2. Flake83. MyPy4. Bandit5. Safety代码分析工具代码格式化工具测试工具性能分析工具总结Python入门全套学习资料附带源码:Python零基础入门视频Python项目源码Python入门到进阶电子书籍和实战案例👉100道Python练习题👈👉面试刷题👈资料领取
- 【Python】pip3安装指南
- ip3是Python的包管理器,能够方便地安装、升级和管理Python包。通过pip3,我们可以轻松获取并安装第三方Python库,提高编程效率。本文将为大家介绍pip3的安装过程,并提供具体的代码示例,帮助大家快速掌握pip3的使用方法。一、安装pip3在开始使用pip3之前,首先需要将pip3安装到系统中。下面将介绍几种常见操作系统的安装方法。1. 在Windows系统中安装pip3在Windows系统中,安装pip3非常简单。首先,需要下载get-pip.py文件,可以在https:
- 【Python】解析matplotlib散点图绘制的简明步骤
- 快速入门:matplotlib散点图绘制步骤解析引言:matplotlib是一个强大的Python数据可视化库,可用于绘制各种类型的图表。其中,散点图是一种常用的图表类型,用于展示数据点之间的关系。本文将介绍使用matplotlib绘制散点图的步骤,以及附带具体的代码示例,帮助读者快速入门。步骤一:导入所需库首先,我们需要导入matplotlib库以及其他可能需要使用的库。在Python代码中,使用import关键字来导入所需库,如下所示:import matplotlib.pyplo
- 【Python】如何用Python编写线性查找算法?
- 如何用Python编写线性查找算法?线性查找是最简单的搜索算法之一,也被称为顺序搜索。它的原理很简单,就是从头到尾遍历待查找的数据集合,逐个比较查找目标和数据集合中的元素。下面我们将介绍如何使用Python编写线性查找算法,并给出具体的代码示例。算法实现步骤:遍历待查找的数据集合,逐个比较目标和元素。若找到目标,返回元素的索引位置。若遍历完所有元素仍未找到目标,返回-1。代码示例:def linear_search(arr, target): for i
- 【Python】Django的优势与特点:为什么选择它作为Web开发框架
- Django是一个高效、健壮、易于扩展的Python Web开发框架。自从2005年问世以来,Django已经成为了很多企业级应用领域的首选框架。那么,Django为什么如此受欢迎呢?这篇文章将会深入分析Django的优势和特点,并为大家提供一些具体的代码示例。一、Django的优势易于上手Django是一个非常易于使用的框架。它提供了一个简单并易于理解的架构。因此,即使是初学者也能够快速掌握Django的基本知识。Django的API文档也非常完整,可以帮助开发者更快地学习。自带Web服务器D
- 【Python】Python程序用于按列对2D数组进行排序
- 当声明二维数组或二维数组时,它被视为矩阵。所以,我们知道矩阵由行和列组成。按升序或降序对属于矩阵特定列的元素进行排序的过程称为跨列对 2D 数组进行排序。让我们考虑一个算法和一个输入输出场景,以了解这个概念的确切应用。输入输出场景考虑一个二维数组。arr = [[ 7, 9, 5, 7 ], [9, 5, 9, 4], [2, 7, 8,&nbs
- 【Python】提升代码注释效率的神奇工具:让PyCharm成为您的首选
- PyCharm注释神器:让代码注释变得轻松又高效导语:代码注释是程序开发中不可或缺的一部分,无论是为了方便代码阅读、协作开发,还是为了方便后续的代码维护与调试。而在Python开发中,PyCharm注释神器则为我们带来了便捷而高效的代码注释体验。本文将为大家详细介绍PyCharm注释神器的功能和使用方法,并结合具体的代码示例进行演示。一、PyCharm注释神器的功能PyCharm是一款功能强大的Python集成开发环境,其内置的注释功能使得我们可以轻松添加和管理代码注释。以下是PyCharm注释