爬虫 | (3)selenium的应用

戴冠英

爬虫|2023-8-14|最后更新: 2023-9-13|

1.作用

selenium可以模拟人操作浏览器网页。有的网站有很强的反爬措施,我们就用selenium模仿人类浏览网页的样子,然后把得到的东西记录下来。也可以自动化办公,例如每天都要打开网页进行一些无意义的工作,这些可以使用selenium自动进行。

2.下载

第一步,打开Chrome,查看一下浏览器版本。
可以在网址处输入chrome://version/。即可查看版本,如下图所示:
notion image
第二步,下载合适的ChromeDriver
下载链接如下:
这里有两个大坑:
1)版本无法完全对应
我的版本是110.0.5481.178 ,但在下载网站却无法找到,最后我看到一句话:If you are using Chrome version 110, please download ChromeDriver 110.0.5481.77。所以无需完全对应,注意看网站的说明吧!
2)没有win-64版本
了解了一下,win-64是兼容win-32的,所以下载win-32的ChromeDriver即可。
第三步,下载到合适的地方
把ChromeDriver 下载到合适的地方
在cmd运行where python,可以得到如下信息:
notion image
你把它安装到..\anaconda3\Script文件夹下即可。
第四步,pip install selenium
注意,如果你的google动不动就报错,说版本不合适,那么可能是google自动更新了,参考这个,禁掉自动更新
然后,在这里下载合适的google版本

3.语法

3.1 启动

3.2 参数配置

这个东西就像你让人去打仗一样,得给人穿点铠甲,不能让人不穿衣服直接上吧?不穿衣服当然也能打,但有铠甲更能打。 基本操作如下:
具体举几个例子:

3.3 定位节点

selenium的思路就是你定位到某个节点,然后你可以进行鼠标操作、键盘操作、获取源代码以及一些其他的操作。
于是乎你首先得定位节点,市场上常见的说法是,可以用一下八个指令定位节点。
方法
说明
find_element_by_id()
通过 id 属性值定位
find_element_by_name()
通过 name 属性值定位
find_element_by_class_name()
通过 class 属性值定位
find_element_by_tag_name()
通过 tag 标签名定位
find_element_by_link_text()
通过<a>标签内文本定位,即精准定位。
find_element_by_partial_link_text()
通过<a>标签内部分文本定位,即模糊定位。
find_element_by_xpath()
通过 xpath 表达式定位
find_element_by_css_selector()
通过 css 选择器定位
但是,这些方法实际上已经过时了,现在使用的是find_element(),具体使用方法如下:
我们操作百度做个示范:
notion image
百度的输入框html是这样
搜索框的代码是这样
那么我们定位输入框和搜索框的代码如下:
我习惯用xpath,当然也可以用其他方法获得定位,都是完全一样的。

3.4 基本操作

那么,获取定位后又是如何?接下来就是对鼠标、键盘这些的操作了!

3.4.1 浏览器操作

3.4.2 键盘操作

键盘的基本使用方法有什么呢?输入、删除、复制、粘贴、回车等等……

3.4.3 鼠标操作

鼠标能有什么操作呢?移动、点击、双击、右键……

3.4.4 基操小案例

3.5 selenium实战:爬取京东商品信息

这次我们爬京东的商品信息,包括名称、价格、链接和图片,开搞。

3.5.1观察需求

我们做什么事情都要想清楚需求是什么哈!我们爬一下“Python语言程序设计”的前两页所有商品,假设我们是人,不是机器(好像本来就是):
notion image
那么我们先在搜索框输入“Python语言程序设计”,随后点击搜索按钮搜索。
notion image
进入后,我们查看一下需要的信息保存在哪里
商品名:
notion image
价格:
notion image
图片:
notion image
总之,可以很快得到商品名、价格、图片、链接的源码。随后我们爬虫会利用到这一部分。
大概是这样
同时,京东这个网页需要下滑到底部才能加载所有的商品,因此我们下滑到底部后才进行爬虫。这个的代码写法如下(需要执行JS):

3.5.2 配置

如果你想要的话,可以使用无头浏览器,避免打开Chrome,代码如下:
但我是故意不加的,因为这个是小批量的任务,只有保留它,才知道你写的是什么东西(这样才知道你吃的是大肠!)。

3.5.3 搜索商品

就是输入然后搜索嘛

3.5.4 获取数据

这部分的思路是,你搜索后,滑到底部,然后把需要的东西都爬下来。其中我们用到了之前没有介绍的新方法get_attribute,这个的作用是获取元素信息。假设变量a如下:
那么a.get_attribute()就是https://www.baidu.com/

