selenium+phantomjs绕过接口加密

我们为什么需要selenium

之前我们讲解了 Ajax 的分析方法,利用 Ajax 接口我们可以非常方便地完成数据的爬取。只要我们能找到 Ajax 接口的规律,就可以通过某些参数构造出对应的的请求,数据自然就能被轻松爬取到。

但是,在很多情况下,Ajax 请求的接口通常会包含加密的参数,如 token、sign 等。

由于接口的请求加上了 token 参数,如果不深入分析并找到 token 的构造逻辑,我们是难以直接模拟这些 Ajax 请求的。

解决方法:

  1. 一种是深挖其中的逻辑,把其中 token 的构造逻辑完全找出来,再用 Python 复现,构造 Ajax 请求;
  2. 另外一种方法就是直接通过模拟浏览器的方式,绕过这个过程。因为在浏览器里面我们是可以看到这个数据的,如果能直接把看到的数据爬取下来,当然也就能获取对应的信息了。

由于第 1 种方法难度较高,在这里我们就先介绍第 2 种方法,模拟浏览器爬取。

selenium是什么

Selenium 是一个自动化测试工具,利用它可以驱动浏览器执行特定的动作,如点击、下拉等操作,同时还可以获取浏览器当前呈现的页面源代码,做到可见即可爬。对于一些使用 JavaScript 动态渲染的页面来说,此种抓取方式非常有效。本课时就让我们来感受一下它的强大之处吧。

大家经常听说的是selenium加PhantomJS

selenium是操作浏览器的软件包,PhantomJS是特殊浏览器,不显示任何页面,被称为无头浏览器,这样可以运行的更快,但是该浏览器已经不再更新,属于半淘汰品了。因为谷歌59以上版本已经支持无头模式了

import time

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service options = webdriver.ChromeOptions()
# 设置无头模式
# options.add_argument('--headless') # selenium新版本: 将谷歌驱动网址用service包裹一下
service = Service('D:\extention\spider\day4\chormedriver\chromedriver-win64\chromedriver.exe')
# 驱动
driver = webdriver.Chrome(service=service, options=options)
# 访问网址
driver.get('https://baidu.com')
# 等待30秒
time.sleep(30)

准备工作

以 Chrome 为例来讲解 Selenium 的用法。在开始之前,请确保已经正确安装好了 Chrome 浏览器并配置好了 ChromeDriver。另外,还需要正确安装好 Python 的 Selenium 库。

驱动下载地址: https://googlechromelabs.github.io/chrome-for-testing/#canary
安装selenium: pip install selenium

基本使用

import time

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
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 options = webdriver.ChromeOptions()
# 设置无头模式
# options.add_argument('--headless') # selenium新版本: 将谷歌驱动网址用service包裹一下
service = Service('D:\extention\spider\day4\chormedriver\chromedriver-win64\chromedriver.exe')
# 驱动
browser = webdriver.Chrome(service=service, options=options)
try:
# 访问网址
browser.get('https://baidu.com')
# 获取输入框
input = browser.find_element('xpath', "//*[@id='kw']")
# 输入python
input.send_keys('python')
# 点击确定
input.send_keys(Keys.ENTER)
# 智能等待
wait = WebDriverWait(browser, 10)
# 直到某个元素出现
wait.until(EC.presence_of_element_located((By.XPATH, '//*[@id="content_left"]')))
print(f"网页url: {browser.current_url}")
print(f"cookies: {browser.get_cookies()}")
print(f"网页源代码: {browser.page_source}")
finally:
browser.close()

声明浏览器对象

Selenium 支持非常多的浏览器,如 Chrome、Firefox、Edge 等,还有 Android、BlackBerry 等手机端的浏览器。

此外,我们可以用如下方式进行初始化:

from selenium import webdriver
browser = webdriver.Chrome()
browser = webdriver.Firefox()
browser = webdriver.Edge()
browser = webdriver.Safari()

