Python爬虫(第七周)

目录

一、Selenium

1.chromedriver

2.Selenium

3.无头浏览器和有头浏览器

4.Selenium的基础使用

5.selenium的实际使用

主要方法

其他方法

6.iframe窗口

7.页面等待

8.selenium获取京东图书数据

单页

多页

二、常见的反爬


一、Selenium

1.chromedriver

下载网站:https://npm.taobao.org/mirrors/chromedriver/

根据自己的chrome浏览器版本进行选择下载,下载成功后解压缩,找到chromedriver.exe,复制到于自己python解释器同一路径下

2.Selenium

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

测试就是在项目上线前,去测试功能是否有问题,测试的方法:点击 > 发送请求,检查对应的响应是否是正确,而这些点击,滑动等去触发的请求都是js代码,我们可以使用python代码驱动selenium去进行模拟点击,模拟滑动去发送请求获取响应,这就是selenium为什么会被应用的爬虫的原因。

3.无头浏览器和有头浏览器

既然自动化测试工具可以利用python代码模拟在浏览器上进行鼠标的点击和滑动,那么肯定离不开浏览器的使用。

无头浏览器:无界面浏览器,类似于cmd,我们可以在黑窗口cmd中打开文件关闭文件删除文件等操作

有头浏览器:有界面浏览器,类似于我们的桌面,不同于cmd黑窗口的是,我们可以非常直观的对文件进行打开关闭删除等操作

4.Selenium的基础使用

首先我们需要三个工具,1.chromedriver(前面已经介绍如何下载安装) 2.浏览器  3.第三方库:selenium

使用selenium写爬虫代码的流程于我们平常写代码的流程不太一样

# 导包
from selenium.webdriver import Chrome

if __name__ == '__main__':
    # 1.创建浏览器对象
    chrome_ = Chrome()

这一句代码有什么效果呢?他会打开一个对应的浏览器窗口

注意的是:我们可以在Chrome()的括号中添加参数,其中executable_path需要我们注意,前面提到了需要把chromedriver.exe放到与我们的python解释器同一路径下,如果没有放到同一路径下,executable_path=‘chromedrive的绝对路径’

# 导包
from selenium.webdriver import Chrome

if __name__ == '__main__':
    # 1.创建浏览器对象
    chrome_ = Chrome()

    # 2.url地址栏填入url,发送请求
    chrome_.get('https://www.baidu.com/')

这两句代码的运行效果是打开一个Google浏览器,并且在url地址栏填入百度首页的url,并实现跳转

# 导包
from selenium.webdriver import Chrome

if __name__ == '__main__':
    # 1.创建浏览器对象
    chrome_ = Chrome()

    # 2.url地址栏填入url,发送请求
    chrome_.get('https://www.baidu.com/')

    # 3.提取当前页面的网页数据 > 网页源代码
    data_ = chrome_.page_source

    # 4.保存,看一下效果
    with open('baidu.html', 'w', encoding='utf-8') as f:
        f.write(data_)

需要注意的是:我们这句命令提取到的是网页源代码(即我们看到的页面的代码),和network里面的数据包的response是有区别的

# 导包
from selenium.webdriver import Chrome

if __name__ == '__main__':
    # 1.创建浏览器对象
    chrome_ = Chrome()

    # 2.url地址栏填入url,发送请求
    chrome_.get('https://www.baidu.com/')

    # 3.提取当前页面的网页数据 > 网页源代码
    data_ = chrome_.page_source

    # 浏览器扩大化,因为打开是默认不是全屏
    chrome_.maximize_window()

    # 网页截图
    chrome_.save_screenshot('百度.png')

需要注意的是:网页截图只能保存png格式

# 导包
import time

from selenium.webdriver import Chrome

