Selenium复盘

1. selenium概述

我们在抓取一些普通网页的时候requests基本上是可以满足的. 但是, 如果遇到一些特殊的网站. 它的数据是经过加密的. 但是呢, 浏览器却能够正常显示出来. 那我们通过requests抓取到的内容可能就不是我们想要的结果了. 例如,

image-20210125173604985

电影票房数据. 在浏览器上看的时候是正常的. 那么按照之前的逻辑. 我们只需要看看数据是通过哪个请求拿到的就可以进行模拟请求了. 但是!

image-20210125173719899

数据找到了. 接着看”预览”吧

image-20210125173744598

我们发现这个数据是经过加密算法的. 这就头疼了. 直接通过requests拿到这些内容必须要解密才能看到真实数据. 但是该网站采用的加密方式又不是那么容易破解. 此时, 各位想想如果我能通过我的程序直接调用浏览器. 让浏览器去解密这些内容. 我们直接拿结果岂不妙哉. 哎~这就引出了我们本章要重点讲解的selenium了. 它可以完美解决上述问题

简单介绍一下selenium, 它本身是一个自动化测试的工具. 可以启动一个全新的浏览器.并从浏览器中提取到你想要的内容. 随着各种网站的反爬机制的出现. selenium越来越受到各位爬sir的喜爱. selenium最大的缺点其实就一个, 慢! 你想啊. 他要启动一个第三方的软件(浏览器), 并且还要等待浏览器把数据渲染完毕. 这个过程必然是很耗时的. 所以它慢.

接下来, 我们来聊聊selenium如何安装和使用.

就像其他第三方库一样, selenium直接用pip就可以安装了

1
pip install selenium

但是呢, 它与其他库不同的地方是他要启动你电脑上的浏览器, 这就需要一个驱动程序来辅助.

chrome驱动地址:https://npm.taobao.org/mirrors/chromedriver

这里推荐用chrome浏览器. 其他浏览器的驱动请自行百度.

image-20210125174618013

image-20210125174658971

根据你电脑的不同自行选择吧. win64选win32即可.

然后关键的来了. 把你下载的浏览器驱动放在程序所在的文件夹. 或者放到python解释器所在的文件夹. 两种二选其一.

image-20210125174915946

或者

image-20210125175328245

OK~ 前期准备工作完毕. 上代码看看, selenium是个什么鬼

1
2
3
4
5
6
7
8
9
from selenium.webdriver import Chrome  # 导入谷歌浏览器的类


# 创建浏览器对象
web = Chrome(executable_path="chromedriver") # 如果你的浏览器驱动放在了项目里.
# web = Chrome() # 如果你的浏览器驱动放在了解释器文件夹

web.get("http://www.baidu.com") # 输入网址
print(web.title) # 打印title

运行一下你会发现神奇的事情发生了. 浏览器自动打开了. 并且输入了网址. 也能拿到网页上的title标题.

image-20210125175906255

cool~

2. selenium各种神奇操作

selenium不但可以打开浏览器. 还可以对浏览器各种操作. 比如, 点击, 查找. 都可以.

我们直接上案例. 抓取拉钩网招聘python工程师的招聘信息

2.1 准备工作

1
2
3
4
5
6
from selenium.webdriver import Chrome

web = Chrome()

web.get("http://lagou.com")

image-20210125180302833

###2.2 点击-全国按钮

想要点击这个按钮. 我们需要先定位到这个按钮. 然后再点击

selenium想要定位某个元素. 太简单了.

image-20210125180558103

有了xpath是不是明白了些什么.

1
2
3
4
5
6
7
8
from selenium.webdriver import Chrome

web = Chrome()

web.get("http://lagou.com")
btn = web.find_element_by_xpath('//*[@id="changeCityBox"]/ul/li[1]/a') # 找到全国按钮
btn.click() # 点击这个按钮

image-20210125180745412

舒服!

2.3 搜索python

人的过程: 找到文本框输入”python”, 点击”搜索”按钮.

机器的过程: 找到文本框输入”python”, 点击”搜索”按钮.

发现没, 用selenium最爽的地方就是这里. 人是怎么操作的. 机器就怎么操作. 爽到极点

1
2
3
# 找到文本框输入python, 点击搜索按钮
web.find_element_by_xpath('//*[@id="search_input"]').send_keys("python")
web.find_element_by_xpath('//*[@id="search_button"]').click()

send_keys() 这里要说一下. 如果我们给出的是一个字符串. 就是输入文本. 但是, 如果给出的是一个键盘指令, 那就按下键盘. 比如, 我想要按回车按钮. 就是这样的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from selenium.webdriver import Chrome
from selenium.webdriver.common.keys import Keys
import time
web = Chrome()

web.get("http://lagou.com")
btn = web.find_element_by_xpath('//*[@id="changeCityBox"]/ul/li[1]/a') # 找到全国按钮
btn.click() # 点击这个按钮

time.sleep(2) # 让浏览器反应一会儿