这样就完成了浏览器对象的初始化并将其赋值为 browser 对象。接下来,我们要做的就是调用 browser 对象,让其执行各个动作以模拟浏览器操作。

访问页面

我们可以用 get 方法来请求网页,只需要把参数传入链接 URL 即可。比如,这里用 get 方法访问淘宝,然后打印出源代码,代码如下

from selenium import webdriver
browser = webdriver.Chrome()
browser.get('https://www.taobao.com')
print(browser.page_source)
browser.close()

运行后会弹出 Chrome 浏览器并且自动访问淘宝,然后控制台会输出淘宝页面的源代码,随后浏览器关闭。

通过这几行简单的代码,我们就可以驱动浏览器并获取网页源码,非常便捷。

查找节点

单个节点

Selenium 提供了 find_element 这个通用方法,它需要传入两个参数:查找方式 By 和值。

By.ID
By.XPATH
By.TAG_NAME: 标签名称
By.CLASS_NAME
By.CSS_SELECTOR: CSS选择器
By.LINK_TEXT: 精确查询,a标签中文字
By.PARTIAL_LINK_TEXT: 模糊查询,a标签中文字

多个节点

Selenium 提供了 find_elements这个通用方法,它需要传入两个参数:查找方式 By 和值。

返回:一个包含 多个WebElement对象的 列表

节点交互

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

更多的操作可以参见官方文档的交互动作介绍 :http://selenium-python.readthedocs.io/api.html#module-selenium.webdriver.remote.webelement。

动作链

在上面的实例中,一些交互动作都是针对某个节点执行的。比如,对于输入框,我们调用它的输入文字和清空文字方法;对于按钮,我们调用它的点击方法。其实,还有另外一些操作,它们没有特定的执行对象,比如鼠标拖拽、键盘按键等,这些动作用另一种方式来执行,那就是动作链。

比如,现在我要实现一个节点的拖拽操作,将某个节点从一处拖拽到另外一处,可以这样实现:

from selenium import webdriver
from selenium.webdriver import ActionChains
browser = webdriver.Chrome()
url = 'http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable'
browser.get(url)
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()

执行JavaScript

Selenium API 并没有提供实现某些操作的方法,比如,下拉进度条。但它可以直接模拟运行 JavaScript,此时使用 execute_script 方法即可实现,代码如下:

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

切换 Frame

我们知道网页中有一种节点叫作 iframe,也就是子 Frame,相当于页面的子页面,它的结构和外部网页的结构完全一致。Selenium 打开页面后,默认是在父级 Frame 里面操作,而此时如果页面中还有子 Frame,Selenium 是不能获取到子 Frame 里面的节点的。这时就需要使用 switch_to.frame 方法来切换 Frame。示例如下:

登录qq空间小案例:

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from multiprocessing import Pool dr = webdriver.Chrome(r'D:\an\Lib\site-packages\chromedriver.exe')
dr.get('https://qzone.qq.com/')
dr.switch_to.frame('login_frame')
dr.find_element(By.PARTIAL_LINK_TEXT,'密码登录').click()
dr.find_element(By.ID,'u').send_keys('80713767')
dr.find_element(By.ID,'p').send_keys('1234567')
dr.find_element(By.ID,'login_button').click()

前进后退

平常我们使用浏览器时都有前进和后退功能,Selenium 也可以完成这个操作,它使用 back 方法后退,使用 forward 方法前进。示例如下:

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

Cookies

使用 Selenium,还可以方便地对 Cookies 进行操作,例如获取、添加、删除 Cookies 等。示例如下:

from selenium import webdriver
browser = webdriver.Chrome()
browser.get('https://www.zhihu.com/explore')
print(browser.get_cookies())
browser.add_cookie({'name': 'name', 'domain': 'www.zhihu.com', 'value': 'germey'})
print(browser.get_cookies())
browser.delete_all_cookies()
print(browser.get_cookies())

选项卡管理

在访问网页的时候,我们通常会开启多个选项卡。在 Selenium 中,我们也可以对选项卡进行操作。示例如下:

