爬虫 — 自动化爬虫 Selenium

一、介绍

Selenium 爬取网页时,当前访问的 url 就是爬虫当中的目标 url,获取内容只要是页面上可见的,都可以爬取(可见即可爬)。

步骤

Selenium + 浏览器 + 浏览器驱动

1、导入

2、url(找动态 url,抓取到的数据是加密的)

3、获取内容,做解析

Selenium 是一个用于 Web 应用程序测试的工具,最初是为网站自动化测试而开发的,Selenium 可以直接运行在浏览器上,它支持所有主流的浏览器,可以接收指令,让浏览器自动加载页面,获取需要的数据,甚至页面截屏。

chromedriver 是一个驱动 Chrome 浏览器的驱动程序,使用它才可以驱动浏览器

针对不同的浏览器有不同的 driver,但 Chrome 的兼容性最好。

二、对比

Ajax:可以使用网页实现异步更新,可以在不重新加载整个网页的情况下,对网页的某部分进行更新。

1、获取 Ajax 数据的方式

  • 直接分析 Ajax 调用的接口,然后通过代码请求这个接口。

  • 使用 Selenium + chromedriver 模拟浏览器行为获取数据。

2、获取 Ajax 数据方式对比

方式优点缺点
找数据接口直接可以请求到数据,代码量少,性能高分析接口比较复杂,尤其通过 js 混淆的接口,容易被发现是爬虫
Selenium直接模拟浏览器行为,浏览器能请求到的,使用 Selenium 也能请求到代码量多,性能低

三、安装

1、驱动下载地址

下载 Chrome 驱动

下载 Firefox 驱动

2、安装 Selenium 第三方库(建议指定版本安装)

pip install selenium==4.0.0a1

3、安装驱动(Chrome 的兼容性最好,建议安装 chromedriver)

  • 先确定浏览器版本号

在这里插入图片描述

在这里插入图片描述

  • 打开谷歌驱动下载地址

在这里插入图片描述

  • 版本号前面三位对应上就可以,最后一位建议选择版本小的

在这里插入图片描述

  • 按照电脑的系统来选择下载(如果电脑是 windows-64 位,选 win32 就行)

在这里插入图片描述

  • 驱动下载完成之后,将文件进行解压,复制到 chromedriver.exe 到 Python 解释器目录下

终端输入命令:where python 可以查看 Python 的安装目录

四、简单使用

# 导入模块,加载驱动
from selenium import webdriver
# 内置库
import time

# 加载驱动
drive = webdriver.Chrome()

# 窗口最大化
drive.maximize_window()

# 加载网站
drive.get('https://www.baidu.com')

# 代码停3秒再运行
time.sleep(3)

# 关闭当前的窗口
# drive.close()  # 要打开多个窗口,关闭的是当前的窗口

# 退出驱动
drive.quit()  # 关闭所有窗口,退出浏览器

五、定位元素

# 导入模块,加载驱动
from selenium import webdriver
# 定位元素
from selenium.webdriver.common.by import By

# 加载驱动
driver = webdriver.Chrome()

# 窗口最大化
driver.maximize_window()

# 加载网站
driver.get('https://www.baidu.com')

1、By.ID

根据 id 来查找定位元素。

# find_element 找一个元素,find_elements 找多个
el = driver.find_element(By.ID, 'kw')
# 返回的是一个元素对象
print(el)

2、By.CLASS_NAME

通过 class 属性值定位某个元素。

el = driver.find_element(By.CLASS_NAME, 's_ipt')
# 返回的是一个元素对象
print(el)

3、By.NAME

通过 name 属性查找定位某个元素。

el = driver.find_element(By.NAME, 'wd')
# 返回的是一个元素对象
print(el)

4、By.TAG_NAM

通过标签定位元素。

input_tag = driver.find_elements(By.TAG_NAME, 'input')
# find_elements 定位元素,返回的数据类型是 list
print(input_tag)

5、By.XPATH

通过 xpath 语法定位元素。

el = driver.find_element(By.XPATH, '//input[@id="kw"]')
# 返回的是一个元素对象
print(el)