if __name__ == '__main__':
    # 1.创建浏览器对象
    chrome_ = Chrome()

    # 2.url地址栏填入url,发送请求
    chrome_.get('https://www.baidu.com/')

    # 3.提取当前页面的网页数据 > 网页源代码
    data_ = chrome_.page_source

    # 浏览器扩大化,因为打开是默认不是全屏
    chrome_.maximize_window()

    # 网页截图
    chrome_.save_screenshot('百度.png')

    # 自动关闭页面
    chrome_.close()

    time.sleep(2)
    
    # 自动关闭浏览器
    chrome_.quit()

我们刚才可以看到浏览器的打开,url的输入,网页的跳转,页面的关闭,浏览器的退出就是有界面,无界面就是我们并不能看到这一系列过程

无头浏览器:优点:效率高一点点

                      缺点:直观性不强

有头浏览器:优点:直观性强

                      缺点:效率低(速度慢)

无界面浏览器:

# 导包
import time
from selenium.webdriver.chrome.options import Options

from selenium.webdriver import Chrome

if __name__ == '__main__':
    # 设置无界面(无头模式)的参数
    options_ = Options()  # 创建对象
    options_.add_argument('--headless')  # 无头模式的由来

    # 1.创建浏览器对象
    chrome_ = Chrome(options=options_)

    # 2.url地址栏填入url,发送请求
    chrome_.get('https://www.baidu.com/')

    # 3.提取当前页面的网页数据 > 网页源代码
    data_ = chrome_.page_source

    with open('百度1.html', 'w', encoding='utf-8') as f:
        f.write(data_)

程序运行期间是没有浏览器的打开的

5.selenium的实际使用

主要方法

需求:

1.进入百度首页

2.在搜索栏中输入中国

        定位到搜索框:鼠标右键点击检查,选择左上角的箭头加小方框,点击搜索框,定位到在elements中的位置,鼠标右键选择copy xpath

        输入关键字:send_keys()

3.点击百度一下,发送请求,获取相应的响应

# 导包
import time

from selenium.webdriver import Chrome

if __name__ == '__main__':
    # 1.创建浏览器对象
    chrome_ = Chrome()

    # 2.url地址栏填入url,发送请求
    chrome_.get('https://www.baidu.com/')

    # 3.定位到搜索框
    input_obj = chrome_.find_element_by_xpath('//*[@id="kw"]')

    # 4.在搜索框输入关键字 中国
    input_obj.send_keys('中国')

    # 5.定位到 百度一下
    click_obj = chrome_.find_element_by_xpath('//*[@id="su"]')

    time.sleep(2)

    # 6.点击 百度一下
    click_obj.click()

其他方法

# 导包
import time

from selenium.webdriver import Chrome

if __name__ == '__main__':
    # 1.创建浏览器对象
    chrome_ = Chrome()

    # 2.url地址栏填入url,发送请求
    chrome_.get('https://www.baidu.com/')

    # 3.获取Cookie
    Cookie_ = chrome_.get_cookies()
    print(Cookie_)

    # 4.新开一个窗口
    js = 'window.open("https://www.sogou.com");'
    chrome_.execute_script(js)

    time.sleep(2)

    # 5.窗口的切换
    # 获取到窗口信息
    windows_ = chrome_.window_handles
    print(windows_)
    # 进行窗口切换(window_中列表的索引进行切换)
    time.sleep(2)
    chrome_.switch_to.window(windows_[0])

6.iframe窗口

网易云音乐链接:https://music.163.com/

如果我们想点击网易云音乐中热门推荐的第一个,按照我们上述介绍的流程进行操作

# 导包
import time

from selenium.webdriver import Chrome

if __name__ == '__main__':
    # 1.创建浏览器对象
    chrome_ = Chrome()

    # 2.url地址栏填入url,发送请求
    chrome_.get('https://music.163.com/')

    # 3.定位热门推荐第一个
    click_obj = chrome_.find_element_by_xpath('//*[@id="discover-module"]/div[1]/div/div/div[1]/ul/li[1]/div/a')

    time.sleep(2)

    # 4.点击
    click_obj.click()

我们发现按照上述流程操作报错了

出错原因分析:

1.没有找到正确的节点

2.存在iframe窗口