import time
from selenium import webdriver
browser = 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(1)
browser.switch_to.window(browser.window_handles[0])
browser.get('https://python.org')

异常处理

在使用 Selenium 的过程中,难免会遇到一些异常,例如超时、节点未找到等错误,一旦出现此类错误,程序便不会继续运行了。这里我们可以使用 try except 语句来捕获各种异常。

示例如下:

from selenium import webdriver
from selenium.common.exceptions import TimeoutException,
NoSuchElementException
browser = webdriver.Chrome()
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()

案例:振坤行商品信息

振坤行分析:

  • 不登陆,只允许搜索一次,搜索第二次就会封禁IP,此IP以后每次搜索则会跳转登陆页面
  • 登录必须企业认证

以下是假如不登陆可以搜索无限次的情况下,进行爬取商品信息的代码(学习用法即可)

下面代码为获取振坤行商品信息

import time

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
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
from multiprocessing import Pool def get_data(key):
global browser
try:
options = webdriver.ChromeOptions()
# selenium新版本: 将谷歌驱动网址用service包裹一下
service = Service('D:\extention\spider\day4\chormedriver\chromedriver-win64\chromedriver.exe')
# 句柄
browser = webdriver.Chrome(service=service, options=options) # 访问网址
browser.get('https://www.zkh.com/')
# 最大化浏览器窗口
browser.maximize_window()
# 智能等待
wait = WebDriverWait(browser, 10)
# 直到搜索框出现
wait.until(EC.presence_of_element_located((By.CLASS_NAME, 'form-key'))) # 输入关键词key
browser.find_element(By.CLASS_NAME, 'form-key').send_keys(key)
# 输入回车
browser.find_element(By.CLASS_NAME, 'form-key').send_keys(Keys.ENTER)
# 爬取商品价格信息
while True:
page = 1
# 等待搜索结果出来
time.sleep(0.5)
# 智能等待商品元素出现
# 完整性和唯一性: 类名应该是目标元素的完整类名,并且最好是唯一的。
# WebDriverWait(browser, 10).until(EC.presence_of_all_elements_located((By.XPATH, "//div[@class='total-main-sku-wapper']/div[@class='goods-list-outer']/div[@class='goods-item-box-new clearfix flow-side-goods-item-inner']/div[@class='goods-item-wrap-new clearfix common-item-wrap']")))
# 右侧滚动条拉到最后
for i in range(6):
browser.execute_script('window.scrollTo(0, document.body.scrollHeight)')
# 等待浏览器拉到底部
time.sleep(1)
print(1111)
# 智能等待最后一个商品元素出现
WebDriverWait(browser, 10).until(EC.presence_of_element_located(
(By.XPATH, "//div[@class='goods-item-wrap-new clearfix common-item-wrap'][50]"))) print(f"-------------------当前{key},第{page}页")
divs = browser.find_elements(By.XPATH, "//div[@class='goods-item-wrap-new clearfix common-item-wrap']")
for div in divs:
integer = div.find_element(By.XPATH, "//span[@class='integer xh-highlight']").text
decimal = div.find_element(By.XPATH, "//span[@class='decimal']").text
price = integer + decimal
print(price) # 获取最大页
max_page = browser.find_element(By.XPATH, "//button[@class='numberbtn'][6]").text
if page == max_page:
break
# 点击下一页
page += 1
browser.find_element(By.XPATH, "//button[@class='nextbtn']").click()
finally:
browser.close() if __name__ == '__main__':
get_data("口罩")

多进程优化

if __name__ == '__main__':
# get_data("口罩")
pool = Pool(3)
try:
for kw in ['雨衣', '螺丝', '口罩']:
pool.apply_async(get_data, args=(i,))
except KeyboardInterrupt:
pool.terminate()
finally:
pool.close()
pool.join()

如何加代理?

首先你得有代理,可以买小象代理或者芝麻代理