六、操作元素

1、在输入框输入内容并搜索

# 内置库
import time
# 导入模块,加载驱动
from selenium import webdriver
# 定位元素
from selenium.webdriver.common.by import By

# 加载驱动
driver = webdriver.Chrome()

# 窗口最大化
driver.maximize_window()

# 加载网站
driver.get('https://www.baidu.com')

# 定位到元素
el = driver.find_element(By.ID, 'kw')

# 元素输入框里面输入值
el.send_keys('唐僧')

# 等待2秒
time.sleep(2)

# 点击元素
driver.find_element(By.ID, 'su').click()

# 清空内容
el.clear()

2、打开网站搜索音乐并播放

# 内置库
import time
# 导入模块,加载驱动
from selenium import webdriver
# 定位元素
from selenium.webdriver.common.by import By
# 操作键盘
from selenium.webdriver.common.keys import Keys

# 加载驱动
driver = webdriver.Chrome()

# 窗口最大化
driver.maximize_window()

# 加载网站
driver.get('https://music.163.com/')

# 搜索内容
driver.find_element(By.ID, 'srch').send_keys('愿')

# 按回车键
driver.find_element(By.ID, 'srch').send_keys(Keys.ENTER)

# 等待2秒
time.sleep(2)

# 网页里面嵌套了一个网页,要进入该网页才会获取对应的数据
driver.switch_to.frame('g_iframe')

# 播放按钮
driver.find_element(By.ID, 'song_2010214999').click()

七、Cookie 操作

1、获取所有的 Cookie

cookies = driver.get_cookies()

2、根据 Cookie 的 name 获取 Cookie

value = driver.get_cookie(name)

3、删除某个 Cookie

driver.delete_cookie('key')

4、处理 Cookie

# 导入模块,加载驱动
from selenium import webdriver

# 加载驱动
driver = webdriver.Chrome()

# 窗口最大化
driver.maximize_window()

# 加载网站
driver.get('https://www.baidu.com')

# 获取百度的 cookie
cookies = driver.get_cookies()

# 返回的 list,列表里面嵌套的字典
print(cookies)

'''
通过程序拿到的 cookie 与页面的是不一致,还需要做处理
只需要里面的两个字段值,name 和 value
BAIDUID_BFESS=F875E52E04E65B3748D8FDDE2E25399E; ZFY=idY6KuND2T0e6ROY1txjofI8Nvn4lb6hXiw:BN2mgeaA:C
'''
for cookie in cookies:
    print(cookie['name']+'='+ cookie['value'])

5、案例

模拟登录 qq 空间

# 内置库
import time
# 导入模块,加载驱动
from selenium import webdriver
# 定位元素
from selenium.webdriver.common.by import By

# 加载驱动
driver = webdriver.Chrome()

# 最大化窗口
driver.maximize_window()

# 加载网站
driver.get('https://i.qq.com/')

# 切换 iframe
driver.switch_to.frame('login_frame')

# 等待2秒
time.sleep(2)

# 点击头像进行登录,获取登录之后的 cookie
driver.find_element(By.ID, 'img_out_1234567890').click()

# 等待2秒
time.sleep(2)

# 获取 cookie
cookies = driver.get_cookies()

# 打印出的数据为列表
# print(cookies)

# 获取的 cookie 需要处理
li = []
for cookie in cookies:
    # 只需要每一组字典里面的 name value
    li.append(cookie['name']+'='+cookie['value'])
    # print(cookie)

# 处理好的 cookie
cookie = '; '.join(li)
print(cookie)

# 导入库
import requests

# 确定 url, 静态加载的
url = 'https://user.qzone.qq.com/1234567890'

# 设置请求头参数
head = {
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36',
    'cookie': cookie
}

# 发请求,获取响应
res = requests.get(url, headers=head)

# 获取响应内容
# print(res.text)

# 写入文件
with open('qq.html', 'w', encoding='utf-8') as f:
    f.write(res.text)

八、Selenium 操作下拉菜单

select 元素不能直接点击,因为点击后还需要选中元素,这时候 selenium 就专门为 select 标签提供了一个类。