经对网易云音乐的elements进行检查,发现我们要找的节点确实是在iframe节点当中

那什么是iframe窗口呢?我们可以理解为画中画,就是页面中的页面,窗口中的窗口(即页面的嵌套,窗口的嵌套),我们的浏览器进入https://music.163.com/只是进入了外部的窗口,那我们如何切换到iframe窗口呢?

我们定位到的节点存在下面这个iframe窗口中:

<iframe name="contentFrame" id="g_iframe" class="g-iframe" scrolling="auto" frameborder="0" src="about:blank" allowfullscreen="true"></iframe>

可以看到这个iframe窗口的name属性为contentFrame

# 导包
import time

from selenium.webdriver import Chrome

if __name__ == '__main__':
    # 1.创建浏览器对象
    chrome_ = Chrome()

    # 2.url地址栏填入url,发送请求
    chrome_.get('https://music.163.com/')

    # 3.定位热门推荐第一个
    # 切换到iframe窗口 > 切换到name属性为contentFrame的窗口
    chrome_.switch_to.frame('contentFrame')
    # 定位到节点
    click_obj = chrome_.find_element_by_xpath('//*[@id="discover-module"]/div[1]/div/div/div[1]/ul/li[1]/div/a')

    time.sleep(2)

    # 4.点击
    click_obj.click()

7.页面等待

我们使用的selenium模拟浏览器,一个页面的组成由很多数据包构成,而这些数据包共同渲染页面,就需要一定的时间,有时候由于网络原因,加载出来一个页面也需要时间。

例如:我们要在百度首页的搜索框输入关键字并且搜索,当我们使用python代码和selenium去操作,有可能由于网络原因,当搜索框还在加载的时候,我们的python代码已经开始去进行定位,这样就会报错:该元素定位不到,此时就需要页面等待操作,等待数据包请求完毕,网页加载完毕

页面等待:

1.简单方法:time.sleep(2) 

优点:简单 

缺点:等待时间较短页面还是没加载完或者等待时间长造成时间上的浪费

2.显示等待: 可以自定义时间 10s,每500ms就尝试一次去定位元素,成功就直接返回

3.隐式等待: 可以自定义次数 10次

8.selenium获取京东图书数据

单页

我们以京东图书中中国当代小说信息的爬取为例

https://list.jd.com/list.html?cat=1713,3258,3297

需求:获取中国当代小说的书名以及对应的价格

因为我们采用的selenium,所以拿到的数据只能是html格式,提取数据只能使用xpath

经调试:

书名的xpath语法://div[@class='gl-i-wrap']/div[@class='p-name']/a[@target='_blank']/em/text()

价格的xpath语法://div[@class='p-price']/strong/i/text()

此时我们可以获取到的书名和价格都是三十个,但当我们向下滑动鼠标时,发现又加载出来了30本书,这是因为我们向下滑动鼠标时触发了Ajax,所以又有新的请求发送,加载出来了新的数据,此时在使用我们找到的xpath语法,发现可以将这三十本书的书名和价格成功提取。

所以在我们进行爬取时,必不可少的一个操作就是模拟鼠标向下滑动,使剩下的三十本的数据加载出来,而这个操作必须是在我们获取页面数据之前。

# 导包
import json
import time
from selenium.webdriver import Chrome
from lxml import etree
from selenium.common.exceptions import TimeoutException

if __name__ == '__main__':
    # 1.创建浏览器对象
    chrome_ = Chrome()

    # 设置主页渲染时间:给你五秒钟进行页面渲染
    chrome_.set_page_load_timeout(5)

    # 2.url地址栏填入url,发送请求
    try:
        chrome_.get('https://list.jd.com/list.html?cat=1713,3258,3297')
    except TimeoutException:
        print('网页渲染超时!')

    # 3.页面滚动
    js_ = 'document.documentElement.scrollTop=7000'
    chrome_.execute_script(js_)

    # 4.等待页面加载数据
    time.sleep(10)

    # 5.获取此时的页面数据
    data_ = chrome_.page_source
    html_ = etree.HTML(data_)

    # 6.提取书名
    title_list = html_.xpath("//div[@class='gl-i-wrap']/div[@class='p-name']/a[@target='_blank']/em/text()")

    # 7.提取价格
    price_list = html_.xpath("//div[@class='p-price']/strong/i/text()")

    # 8.关闭浏览器
    chrome_.quit()

    # 9.数据保存
    with open('京东图书.json', 'a', encoding='utf-8') as f:
        for i in range(len(price_list)):
            book_dict = {}
            book_dict[title_list[i]] = price_list[i]
            json_data = json.dumps(book_dict, ensure_ascii=False) + ',\n'
            f.write(json_data)