proxy = 'http://{}'.format('183.165.224.223:4231')
proxies = {
'http': proxy,
'https': proxy,
} option = webdriver.ChromeOptions()
option.add_argument('--proxy-server={}'.format(proxy))
dr = webdriver.Chrome(r'D:\an\Lib\site-packages\chromedriver.exe',options=option)
dr.get('https://2023.ip138.com/')

如何规避监测风险?

网站会根据环境变量检查你是否为selenium,所以我们要伪装环境变量,消除指纹

stealth.min.js就是一系列修改环境变量的方法

with open('stealth.min.js') as f:
js = f.read()
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
"source": js
})

这里提供一个检测浏览器环境的网站给你参考

https://bot.sannysoft.com/

stealth.min.js安装方法:

  1. 安装node.js环境

  2. 运行命令即可获得此文件

    npx extract-stealth-evasions

selenium里的xpath和正常xpath区别

  • 正常:

    • 获得文字信息: "//a/text()"
    • 获取属性: "//a/@href"
  • selenium
    • 获得文字信息: "//a".text
    • 获取属性: "a".get_attribute('href')

弊端

  • 登录需要滑块验证,selenium无法爬取
  • 登录需要手机号验证码,selenium无法爬取

适用场景

  • 不登陆的数据爬取
  • 根据用户名和密码进行登录的网站的 数据爬取

更多精致内容