3.5.5 程序员必经之路——bug

我们通常图片都是存在src里面的,但这次跑出来却是None。
notion image
于是你去研究一下源代码,发现源代码是这样:
没问题啊!?
你发现旁边有几个奇怪的东西,data-lazy-img、source-data-lazy-img,于是你真的去百度了,发现盲点
懒加载
功能:用到了再加载,不然就不加载,这样比较不会卡。你平时浏览网站时,往下滑图片本来是白白的啥都没有,过一会儿才显示出来,这就是懒加载。
原理:正常图片的HTML是这样的<img src = './图片.jpg'></img>,但懒加载时,他这里不写src,可能写其他东西,例如src2data-src等等。你用到的时候,会有一个JS把src恢复原状。你得去看看他原来是什么样的,才能爬下来。
但是你为什么用审查元素看,代码是下面这样呢?
这是因为你审查元素里面的是JS渲染过的,你得去ctrl+U去看源代码,原汁原味。
看了一下,源代码是这样:
好啊,原来是data-lazy-img,于是你改用这个爬取,成功拿下!

3.5.6 完整代码

end

3.6 selenium小知识

3.6.1 webdriver的三种等待

今天我写代码,总觉得心里不太舒服——等太久了。思考了一下,觉得time.sleep()有改进的空间,于是发现了这个知识——webdriver的三种等待。
当使用Selenium自动化测试时,由于网页加载速度、网站性能等原因,我们需要在某些情况下进行等待。Selenium提供了三种等待方式:隐式等待、显式等待和强制等待。
  1. 隐式等待(Implicit Wait):
隐式等待是通过设置一个全局的等待时间,在这个时间内,如果页面元素没有被找到,则会一直等待并轮询页面,直到找到元素或达到设定的最大等待时间。例如,如果将隐式等待时间设置为10秒钟,则在查找页面元素时,每次等待的最长时间不超过10秒钟。
隐式等待可以通过 driver.implicitly_wait() 方法来设置,它会应用到所有的 find_element_by_*find_elements_by_* 方法上。
示例代码:
  1. 显式等待(Explicit Wait):
显式等待是指在特定条件下等待,直到满足条件或者超时之后抛出异常。与隐式等待不同,它只会对某个特定的元素或条件进行等待,而不是全局等待整个页面。
Selenium提供了 WebDriverWait 类来实现显式等待,需要传入一个要等待的条件和最长等待时间,如果在这个时间范围内条件满足,则返回条件相关的对象(如WebElement),否则抛出异常。
示例代码:
  1. 强制等待(Sleep):
强制等待是指使用程序语言提供的time.sleep()方法在执行期间暂停一段时间,以固定时间等待。这种方式的缺点是不管目标元素是否已经加载完成,都会等待固定的时间,可能会造成等待时间过长或者无法等待到目标元素的情况。
示例代码:
综上所述,隐式等待适用于全局等待,而显式等待更加灵活,可以针对特定元素或条件进行等待;而强制等待则不太推荐使用,因为它可能会造成测试效率低下。具体使用哪种等待方式,需要根据具体场景和需求来选择。

3.6.2 隐藏身份

这行Python代码使用了Selenium的execute_cdp_cmd方法执行了一条Chrome DevTools协议(CDP)命令,用于在新文档加载时向页面注入一个JavaScript脚本。具体来说,这个JavaScript脚本会覆盖浏览器中的navigator.webdriver属性,使其返回undefined,以隐藏浏览器自动化工具(如Selenium)的存在。
通常情况下,当使用Selenium等自动化工具控制浏览器时,浏览器会检测到webdriver属性的存在,并采取一些防范措施,例如禁止访问某些网站或显示人机验证等。因此,通过覆盖navigator.webdriver属性可以避免这些限制。
此外,Page.addScriptToEvaluateOnNewDocument是一个CDP命令,用于在每次新文档加载时将指定的脚本注入到页面中。在这里,我们使用它来注入JavaScript脚本,并覆盖掉navigator.webdriver属性。
notion image

3.6.3 使用selenium接管已经打开的浏览器

今天爬了一个网页,这个网页比较特殊,要求登录,没有登陆的话就不会显示任何信息😠
fine,那我们就登录吧。我想到的方法是,先打开一个chrome,登录后用这个chrome爬取数据。操作方法如下
先进入chrome所在的文件夹,设置端口打开chrome
这个端口9322是可以调的,随便写一个就行。
然后给selenium.chrome()添加option
那么selenium就只会操作你已经打开的这个chrome了。