目录
一、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并且返送了请求),字体反爬(正常用户看到的是经过浏览器渲染的正常中文,爬虫用户去请求的时候拿到的是密文)