# 找到文本框输入python, 点击搜索按钮
web.find_element_by_xpath('//*[@id="search_input"]').send_keys("python", Keys.ENTER)
# web.find_element_by_xpath('//*[@id="search_button"]').click()

image-20210125181431480

keys里几乎包含了我们需要的所有特殊按键

2.4 提取招聘信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from selenium.webdriver import Chrome
from selenium.webdriver.common.keys import Keys
import time
web = Chrome()

web.get("http://lagou.com")
btn = web.find_element_by_xpath('//*[@id="changeCityBox"]/ul/li[1]/a') # 找到全国按钮
btn.click() # 点击这个按钮

time.sleep(2) # 让浏览器反应一会儿

# 找到文本框输入python, 点击搜索按钮
web.find_element_by_xpath('//*[@id="search_input"]').send_keys("python", Keys.ENTER)
time.sleep(1)
# web.find_element_by_xpath('//*[@id="search_button"]').click()


ls = web.find_elements_by_xpath('//*[@id="s_position_list"]/ul/li') # 一次性提取多个元素用elements
for item in ls:
name = item.find_element_by_xpath('./div[1]/div[1]/div[1]/a/h3').text
addr = item.find_element_by_xpath('./div[1]/div[2]/div[1]/a').text
print(name, addr)
# 其他内容你自己琢磨吧

发现没有, selenium几乎是傻瓜式的存在.

##3. 处理iframe, 多窗口调度

我们书接上回. 上回说到我们已经可以通过selenium拿到拉钩网的招聘信息了. 但是, 信息不够全面. 我们希望得到的不仅仅是一个岗位名称和公司名称, 我更想知道更加详细的职位描述以及岗位要求.

image-20210126172555841

此时问题就来了. 我们可以在搜索页面点击进入到这个详情页. 然后就可以看到想要的职位描述了. 但是, 这时就涉及到如何从一个窗口转向另一个窗口了(切换选项卡).

首先, 我们先通过selenium定位到搜索页上的职位超链接.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from selenium.webdriver import Chrome
from selenium.webdriver.common.keys import Keys
import time

web = Chrome()
web.get("http://www.lagou.com")

web.find_element_by_xpath('//*[@id="changeCityBox"]/ul/li[1]/a').click()
time.sleep(2)
web.find_element_by_xpath('//*[@id="search_input"]').send_keys("python", Keys.ENTER)
time.sleep(2)
# 不要红包(拉钩的活动. 时有时无)
web.find_element_by_xpath('/html/body/div[8]/div/div[2]').click()
# 点击职位
web.find_element_by_xpath('//*[@id="s_position_list"]/ul/li[1]/div[1]/div[1]/div[1]/a/h3').click()
time.sleep(1)

正片开始

image-20210126175042619

注意! 我们看到的是新窗口的内容, 但是在selenium的视角里, 窗口依然停留在刚才那个窗口. 此时, 必须要将窗口调整到最新的窗口上才可以.

1
2
3
4
# 正片开始
web.switch_to.window(web.window_handles[-1]) # 跳转到最后一个窗口
job_detail = web.find_element_by_xpath('//*[@id="job_detail"]/dd[2]').text
print(job_detail)

接下来我们来看另一种操作.

之前我们抓取过一个网站. 里面把视频内容嵌套在一个iframe中. 那如果换成了selenium应该如何应对呢?

image-20210709175412897

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from selenium.webdriver import Chrome

web = Chrome()
web.get("http://www.wbdy.tv/play/42491_1_1.html")

# 找到那个iframe
iframe = web.find_element_by_xpath('//iframe[@id="mplay"]')

web.switch_to.frame(iframe)
val = web.find_element_by_xpath('//input[@class="dplayer-comment-input"]').get_attribute("placeholder")
print(val)

# 调整回上层结构
web.switch_to.parent_frame()
xxx = web.find_element_by_xpath('/html/body/div[2]/div[3]/div[2]/div/div[2]/h2').text
print(xxx)

4. 无头浏览器

我们已经基本了解了selenium的基本使用了. 但是呢, 不知各位有没有发现, 每次打开浏览器的时间都比较长. 这就比较耗时了. 我们写的是爬虫程序. 目的是数据. 并不是想看网页. 那能不能让浏览器在后台跑呢? 答案是可以的.

咱直接上案例吧. 拿出最开始我们看到的那个网页. 抓取电影票房. 并且用正常的有浏览器窗口的方式来抓取. 然后再改成后台运行不就好了么

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from selenium.webdriver import Chrome
from selenium.webdriver.support.select import Select
from selenium.webdriver.chrome.options import Options


import time


opt = Options()
opt.add_argument("--headless")
opt.add_argument('--disable-gpu')
web = Chrome(options=opt)
web.get('https://www.endata.com.cn/BoxOffice/BO/Year/index.html')


# 切换select
sel = Select(web.find_element_by_xpath('//*[@id="OptionDate"]'))
for i in range(len(sel.options)):
sel.select_by_index(i) # 按照索引位置切换
time.sleep(1)
table = web.find_element_by_xpath('//*[@id="TableList"]/table')
print("===========================================")
print(table.text)