from selenium.webdriver.support.ui import Select

将获取到的元素当成参数传到这个类中,创建这个对象后,就可以使用这个对象进行选择了。

案例

目标网站:https://news.sina.com.cn/

需求:选择娱乐版块,日期8号相关新闻

分析:

1、打开对应网站

2、点击下拉菜单,选择对应的版块内容

3、点击日期图标,选择的日期是8号

# 内置库
import time
# 导入模块,加载驱动
from selenium import webdriver
# 专门针对 Select 标签使用
from selenium.webdriver.support.ui import Select
# 定位元素
from selenium.webdriver.common.by import By

# 加载驱动
driver = webdriver.Chrome()

# 最大化窗口
driver.maximize_window()

# 加载网站
driver.get('https://news.sina.com.cn/')

# 解析,直接定位到 select 标签
el = driver.find_element(By.NAME, 'channel')
# print(el)

# 定位到娱乐的板块,实例化 select 对象
select_tag = Select(el)

# 定位下拉框
# 方法一
# select_tag.select_by_index(4)  # 下标从0开始的
# 方法二
# select_tag.select_by_value('ent')  # 根据 option 里面 value 属性定位的
# 方法三
select_tag.select_by_visible_text('娱乐')  # text 指的是文本

# 等待1秒
time.sleep(1)

# 定位日期
driver.find_element(By.NAME, 'date').click()

# 选择8号
driver.find_element(By.XPATH, '//div[@id="dataView"]/div/table/tbody/tr[2]/td[2]').click()

九、Selenium 鼠标行为链

页面中需要借助鼠标操作元素,那么这时候可以使用鼠标行为链类 ActionChains 来完成,比如现在要将鼠标移动到某个元素上并执行点击事件。

学习文档

1、常用方法

actions = ActionChains(driver)  # 实例化⼀个⿏标⾏为链的对象
actions.move_to_element(inputTag)  # 将⿏标移动到元素的中间
actions.send_keys_to_element(inputTag,'python')  # 将键发送到元素
actions.move_to_element(submitTag)  # 将⿏标移动到元素的中间
actions.context_click()  # 对元素执⾏上下⽂单击(右键单击)
actions.click(submitTag)  # 单击⼀个元素
actions.perform()  # 执⾏所有存储的操作
actions.lick_and_hold(element)  # 点击但不松开⿏标
actions.double_click(element)  # 双击

更多方法可参考

2、案例

目标网站:https://passport.vip.com/login?src=https%3A%2F%2Fwww.vip.com%2F

需求:

1、加载网站

2、切换登录方式

3、输入账号密码,勾选协议,点击登录案例

4、鼠标移动到对应的验证码元素上面

# 内置库
import time
# 导入模块,加载驱动
from selenium import webdriver
# 定位元素
from selenium.webdriver.common.by import By
# 导入鼠标行为链
from selenium.webdriver import ActionChains

# 加载驱动
driver = webdriver.Chrome()

# 最大化窗口
driver.maximize_window()

# 加载网站
driver.get('https://passport.vip.com/login?src=https%3A%2F%2Fwww.vip.com%2F')

# 等待2秒
time.sleep(2)

# 切换登录方式 —— 1、定位元素 2、点击
driver.find_element(By.XPATH, '//div[@class="c-tab-nav "]/div[2]').click()

# 等待0.5秒
time.sleep(0.5)

# 输入用户名
driver.find_element(By.ID, 'J_login_name').send_keys('3424234234')

# 输入密码
driver.find_element(By.ID, 'J_login_pwd').send_keys('34234242')

# 等待0.5秒
time.sleep(0.5)

# 勾选协议
inputs = driver.find_element(By.ID, 'J_login_agree')  # 定位到这个元素

# 通过 click 无法点击成功,可以采用 js 点击
driver.execute_script('arguments[0].click();', inputs)

# 登录
driver.find_element(By.ID, 'J_login_submit').click()

# 等待1秒
time.sleep(1)

# 定位图片
img = driver.find_element(By.CLASS_NAME, 'vipsc_qimg')

# 鼠标移动
actions = ActionChains(driver)
actions.move_to_element(img)  # 移动到目标位置

# 提交行为链
actions.perform()

十、Selenium 切换页面与操作多窗口

1、切换页面

# 内置库
import time
# 导入模块,加载驱动
from selenium import webdriver

# 加载驱动
driver = webdriver.Chrome()

# 最大化窗口
driver.maximize_window()

# 先模拟打开多个网站
driver.get('https://www.baidu.com')  # 百度
time.sleep(3)
driver.execute_script('window.open("https://www.douban.com/")')  # 豆瓣
time.sleep(3)
driver.execute_script('window.open("https://juejin.cn/")')  # 掘金
time.sleep(3)
driver.execute_script('window.open("https://cloud.tencent.com/developer/ask/sof/1237007")')  # 腾讯
time.sleep(3)

# 打印鼠标聚焦的 url
# print(driver.current_url)

# 切换窗口
driver.switch_to.window(driver.window_handles[-3])

'''
0:https://www.baidu.com
1:https://cloud.tencent.com/developer/ask/sof/1237007
2:https://juejin.cn/
3:https://www.douban.com/

-1:https://www.douban.com/
-2:https://juejin.cn/
-3:https://cloud.tencent.com/developer/ask/sof/1237007
'''

# 打印鼠标聚焦的 url
print(driver.current_url)

2、多窗口操作

# 内置库
import time
# 导入模块,加载驱动
from selenium import webdriver
# 定位元素
from selenium.webdriver.common.by import By

# 加载驱动
driver = webdriver.Chrome()

# 最大化窗口
driver.maximize_window()

# 加载网站
driver.get('https://juejin.cn/')

# 等待2秒
time.sleep(2)

# 定位第二篇文章
driver.find_element(By.XPATH, '//div[@class="entry-list list"]/li[2]').click()

# 等待1秒
time.sleep(1)

# 切换窗口
driver.switch_to.window(driver.window_handles[1])

# 获取 elements 内容
te = driver.page_source
print(te)

十一、Selenium 高级操作

1、page_source:返回结构的源码

# 内置库
import time
# 导入模块,加载驱动
from selenium import webdriver

# 加载驱动
driver = webdriver.Chrome()

# 最大化窗口
driver.maximize_window()

# 加载网站
driver.get('https://music.163.com/#/discover/toplist')

# 等待2秒
time.sleep(2)

# 切换到 iframe
driver.switch_to.frame('g_iframe')

# 等待2秒
time.sleep(2)

# 拿到的是 elements 里面的内容,xpath 直接做解析就可以了
print(driver.page_source)

2、find():在源码当中查找某个字符的存在

# 内置库
import time
# 导入模块,加载驱动
from selenium import webdriver
# 定位元素
from selenium.webdriver.common.by import By

# 加载驱动
driver = webdriver.Chrome()

# 最大化窗口
driver.maximize_window()

# 加载网站
driver.get('https://tieba.baidu.com/f?kw=%E8%8F%9C%E8%B0%B1&ie=utf-8&pn=11400')

# 等待2秒
time.sleep(2)

# # 获取网页源码
# html = driver.page_source
# # 打印源码
# print(html)
# # 看网页源码里是否存在下一页
# print(driver.page_source.find('下一页>'))
'''
如果没有查找到对应的字符,返回的是-1
如果查找到了,返回的是数字
'''

while True:
    # 判断源码里存在下一页时
    if driver.page_source.find('下一页>') != -1:
        # 点击下一页的按钮
        driver.find_element(By.CLASS_NAME, 'next').click()
        # 等待1秒
        time.sleep(1)
    # 源码里不存在下一页时,跳出循环
    else:
        print('已经是最后一页了')
        break

3、By.LINK_TEXT:根据链接文本定位

# 内置库
import time
# 导入模块,加载驱动
from selenium import webdriver
# 定位元素
from selenium.webdriver.common.by import By

# 加载驱动
driver = webdriver.Chrome()

# 最大化窗口
driver.maximize_window()

# 加载网站
driver.get('https://movie.douban.com/top250')

# 等待2秒
time.sleep(2)

# 获取网页源码
html = driver.page_source

# 等待1秒
time.sleep(1)

# 根据链接文本定位,点击‘后页>’
driver.find_element(By.LINK_TEXT, '后页>').click()

# 打印点击‘后页>’后的文本
print(driver.page_source)

4、get_attribute():获取属性值

# 内置库
import time
# 导入模块,加载驱动
from selenium import webdriver
# 定位元素
from selenium.webdriver.common.by import By

# 加载驱动
driver = webdriver.Chrome()

# 最大化窗口
driver.maximize_window()

# 加载网站
driver.get('https://movie.douban.com/top250')

# 等待2秒
time.sleep(2)

# 获取图片标签
img_tag = driver.find_element(By.XPATH, '//div[@class="pic"]/a/img')

# 获取属性值 —— 通过方法
print(img_tag.get_attribute('src'))

5、.text:获取节点内容

# 内置库
import time
# 导入模块,加载驱动
from selenium import webdriver
# 定位元素
from selenium.webdriver.common.by import By

# 加载驱动
driver = webdriver.Chrome()

# 最大化窗口
driver.maximize_window()

# 加载网站
driver.get('https://movie.douban.com/top250')

# 等待2秒
time.sleep(2)

# 获取文本内容
div_tag = driver.find_element(By.XPATH, '//div[@class="hd"]').text

# 打印文本内容
print(div_tag)

十二、设置无界面

# 内置库
import time
# 导入模块,加载驱动
from selenium import webdriver
# 定位元素
from selenium.webdriver.common.by import By

# 设置参数
options = webdriver.ChromeOptions()

# 设置无界面模式
options.add_argument('--headless')

# 传递参数
driver = webdriver.Chrome(options=options)

# 加载网站
driver.get('https://movie.douban.com/top250')

# 等待3秒
time.sleep(3)

# 获取图片标签
img_tag = driver.find_element(By.XPATH, '//div[@class="pic"]/a/img')

# 打印属性值
print(img_tag.get_attribute('src'))

十三、页面等待

1、强制等待

time.sleep(时间)

2、隐式等待

调用 driver.implicitly_wait ,针对所有元素,设置等待时间,如果等待时间内加载出来,代码继续往下走,等待时间以内不断刷新看元素是否加载出来,超出则报出异常。

# 导入模块,加载驱动
from selenium import webdriver
# 定位元素
from selenium.webdriver.common.by import By

# 加载驱动
driver = webdriver.Chrome()

# 加载网站
driver.get('https://www.baidu.com')

# 显示等待,针对的全局元素
driver.implicitly_wait(10)

# 10秒内出现代码继续往下走
driver.find_element(By.ID, 'kw').send_keys('python')

# 等待10秒不出现就会报错
driver.find_element(By.ID, 'kw1').send_keys('python')

3、显示等待

表明某个条件成立后才执行获取元素的操作,也可以在等待的时候指定一个最大的时间,如果超过这个时间那么就抛出一个异常。

# 显示等待,需要导入模块
# 导入 WebDriverWait 类
from selenium.webdriver.support.wait import WebDriverWait
# 导入 expected_conditions 模块并使用别名 EC
from selenium.webdriver.support import expected_conditions as EC
# 导入模块,加载驱动
from selenium import webdriver
# 定位元素
from selenium.webdriver.common.by import By

# 显示等待,需要导入模块
# 导入 WebDriverWait 类
from selenium.webdriver.support.wait import WebDriverWait
# 导入 expected_conditions 模块并使用别名 EC
from selenium.webdriver.support import expected_conditions as EC

# 加载驱动
driver = webdriver.Chrome()

# 加载网站
driver.get('https://www.baidu.com')

# 默认是0.5秒刷新一次
# 等待时间总共是10秒,每隔1秒刷新一次
# until 具体的条件内容
element = WebDriverWait(driver, 10, 1).until(
    # 判断元素是否加载出来
    EC.presence_of_element_located((By.ID, 'kw'))
)
element.send_keys('hello')

