爬虫11天——selenium实战
一、目的:爬取阳光视频网的多个视频,下载到本地
二、网站分析:
1.网站结构分为:视频列表页和视频详情页
2.右键检查视频列表网页:
发现:每条视频都是一个class叫"title-box"的div,然后视频详情页的链接在这个div下面的a标签
3.进入视频详情页,检查网页:
发现:视频地址在id为"vs"的div标签下面的video标签里面
三、爬取过程:
1.最初爬取代码:
#需求:爬取阳光宽频网的视频,下载到本地
from selenium import webdriver
import time
import requests
#阳光宽频网爬取类
class ygkp:
video_url_list = []
url_list = []
#1.驱动——返回驱动driver
def get_driver(self):
# 1.selenium配置
# 1.1 设置请求头
options = webdriver.ChromeOptions()
options.add_argument("user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36")
driver = webdriver.Chrome(options=options)
return driver
# #1.5 关闭底部banner页
# def close_bottom_banner(self,driver):
# #定位关闭按钮
# close_bt = driver.find_element_by_class_name("close-banner-icon")
# #点击关闭按钮
# close_bt.click()
#2.视频列表页——返回视频网页链接元素列表
def get_video_list_page(self,driver):
#2.进入网站
driver.get("https://365yg.com/")
time.sleep(5)
#3.获取视频详情页链接
video_div_url_list = driver.find_elements_by_class_name("title-box")
#print("video_div_url_list" + str(video_div_url_list))
for div in video_div_url_list:
#print("div" + str(div))
a = div.find_element_by_tag_name("a")
self.video_url_list.append(a)
#url = a.get_attribute("href")
#self.url_list.append(url)
#3.视频详情页——返回视频的URL
def get_video_url(self,driver,num):
time.sleep(5)
if num == 1:
driver.switch_to.window(driver.window_handles[num+1])
else:
driver.switch_to.window(driver.window_handles[-1])
driver.save_screenshot("01.png")
div = driver.find_element_by_id("vs")
#print("video_div" + str(div))
time.sleep(5)
video_src = div.find_element_by_tag_name("video").get_attribute("src")
#print("video_src" + str(video_src))
return video_src
#4.下载视频
def download_video(self,num,video_src):
response = requests.get(video_src).content
with open("shipin" + str(num+1) + ".mp4", "wb") as f:
f.write(response)
#5.运行
def run(self):
#1.获取驱动
driver = self.get_driver()
#2.获取视频详情页列表
self.get_video_list_page(driver=driver)
print(str(len(self.video_url_list)))
#3.关闭底部banner页
#self.close_bottom_banner(driver=driver)
#print("video_url_list"+str(self.video_url_list))
#4.点击每个视频链接
for i, video_web_url in enumerate(self.video_url_list):
driver.switch_to.window(driver.window_handles[0])
print("video_web_url" + str(i+1) +":" + str(video_web_url))
#print("url" + str(i+1) + ":" + str(self.url_list[i]))
time.sleep(10)
video_web_url.click()
#driver.execute_script("arguments[0].click();", video_web_url)
#5.获取每个视频的URL地址
video_src = self.get_video_url(driver=driver,num=i)
#6.下载url
self.download_video(num=i,video_src=video_src)
ygkp().run()
结果报错:
2.
在网上查询到,有两种解决办法:
#方法1:
element = driver.find_element_by_css('div[class*="loadingWhiteBox"]')
driver.execute_script("arguments[0].click();", element)
#方法2:
element = driver.find_element_by_css('div[class*="loadingWhiteBox"]')
webdriver.ActionChains(driver).move_to_element(element ).click(element ).perform()
我都试了一遍,结果,不会再报这个错误,但是后面会反复进入同一个详情页,反复下载同一个视频
再次查询ElementClickInterceptedException: Message: element click intercepted报错原因:发现原来是由于已经定位到的目标元素被其他元素遮挡,所以无法点击该元素。
查看网页:
发现:视频列表页,底部有banner页,挡住了第五条视频。所以,无法点击。就像用户操作鼠标一样,当banner页覆盖了第五条视频时,用户无法用鼠标点击到该条视频。这应该就是所说的——页面元素存在遮挡
再次查看报错信息:
也是在点击第五条视频时,出现错误。
解决方法:第一次进入视频列表网页时,就先立即关闭banner页,然后再逐个点击视频。
检查网页:
关闭banner的X按钮,class叫“close-banner-icon”
修改后代码:
#需求:爬取阳光宽频网的视频,下载到本地
from selenium import webdriver
import time
import requests
#阳光宽频网类
class ygkp:
video_url_list = []
url_list = []
#1.驱动——返回驱动driver
def get_driver(self):
# 1.selenium配置
# 1.1 设置请求头
options = webdriver.ChromeOptions()
options.add_argument("user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36")
driver = webdriver.Chrome(options=options)
return driver
#1.5 关闭底部banner页
def close_bottom_banner(self,driver):
#定位关闭按钮
close_bt = driver.find_element_by_class_name("close-banner-icon")
#点击关闭按钮
close_bt.click()
#2.视频列表页——返回视频网页链接元素列表
def get_video_list_page(self,driver):
#2.进入网站
driver.get("https://365yg.com/")
time.sleep(5)
#3.获取视频详情页链接
video_div_url_list = driver.find_elements_by_class_name("title-box")
#print("video_div_url_list" + str(video_div_url_list))
for div in video_div_url_list:
#print("div" + str(div))
a = div.find_element_by_tag_name("a")
self.video_url_list.append(a)
#url = a.get_attribute("href")
#self.url_list.append(url)
#3.视频详情页——返回视频的URL
def get_video_url(self,driver,num):
time.sleep(5)
if num == 1:
driver.switch_to.window(driver.window_handles[num+1])
else:
driver.switch_to.window(driver.window_handles[-1])
driver.save_screenshot("01.png")
div = driver.find_element_by_id("vs")
#print("video_div" + str(div))
time.sleep(5)
video_src = div.find_element_by_tag_name("video").get_attribute("src")
#print("video_src" + str(video_src))
return video_src
#4.下载视频
def download_video(self,num,video_src):
response = requests.get(video_src).content
with open("shipin" + str(num+1) + ".mp4", "wb") as f:
f.write(response)
#5.运行
def run(self):
#1.获取驱动
driver = self.get_driver()
#2.获取视频详情页列表
self.get_video_list_page(driver=driver)
print(str(len(self.video_url_list)))
#3.关闭底部banner页
self.close_bottom_banner(driver=driver)
#print("video_url_list"+str(self.video_url_list))
#4.点击每个视频链接
for i, video_web_url in enumerate(self.video_url_list):
driver.switch_to.window(driver.window_handles[0])
print("video_web_url" + str(i+1) +":" + str(video_web_url))
#print("url" + str(i+1) + ":" + str(self.url_list[i]))
time.sleep(10)
video_web_url.click()
#driver.execute_script("arguments[0].click();", video_web_url)
#5.获取每个视频的URL地址
video_src = self.get_video_url(driver=driver,num=i)
#6.下载url
self.download_video(num=i,video_src=video_src)
ygkp().run()
这样就能正常爬取了
四、补充:
查看视频列表长度,发现:每次只能获取7条视频。
这是因为,网站视频列表是动态加载的。每次滑动到底部会再加载新的7条视频。
如果我们要想爬取所有视频,该怎么办呢?
解决方法:先爬取最初的7条视频,然后每次爬取之前,都将网页滚动到浏览器底部,待加载出新的视频后,再次爬取。为了防止视频element有重复,可以使用set集合存放视频element。
#需求:爬取阳光宽频网的视频,下载到本地
from selenium import webdriver
import time
import requests
#阳光宽频网类
class ygkp:
video_url_list = set()
url_list = set()
#1.驱动——返回驱动driver
def get_driver(self):
# 1.selenium配置
# 1.1 设置请求头
options = webdriver.ChromeOptions()
options.add_argument("user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36")
driver = webdriver.Chrome(options=options)
return driver
#1.5 关闭底部banner页
def close_bottom_banner(self,driver):
#定位关闭按钮
close_bt = driver.find_element_by_class_name("close-banner-icon")
#点击关闭按钮
close_bt.click()
#2.视频列表页——返回视频网页链接元素列表
def get_video_list_page(self,driver):
# #2.进入网站
# driver.get("https://365yg.com/")
# time.sleep(5)
#3.获取视频详情页链接
video_div_url_list = driver.find_elements_by_class_name("title-box")
#print("video_div_url_list" + str(video_div_url_list))
for div in video_div_url_list:
#print("div" + str(div))
a = div.find_element_by_tag_name("a")
self.video_url_list.add(a)
url = a.get_attribute("href")
self.url_list.add(url)
#3.视频详情页——返回视频的URL
def get_video_url(self,driver,num):
time.sleep(5)
if num == 1:
driver.switch_to.window(driver.window_handles[num+1])
else:
driver.switch_to.window(driver.window_handles[-1])
driver.save_screenshot("01.png")
div = driver.find_element_by_id("vs")
#print("video_div" + str(div))
time.sleep(5)
video_src = div.find_element_by_tag_name("video").get_attribute("src")
#print("video_src" + str(video_src))
return video_src
#4.下载视频
def download_video(self,num,video_src):
response = requests.get(video_src).content
with open("shipin" + str(num+1) + ".mp4", "wb") as f:
f.write(response)
#5.运行
def run(self):
#1.获取驱动
driver = self.get_driver()
# 2.进入网站
driver.get("https://365yg.com/")
time.sleep(5)
# 3.关闭底部banner页
self.close_bottom_banner(driver=driver)
#2.获取视频详情页列表
for i in range(5):
self.get_video_list_page(driver=driver)
print(str(len(self.video_url_list)))
driver.execute_script("window.scrollTo(0,document.body.scrollHeight)")
time.sleep(5)
#print("video_url_list"+str(self.video_url_list))
#4.点击每个视频链接
# for i, video_web_url in enumerate(self.video_url_list):
# driver.switch_to.window(driver.window_handles[0])
# print("video_web_url" + str(i+1) +":" + str(video_web_url))
# print("url" + str(i+1) + ":" + str(self.url_list[i]))
# time.sleep(10)
# video_web_url.click()
# #driver.execute_script("arguments[0].click();", video_web_url)
# #5.获取每个视频的URL地址
# video_src = self.get_video_url(driver=driver,num=i)
# #6.下载url
# self.download_video(num=i,video_src=video_src)
ygkp().run()
运行结果:
可以看到:视频列表的长度增加了。
如果想爬取所有视频,可以将for循环改成while循环。
五:总结:
我学到了:
1.元素element定位有多种方式:
https://i.cnblogs.com/EditPosts.aspx?postid=11127907
2. 获取element的属性值:get_attribute("属性名")
3.下载视频、图片:
https://i.cnblogs.com/EditPosts.aspx?postid=11127907
4.报错:element click intercepted的原因
是由于网页上,存在页面元素相互遮挡,无法点击到目标元素
解决方法:
#方法1:
element = driver.find_element_by_css('div[class*="loadingWhiteBox"]')
driver.execute_script("arguments[0].click();", element)
#方法2:
element = driver.find_element_by_css('div[class*="loadingWhiteBox"]')
webdriver.ActionChains(driver).move_to_element(element ).click(element ).perform()
方法3:
关闭掉,遮挡元素;总之,想法设法将被遮挡的点击目标元素,露出来。
5.selenium滑动浏览器:
#移动到元素element对象的“顶端”与当前窗口的“顶部”对齐
driver.execute_script("arguments[0].scrollIntoView();", element);
driver.execute_script("arguments[0].scrollIntoView(true);", element);
#移动到元素element对象的“底端”与当前窗口的“底部”对齐
driver.execute_script("arguments[0].scrollIntoView(false);", element);
#移动到页面最底部
driver.execute_script("window.scrollTo(0, document.body.scrollHeight)");
#移动到指定的坐标(相对当前的坐标移动)
driver.execute_script("window.scrollBy(0, 700)");
#结合上面的scrollBy语句,相当于移动到700+800=1600像素位置
driver.execute_script("window.scrollBy(0, 800)");
#移动到窗口绝对位置坐标,如下移动到纵坐标1600像素位置
driver.execute_script("window.scrollTo(0, 1600)");
#结合上面的scrollTo语句,仍然移动到纵坐标1200像素位置
driver.execute_script("window.scrollTo(0, 1200)");
6.python中set集合的用法: