python学习之爬虫(六)--selenium: 无头浏览器、selenium的基本使用、selenium元素定位的方法、selenium爬虫案例练习

一、无头浏览器:

1.什么是selenium:

Selenium是一个Web的自动测试工具, 最初是为了网站自动化测试二开发的, Selenium可以直接运行在浏览器上,特支持所有主流的浏览器(包括PhantomJS这些无界面的浏览器), 可以接收指令,让浏览器自动加载页面,获取需要的数据,甚至页面截屏.

2.Phantom JS的介绍:

PhantomJS是一个基于Webkit的"无界面"(headless)浏览器, 它会把网站加载到内存并执行页面上的JavaScript.
下载地址: http://phantomjs.org/download.html

3. Chromedriver的介绍:

Chromedriver也是一个能够被selenium驱动的浏览器,但是和PhantomJS的区别在于它是有界面的.
下载地址:https://npm.taobao.org/mirrors/chromedriver

4.driver的安装:

最简单的安装方式: 解压后吧bin目录下的可执行文件移动到环境变量下

5. PhantomJS安装实例:

5.1 下载PhantomJS

wget https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-2.1.1-linux-x86_64.tar.bz2

5.2 解压并建立软连接:

tar -xvjf phantomjs-2.1.1-linux-x86_64.tar.bz2 
sudo cp -R phantomjs-2.1.1-linux-x86_64 /usr/local/share/ 
sudo ln -sf /usr/local/share/phantomjs-2.1.1-linux-x86_64/bin/phantomjs /usr/local/bin/

6. chromedriver安装示例:

chromedriver下载地址:
http://chromedriver.storage.googleapis.com/index.html

----- Linux 下安装方式
chromedriver_linux64.zip : 版本 ChromeDriver v2.22 (2016-06-06)
(支持 Chrome v49-52,当前Ubuntu虚拟机下的Chrome版本为50.0)


1. unzip chromedriver_linux64.zip
2. sudo chmod +x chromedriver
3. sudo mv chromedriver /usr/local/bin/


----- MacOS X 下安装方式
chromedriver_mac64.zip : 版本 ChromeDriver v2.32 (2017-08-30)
(支持 Chrome v59-61)

1. 安装 同Linux



----- Windows 下安装方式
chromedriver_win32.zip : 版本 ChromeDriver v2.32 (2017-08-30)
(支持 Chrome v59-61)

1. 解压 chromedriver_win32.zip
2. 将 chromedriver 移动到 Python安装目录下
(其实放哪都可以,但是需要配环境变量,放Python安装目录下省事)


注意:Chromedriver和电脑上的chrome版本有对应关系,建议使用最新的Chromedriver版本并且更新chrome浏览器到最新版

7.小结

  • 能够安装PhtantomJs和Chromedriver浏览器
  • 能够知道selenium是自动化测试工具/local/share/phantomjs-2.1.1-linux-x86_64/bin/phantomjs /usr/local/bin/

二、selenium的基本使用:

安装selenium:

pip install selenium

1.加载网页:

selenium通过控制浏览器,对应获取的数据都是elements的内容.

# coding=utf-8
from selenium import webdriver
import time
# 指定driver的绝对路径
# driver = webdriver.PhantomJS(executable_path='/home/worker/Desktop/driver/phantomjs') 
driver = webdriver.Chrome(executable_path=r''/home/worker/Desktop/driver/chromedriver')

# 想一个url发起请求
driver.get("https://www.baidu.com/")
# 保存页面
driver.save_screenshot("baidu.png")
time.sleep(5)

# 退出
driver.quit()

2.定位和操作 :

以百度搜索为例:

# coding=utf-8

from selenium import webdriver
import time
# 指定driver的绝对路径
# driver = webdriver.PhantomJS(executable_path='/home/worker/Desktop/driver/phantomjs') 
driver = webdriver.Chrome(executable_path=r'F:\学习\python学习内容\python练习\02_selenium的使用\chromedriver_win32\chromedriver.exe')

# 想一个url发起请求
driver.get("https://www.baidu.com/")
driver.find_element_by_id('kw').send_keys('python')
time.sleep(5)
driver.find_element_by_id('su').click()
time.sleep(5)

# 退出
driver.quit()

3.查看请求信息:

driver.page_source # 查看网页源码
driver.get_cookies() # # 获取当前浏览器的全部cookies
driver.current_url # 获取当前页面的url

4.退出:

driver.close() #退出当前页面
driver.quit()  #退出浏览器

5.练习:

模拟百度搜索’传智博客’

# coding=utf-8
from selenium import webdriver
import time

# 指定driver的绝对路径
driver = webdriver.Chrome(executable_path=r'F:\学习\python学习内容\python练习\02_selenium的使用\chromedriver_win32\chromedriver.exe')


driver.get("https://www.baidu.com/")
driver.find_element_by_id('kw').send_keys("传智播客")
time.sleep(5)
driver.find_element_by_id('su').click()
time.sleep(5)

# 退出
driver.quit()

6.小结:

  • selenium的导包:from selenium import webdriver
  • selenium创建driver对象:webdriver.PhantomJS()
  • selenium请求数:driver.get(“http://www.baidu.com/”)
  • selenium查看数据: driver.page_source
  • 关闭无界面浏览器: driver.quit()
  • 根据id定位元素: driver.find_element_by_id(“kw”)
  • 操作点击事件: click()
  • 给输入框赋值:send_keys()

三、selenium元素定位的方法:

1.selenium的定位操作:

定位元素语法:

find_element_by_id(返回一个元素)
find_elements_by_xpatn(返回一个包含元素的列表)
find_elements_by_link_text(根据连接文本获取元素列表)
find_elements_by_partial_link_text(根据连接包含的文本获取袁旭列表)
find_elements_by_tag_name(根据标签名获取元素列表)
find_elements_by_class_name(根据类名获取元素列表)

注意:

find_element和find_elements的区别: 多了s就返回列表, 没有s就返回匹配到的第一个元素
by_link_text和by_partial_link_text的区别: 全部文本和包含某个文本

练习:

以豆瓣首页为例: https://www.douban.com/

# coding=utf-8
from selenium import webdriver
import time

# 指定driver的绝对路径
driver = webdriver.Chrome(executable_path=r'F:\学习\python学习内容\python练习\02_selenium的使用\chromedriver_win32\chromedriver.exe')

driver.get("https://www.douban.com/")

# find_element_by_id (返回一个元素)
ret1 = driver.find_element_by_id("anony-nav")
print("ret1: {}".format(ret1))

# find_elements_by_xpath (返回一个包含元素的列表)
ret2 = driver.find_elements_by_xpath('//*[@id="anony-nav"]/h1')
for el in ret2:
    print("ret2: {}".format(el))      

# find_elements_by_link_text (根据连接文本获取元素列表)
ret3 = driver.find_elements_by_link_text("下载豆瓣 App")
for el in ret3:
    print("ret3: {}".format(el)) 

# find_elements_by_partial_link_text (根据链接包含的文本获取元素列表)
ret4 = driver.find_elements_by_partial_link_text("豆瓣")
for el in ret4:
    print("ret4: {}".format(el)) 

# find_elements_by_tag_name (根据标签名获取元素列表)
ret5 = driver.find_elements_by_tag_name("h1")
for el in ret5:
    print("ret5: {}".format(el)) 

# find_elements_by_class_name (根据类名获取元素列表)
ret6 = driver.find_elements_by_class_name("section")
for el in ret6:
    print("ret6: {}".format(el)) 

time.sleep(5)

# 退出
driver.quit()

2.获取数据:

find_element仅仅能获取元素, 不能够直接获取其中的数据,如果需要获取其中的数据, 需要使用一下方法:

  • element.text: 获取文本
  • element.get_attribute(“href”): 获取属性值

四、selenium的其他方法:

1.selenium处理cookie:

driver.get_cookies(): 获取的是完整的cookie信息, 不光有name、value, 还有domain等其他信息.

# 把cookie转化成字典
dookie_dict = {cookie['name']: cookie['value'] for cookie in driver.get_cookies()}

# 删除一条cookie
driver.delete_cookie('cookie_name')

# 删除所有的cookie
driver.delete_cookies()

2.页面等待:

  • 如果页面采用了动态html技术,name页面上部分元素出现的时间编不能确定,这个时候可以设置一个等待时间, 强制要求在时间内出现,否则报错.
  • 页面等待的方法: time.sleep(10)

3.selenium执行js代码:

# coding=utf-8
from selenium import webdriver
import time

# 指定driver的绝对路径
driver = webdriver.Chrome(executable_path=r'F:\学习\python学习内容\python练习\02_selenium的使用\chromedriver_win32\chromedriver.exe')

driver.get("http://www.itcast.cn/")
time.sleep(2)

js = 'window.scrollTo(0,document.body.scrollHeight)' # js语句:页面到最后
driver.execute_script(js) # 执行js的方法

time.sleep(5)
# 退出
driver.quit()

4.switch方法切换的操作:

4.1 标签页切换

一个 浏览器肯定会有很多窗口, 所有我们肯定要有方法来实现窗口的切换. 切换窗口的方法如下:

# 1. 获取当前所有的窗口
current_windows = driver.window_handles

# 2.根据窗口索引进行切换
driver.switch_to.window(current_windows[1])

完整代码:

# coding=utf-8
from selenium import webdriver
import time

# 指定driver的绝对路径
driver = webdriver.Chrome(executable_path=r'F:\学习\python学习内容\python练习\02_selenium的使用\chromedriver_win32\chromedriver.exe')

# 打开第一个页面
driver.get("https://www.baidu.com/")
time.sleep(1)
driver.find_element_by_id("kw").send_keys('python')
time.sleep(1)
driver.find_element_by_id('su').click()
time.sleep(1)

# 通过js打开第二个标签页
js = 'window.open("http://www.sougou.com/");'
driver.execute_script(js)
time.sleep(3)

# 获取当前所有窗口
windows = driver.window_handles
print(windows)
time.sleep(2)
# 根据窗口进行切换
driver.switch_to.window(windows[0])
time.sleep(2)
driver.switch_to.window(windows[1])

time.sleep(6)
# 退出
driver.quit()

4.2 页内iframe:

iframe是html中常用的一种技术, 即一个页面中嵌套了另一个页面, selenium默认是访问不了frame中的内容的, 对应的解决思路是: driver.switch_to.frame()

在使用selenium登良路QQ邮箱的过程中, 会发现无法在邮箱登录input标签中输入内容,通过观察源码可以发现, from表单在一个frame中,所以需要切换到frame中

login_frame = driver.find_element_by_id('login_frame')	# 定位到frame
driver.switch_to.frame(login_frame)	# 转向到该frame中
练习:

模拟登录QQ邮箱:

# coding=utf-8
from selenium import webdriver
import time

# 指定driver的绝对路径
driver = webdriver.Chrome(executable_path=r'F:\学习\python学习内容\python练习\02_selenium的使用\chromedriver_win32\chromedriver.exe')
mail_url = "https://mail.qq.com/cgi-bin/loginpage"
driver.get(mail_url)
time.sleep(2)

# 根据定位,切换到iframe
login_frame = driver.find_element_by_id('login_frame')
driver.switch_to.frame(login_frame)

driver.find_element_by_link_text("帐号密码登录").click()

# 输入邮箱的账号密码
driver.find_element_by_xpath('//*[@id="u"]').send_keys("117****619@qq.com")
driver.find_element_by_xpath('//*[@id="p"]').send_keys("********")
driver.find_element_by_xpath('//*[@id="login_button"]').click()
time.sleep(3)

# 切换到iframe元素的外边
windows = driver.window_handles
driver.switch_to.window(windows[0])

username = driver.find_element_by_xpath('//*[@id="useralias"]').text
print(username)


time.sleep(10)
# 退出
driver.quit()

4.3 alert弹窗:

当触发了某个事件之后,页面出现了弹窗提示,处理这个提示或者获取提示信息方法如下:

driver.switch_to.alert() # 跟frame一样的处理方式!

5. 页面前进和后退

driver.forward()     # 前进
driver.back()        # 后退

6. selenium的优缺点

  • selenium能够执行页面上的js,对于js渲染的数据和模拟登陆处理起来非常容易
  • selenium由于在获取页面的过程中会发送很多请求,所以效率非常低,所以在很多时候需要酌情使用

五、selenium的爬虫案例练习:

1.斗鱼爬虫:

爬取斗鱼直播平台的所有房间信息:https://www.douyu.com/directory/all

1.1 思路分析:

  1. 数据的位置:
    每个房间的数据都在class=layout-Cover-list的ul中
    在这里插入图片描述
  2. 实现翻页和控制程序结束:
    selenium中通过点击就可以实现翻页,观察存在下一页和不存在下一页时候标签的变化

存在下一页时:aria-disabled=“false”在这里插入图片描述
不存在下一页时:aria-disabled=“true”
在这里插入图片描述

1.2 实现代码:

ps:应该是斗鱼做了反爬, 始终没有得到预期结果

# coding=utf-8
from selenium import webdriver
import time
# 指定driver的绝对路径
# driver = webdriver.PhantomJS(executable_path='/home/worker/Desktop/driver/phantomjs') 
# driver = webdriver.Chrome(executable_path=r'F:\学习\python学习内容\python练习\02_selenium的使用\chromedriver_win32\chromedriver.exe')

class Douyu:
    def __init__(self):
        """初始化数据"""
        self.start_url = "https://www.douyu.com/directory/all"
        self.driver = driver = webdriver.Chrome(executable_path=r'F:\学习\python学习内容\python练习\02_selenium的使用\chromedriver_win32\chromedriver.exe')
        self.content_list = []
    
    def get_content_list(self):
        """提取数据"""
        time.sleep(5)
        li_list = self.driver.find_elements_by_xpath('//ul[@class="layout-Cover-list"]/li')
        for li in li_list:
            item = {}
            item['title'] = li.find_element_by_xpath('//h3[@class="DyListCover-intro"]').text
            item['zone'] = li.find_element_by_xpath('//span[@class="DyListCover-zone"]').text
            item['anchor'] = li.find_element_by_xpath('//h2[@class="DyListCover-user"]').text
            item['watch_num'] = li.find_element_by_xpath('//span[@class="DyListCover-hot"]').text
            self.content_list.append(item)
            print(item)
        # 提取下一页数据
        next_url = self.driver.find_element_by_xpath('//li[@title="下一页"]')    
        if next_url.get_attribute("aria-disabled")=="false":
            return next_url
        else:
            return False

    def save_content_list(self):
        """保存content"""
        for content in self.content_list:
            print(content)

    def run(self):
        """运行逻辑"""
        self.driver.get(self.start_url)
        next_url = self.get_content_list()
        while next_url:
            next_url.click()
            time.sleep(3)
            next_url = self.get_content_list()
        # self.save_content_list()
        self.driver.close()

if __name__ == "__main__":
    douyu = Douyu()
    douyu.run()

ps: 有看出问题的同学,欢迎留言(笑哭)…

在这里插入图片描述

2.网易云音乐爬虫:

完成网易云音乐的所有列表名字和url地址
地址: http://music.163.com/#/discover/playlist

2.1 思路分析:

  1. 确定程序入口位置;
  2. 确定首页数据的位置和url地址;
  3. 实现反野和程序停止的判断;

2.2 技术点:

  1. 数据在iframe中:在这里插入图片描述

2.3 参考代码:

# coding=utf-8
from selenium import webdriver
import time
# 指定driver的绝对路径
# driver = webdriver.PhantomJS(executable_path='/home/worker/Desktop/driver/phantomjs') 
# driver = webdriver.Chrome(executable_path=r'F:\学习\python学习内容\python练习\02_selenium的使用\chromedriver_win32\chromedriver.exe')


class CloudMusic(object):
    def __init__(self, *args, **kwargs):
        self.start_url = 'http://music.163.com/#/discover/playlist'
        self.driver = webdriver.Chrome(executable_path=r'F:\学习\python学习内容\python练习\02_selenium的使用\chromedriver_win32\chromedriver.exe')


    def get_content_list(self):
        """提取数据"""   
        # 切换进iframe
        data_frame = self.driver.find_element_by_id('g_iframe')
        self.driver.switch_to.frame(data_frame)

        # 获取数据
        li_list = self.driver.find_elements_by_xpath('//*[@id="m-pl-container"]/li')
        print(f"该页有歌单:{len(li_list)}")
        content_list = []
        for li in li_list:
            item = {}
            item['title'] = li.find_element_by_class_name('msk').get_attribute("title")
            item['href'] = li.find_element_by_class_name('msk').get_attribute("href")
            print(item)
            content_list.append(item)
        
        # 下一页
        page_url_list = self.driver.find_elements_by_xpath('.//div[@class="u-page"]/a')
        next_url = page_url_list[-1] if page_url_list[-1].get_attribute("class") != "zbtn znxt js-disabled" else None
        return content_list, next_url

    def save_content_list(self, content_list):
        for content in content_list:
                print(content)

    def run(self):
        """实现主逻辑"""
        # 请求首页面
        self.driver.get(self.start_url)
        time.sleep(3)

        # 获取数据
        contemt_list, next_url = self.get_content_list()

        # 请求下一页
        while next_url is not None:
            js = 'window.scrollTo(0,document.body.scrollHeight)'  # js语句:滚动到页面最底部
            self.driver.execute_script(js)  # 执行js的方法
            print(next_url.get_attribute('href'))
            next_url.click() #页面没有完全加载完,会报错
            time.sleep(3)

            # 此时在iframe标签中 代码逻辑需要我们先切出
            windows = self.driver.window_handles
            self.driver.switch_to.window(windows[0])

            content_list, next_url = self.get_content_list()
            self.save_content_list(content_list)
        # 保存逻辑
        # self.save_content_list(content_list)
        # 退出浏览器
        self.driver.quit()


if __name__ == "__main__":
    cloudmusic = CloudMusic()
    cloudmusic.run()

在这里插入图片描述

六、小结:

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

浅弋、璃鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值