隐式等待针对的是全局元素,全局生效,代码简单,只用于查找元素。

显示等待有很多的判断条件,适用范围更广,只针对某一个元素。

十四、案例

目标网站: https://juejin.cn/

需求:爬取文章内容,保存为 txt 格式,文件名以文章标题命名

分析:

翻页方式:滑动滚动条进行加载内容

1、设置先滚动5次,先把下面的内容加载出来,获取元素

2、先获取所有 li 元素,遍历 li 元素,进行点击操作

# 内置库
import time
# 加载驱动
from selenium import webdriver
# 定位元素
from selenium.webdriver.common.by import By
# 正则
import re

class JuJin(object):

    # 定义初始化方法
    def __init__(self):
        # 实例属性
        # 加载驱动
        self.driver = webdriver.Chrome()
        # 窗口最大化
        self.driver.maximize_window()
        # 加载网站
        self.driver.get('https://juejin.cn/')

    # 解析数据
    def parse_html(self):
        # 等待2秒
        time.sleep(2)
        # 获取 li 里的所有数据
        lis = self.driver.find_elements(By.XPATH, '//div[@class="entry-list list"]/li')
        # 循环处理数据
        for li in lis:
            # 捕获异常
            try:
                # 等待2秒
                time.sleep(2)
                # 获取文章标题标签
                a = li.find_element(By.CLASS_NAME, 'title')
                # 点击标题标签进入详情页
                self.driver.execute_script('arguments[0].click();', a)
                # 切换窗口到内容页
                self.driver.switch_to.window(self.driver.window_handles[1])
                # 等待2秒
                time.sleep(2)
                # 获取标题标签
                title = self.driver.find_elements(By.CLASS_NAME, 'article-title')
                # 获取文章内容标签
                contents = self.driver.find_elements(By.XPATH, '//div[@class="markdown-body cache"]/p')
                # 判断标题是否是空列表,如果是空列表,说明文章是广告文章
                if not title:
                    # 获取标题标签
                    title = self.driver.find_elements(By.XPATH, '//a[@class="title"]/span')
                    # 获取文章内容标签
                    contents = self.driver.find_elements(By.XPATH, '//div[@class="markdown-body"]/p')
                # 获取标题文本
                titles = title[0].text
                # 正则表达式替换标题特殊字符
                titles = re.sub(r'[,?/<>!: ()|"]', '', titles)
                # 定义组装数据的变量
                s = ''
                # 获取数据为列表,需循环取出
                for i in contents:
                    # 组装数据
                    s += i.text + '\n'
                # 打印文章标题,内容
                # print(titles)
                # 保存数据
                self.save_data(titles, s)
                # 关闭当前窗口
                self.driver.close()
                # 切换窗口到列表页
                self.driver.switch_to.window(self.driver.window_handles[0])
                # 等待1秒
                time.sleep(1)
            except Exception as e:
                # 打印异常
                print(e)
                print("没有文章内容")
                # 关闭当前窗口
                self.driver.close()
                # 切换窗口到列表页
                self.driver.switch_to.window(self.driver.window_handles[0])

    # 保存数据
    def save_data(self, title, contents):
        # 创建 txt 文本文档
        with open(f'掘金/{title}.txt', 'w', encoding='utf-8') as f:
            # 文件写入
            f.write(contents)

    # 滚动方法
    def slide(self, height):
        # 滑动滚动条
        self.driver.execute_script(
            f'window.scrollTo(0,{height})'
        )

    # 处理主逻辑
    def main(self):
        # 获取窗口的高度
        heights = self.driver.get_window_size()['height']
        # 滑动次数
        page = 1
        # 滑动
        while page <= 5:
            self.slide(heights)
            # 加高度
            heights = heights + heights
            # 滑动次数+1
            page += 1
            # 等待1秒
            time.sleep(1)
        # 解析数据
        self.parse_html()

# 创建对象
data = JuJin()
# 调用 main 方法,开始执行主程序
data.main()

记录学习过程,欢迎讨论交流,尊重原创,转载请注明出处~

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值