需要注意的是:我们在进入京东图书中国当代小说主页时,由于渲染需要时间,我们需要等待页面渲染,其次在我们模拟鼠标向下滑动后,页面中新数据的填充也需要时间,所以也需要设置等待时间,这里需要根据自己的网速设置

多页

以前我们进行翻页操作是找到每一页url的规律,然后对每一页进行发送请求获取响应

现在我们学习了selenium,我们可以通过模拟点击网页上的下一页图标进行翻页操作

# 导包
import json
import time
from selenium.webdriver import Chrome
from lxml import etree
from selenium.common.exceptions import TimeoutException

if __name__ == '__main__':
    # 1.确定要获取的页数
    pages_ = int(input('请输入要获取的页数:'))

    # 2.创建浏览器对象
    chrome_ = Chrome()
    chrome_.maximize_window()

    # 设置主页渲染时间:给你五秒钟进行页面渲染
    chrome_.set_page_load_timeout(5)

    # 3.url地址栏填入url,发送请求
    try:
        chrome_.get('https://list.jd.com/list.html?cat=1713,3258,3297')
    except TimeoutException:
        print('网页渲染超时!')

    for page_ in range(pages_):
        # 翻页后的页面等待
        time.sleep(2)

        # 4.页面滚动(分段滚动更符合真实情况)
        for i in range(7):
            js_ = f'document.documentElement.scrollTop={i + 1}*1000'
            chrome_.execute_script(js_)
            time.sleep(0.5)

        # 5.等待页面加载数据
        time.sleep(10)

        # 6.获取此时的页面数据
        data_ = chrome_.page_source
        html_ = etree.HTML(data_)

        # 7.提取书名
        title_list = html_.xpath("//div[@class='gl-i-wrap']/div[@class='p-name']/a[@target='_blank']/em/text()")

        # 8.提取价格
        price_list = html_.xpath("//div[@class='p-price']/strong/i/text()")

        # 9.数据保存
        with open('京东图书.json', 'a', encoding='utf-8') as f:
            for i in range(len(price_list)):
                book_dict = {}
                book_dict[title_list[i]] = price_list[i]
                json_data = json.dumps(book_dict, ensure_ascii=False) + ',\n'
                f.write(json_data)

        # 10.模拟点击下一页,下一页的xpath语法建议测试一下是否通用
        chrome_.find_element_by_xpath('//*[@id="J_bottomPage"]/span[1]/a[9]')

    # 11.关闭浏览器
    chrome_.quit()

需要注意的是:我们在翻页后页要设置等待时间,等待翻页后的页面进行渲染;我们可以利用循环改写滑动,让他一次滑动一点,一次滑动一点,而不是一次滑动很多,这样更像人的操作

二、常见的反爬

静态:(属性)检查 User-Agent,Cookie,Referer

动态:(行为)检查请求频率是否过快,检查请求频率是否太过正常(第一页停留3秒翻到第二页,再停留三秒翻到第三页,再停留三秒翻到第四页...),隐藏数据的请求(正常用户只能看到60个url的跳转,而爬虫可能解析到了隐藏的url并且返送了请求),字体反爬(正常用户看到的是经过浏览器渲染的正常中文,爬虫用户去请求的时候拿到的是密文)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

不懂编程的大学生

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

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

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

打赏作者

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

抵扣说明:

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

余额充值