利用Selenium和PhantomJS绕过接口加密的技术探索与实践的更多相关文章

  1. 针对源代码和检查元素不一致的网页爬虫——利用Selenium、PhantomJS、bs4爬取12306的列车途径站信息

    整个程序的核心难点在于上次豆瓣爬虫针对的是静态网页,源代码和检查元素内容相同:而在12306的查找搜索过程中,其网页发生变化(出现了查找到的数据),这个过程是动态的,使得我们在审查元素中能一一对应看到 ...

  2. .net core 利用Selenium和PhantomJS后台生成EChart图片

    1.引用 NuGet安装: Selenium.Support Selenium.WebDriver Selenium.WebDriver.PhantomJS.CrossPlatform  (分布Lin ...

  3. 前端开发工程师 - 05.产品前端架构 - 协作流程 & 接口设计 & 版本管理 & 技术选型 &开发实践

    05.产品前端架构 第1章--协作流程 WEB系统 角色定义 协作流程 职责说明 第2章--接口设计 概述 接口规范 规范应用 本地开发 第3章--版本管理 见 Java开发工程师(Web方向) - ...

  4. 利用JMeter的beanshell进行接口的加密处理

    最近项目中在做http协议的接口测试,其中接口请求报文数据有个字段值需要用到加密后的签名,即出于网络传输过程中,对数据安全的考虑,要对请求的数据进行特定的处理(加密),再进行请求. 刚开始由于项目赶进 ...

  5. Python爬虫实战八之利用Selenium抓取淘宝匿名旺旺

    更新 其实本文的初衷是为了获取淘宝的非匿名旺旺,在淘宝详情页的最下方有相关评论,含有非匿名旺旺号,快一年了淘宝都没有修复这个. 可就在今天,淘宝把所有的账号设置成了匿名显示,SO,获取非匿名旺旺号已经 ...

  6. requests利用selenium,代理Ip,云打码,验证码抠图操作 爬取搜狗微信公众号内容

    爬取思路,爬取搜狗微信公众号内容,爬取第一层url时请求太快出现验证码,我这里用的蘑菇云代理,并在程序中我判断什么情况下是否+代理,做到合理运用代理ip.爬取第二层url时验证码出现次数更严重(和第一 ...

  7. PYTHON 爬虫笔记十:利用selenium+PyQuery实现淘宝美食数据搜集并保存至MongeDB(实战项目三)

    利用selenium+PyQuery实现淘宝美食数据搜集并保存至MongeDB 目标站点分析 淘宝页面信息很复杂的,含有各种请求参数和加密参数,如果直接请求或者分析Ajax请求的话会很繁琐.所以我们可 ...

  8. 利用Selenium和Browsermob批量嗅探下载Bilibili网站视频

    Rerence: http://www.liuhao.me/2016/09/20/selenium_browsermob_sniff_bilibili_video/ 日常生活中,用电脑看视频是非常频繁 ...

  9. asp.net mvc webapi 实用的接口加密方法

    在很多项目中,因为webapi是对外开放的,这个时候,我们就要得考虑接口交换数据的安全性. 安全机制也比较多,如andriod与webapi 交换数据的时候,可以走双向证书方法,但是开发成本比较大, ...

  10. Selenium+Chrome/phantomJS模拟浏览器爬取淘宝商品信息

    #使用selenium+Carome/phantomJS模拟浏览器爬取淘宝商品信息 # 思路: # 第一步:利用selenium驱动浏览器,搜索商品信息,得到商品列表 # 第二步:分析商品页数,驱动浏 ...

随机推荐

  1. JDK源码阅读-------自学笔记(二十六)(java.util.Map 自定义讲解)

    一.简介 Map就是用来存储"键(key)-值(value)"对的. 通过键寻找value,所以键不能重复. 数组的本质也是一种键值对,区别就是索引一般是数字,而Map的Key可以 ...

  2. 2024-05-15:用go语言,考虑一个整数 k 和一个整数 x。 对于一个数字 num, 在其二进制表示中, 从最低有效位开始, 我们计算在 x,2x,3x 等位置处设定位的数量来确定其价值。

    2024-05-15:用go语言,考虑一个整数 k 和一个整数 x. 对于一个数字 num, 在其二进制表示中, 从最低有效位开始, 我们计算在 x,2x,3x 等位置处设定位的数量来确定其价值. 举 ...

  3. Axure和墨刀——两款原型设计工具介绍

    Axure与墨刀是两款在原型设计领域广受欢迎的工具,各具特点和优势: Axure: Axure RP是一款功能强大的原型设计工具,广泛应用于交互设计和用户体验设计领域.它提供了丰富的交互元素库.高保真 ...

  4. Chart.js (v2.9.4)概要介绍

    chart.js是一个非常优秀的开源图表插件,扩展非常灵活,同时也提供了大量的钩子函数,给与用户添加自定义插件,实现个性化的需求. 具体的优势特点,这里不详述,网上大把资料,现开始正式深入了解这个插件 ...

  5. C# winfrom 局域网版多人成语接龙(二)

    功能基本上是完成了,要两个人完才好玩,目前 倒计时,每组游戏玩家数量这些控制变量,都是写死再代码里的,等以后想改的时候再改,这个项目核心的功能算是实现了,但还可以扩展,比如记录一下用户的游戏数据,答对 ...

  6. Django模型层的QuerySet对象

    def index(request): # 查询数据,返回QuerySet对象books books=Book.objects.filter(id__gte=1) # 打印books, 是一个Quer ...

  7. 【分享】FFmpeg桌面神器,集多种功能于一身,超级好用,不用命令行!

    在媒体处理上,市面上有很多软件可以选择,在众多软件里面 FFmpeg 是比较独特的一款,直接选择 FFmpeg 硬核命令行工具的朋友相对较少,大多时候只是被集成在各样的软件里,如果单独拿出来使用,不少 ...

  8. 虚拟机ping不通物理机 PING 192.168.10.1 (192.168.10.1) 56(84) bytes of data.

    准备做samba服务配置的时候 ping 192.168.10.1 (物理机地址) PING 192.168.10.1 (192.168.10.1) 56(84) bytes of data. 查看自 ...

  9. 10位,13位时间戳转为C#.NET格式时间 DateTime

    10位,13位时间戳转为C#.NET格式时间 DateTime - public static DateTime ToDateTime( string timestamp) { var tz = Ti ...

  10. 《Android开发卷——程序自动登录》

    Android程序的自动登录功能 因为是公司的项目,所以这里不方便说出项目名称,这里就说我在做这个项目中用到的一些功能或者叫技术问题吧. 咱们经常用的Android程序中有一个情况,就是当你第一次注册 ...