Python网络爬虫之图片懒加载技术、selenium和PhantomJS
一.图片懒加载
-
图片懒加载概念:
-
图片懒加载是一种网页优化技术。图片作为一种网络资源,在被请求时也与普通静态资源一样,将占用网络资源,而一次性将整个页面的所有图片加载完,将大大增加页面的首屏加载时间。为了解决这种问题,通过前后端配合,使图片仅在浏览器当前视窗内出现时才加载该图片,达到减少首屏图片请求数的技术就被称为“图片懒加载”。
-
-
网站一般如何实现图片懒加载技术呢?
-
在网页源码中,在img标签中首先会使用一个“伪属性”(通常使用src2,original......)去存放真正的图片链接而并非是直接存放在src属性中。当图片出现到页面的可视化区域中,会动态将伪属性替换成src属性,完成图片的加载。
-
案例:
爬取站长素材高清图片
通过细致观察页面的结构后发现,网页中图片的链接是存储在了src2这个伪属性中
# 爬取站长素材中的高清图片 import requests from lxml import etree from urllib import request import re url = "http://sc.chinaz.com/tupian/fengjingtupian.html" headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.12 Safari/537.36' } page_text = requests.get(url,headers=headers).text tree = etree.HTML(page_text) # 图片懒加载概念,网页优化技术 # 当图片被拖动到可视化区域时src2伪属性才会变成真正的属性值,requests请求没有可视话界面要取伪属性 img_src_list = tree.xpath("//div[@id='container']/div/div/a/img/@src2") for src in img_src_list: imgName = src.split("/")[-1] # 请求图片地址,并保存图片 request.urlretrieve(src,imgName)
二.selenium
- 什么是selenium?
-
是Python的一个第三方库,对外提供的接口可以操作浏览器,然后让浏览器完成自动化的操作。
-
-
环境搭建
-
安装selenum:pip install selenium
-
获取某一款浏览器的驱动程序(以谷歌浏览器为例)
-
谷歌浏览器驱动下载地址:
http://chromedriver.storage.googleapis.com/index.html
-
下载的驱动程序必须和浏览器的版本统一,可以根据
http://blog.csdn.net/huilan_same/article/details/51896672中提供的版本映射表进行对应
-
-
编码流程:
- 导包
- 创建某一款浏览器对象
- 制定相关的行为动作
案例:
豆瓣top榜
from selenium import webdriver from time import sleep
bro = webdriver.Chrome(executable_path=r'D:\爬虫+数据分析\tools\chromedriver.exe') # 谷歌浏览器驱动路径 bro.get('https://movie.douban.com/typerank?type_name=%E7%88%B1%E6%83%85&type=13&interval_id=100:90&action=') sleep(3) bro.execute_script('window.scrollTo(0,document.body.scrollHeight)') # 页面滚动一屏,让动态数据加载出来 sleep(3) bro.execute_script('window.scrollTo(0,document.body.scrollHeight)') sleep(3) bro.execute_script('window.scrollTo(0,document.body.scrollHeight)') #获取浏览器当前的页面源码数据 page_text = bro.page_source with open('douban.html','w',encoding='utf-8') as fp: fp.write(page_text) sleep(3) bro.quit()
自动登录qq空间:
# 自动操作浏览器 bro = webdriver.Chrome(executable_path=r'D:\爬虫+数据分析\tools\chromedriver.exe') bro.get('https://qzone.qq.com/') sleep(3) #注意:如果想要通过find系列函数去定位某一个iframe标签下的子标签的话,一定要使用如下操作: bro.switch_to.frame('login_frame')#参数表示的是iframe标签的id属性值,,ifram是子标签 bro.find_element_by_id('switcher_plogin').click() # 单击id为switcher_plogin的页面标签,即点击账号密码登录 sleep(3) # 自动输入用户名,密码登录空间 bro.find_element_by_id('u').send_keys('qq号') bro.find_element_by_id('p').send_keys('pwd') sleep(3) bro.find_element_by_id('login_button').click() print(bro.page_source) sleep(3) bro.quit()
selenium的几种等待方式:
https://www.cnblogs.com/superbaby11/p/15702858.html
主要用显示等待:
from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By from selenium import webdriver from time import sleep def spider(): restart_count = 0 while restart_count < 5: # 有界面操作 driver = webdriver.Chrome() # 无界面操作 # driver = webdriver.Chrome(executable_path=utils.CHROM_DRIVER_PATH, chrome_options=chrome_options) driver.get('https://ncdex.com/markets/spotprices') locator = (By.ID, 'select2-symbol-contain') # 指定首页操作需要加载出的元素 try: WebDriverWait(driver, 30, 1).until(EC.visibility_of_element_located(locator)) except Exception as e: driver.close() print(f"30秒内加载失败, 第{restart_count}次重试") restart_count += 1 continue sleep(0.2)
## 等待元素出现与消失
from selenium.common.exceptions import TimeoutException from selenium.webdriver.common.by import By import selenium.webdriver.support.expected_conditions as EC import selenium.webdriver.support.ui as ui # 一直等待某元素可见,默认超时10秒 def is_visible(locator, timeout=10): try: ui.WebDriverWait(driver, timeout).until(EC.visibility_of_element_located((By.XPATH, locator))) return True except TimeoutException: return False # 一直等待某个元素消失,默认超时10秒 def is_not_visible(locator, timeout=10): try: ui.WebDriverWait(driver, timeout).until_not(EC.visibility_of_element_located((By.XPATH, locator))) return True except TimeoutException: return False
### EC的各种方法 title_is: 判断当前页面的title是否完全等于(==)预期字符串,返回布尔值 title_contains : 判断当前页面的title是否包含预期字符串,返回布尔值 presence_of_element_located : 判断某个元素是否被加到了dom树里,并不代表该元素一定可见 visibility_of_element_located : 判断某个元素是否可见. 可见代表元素非隐藏,并且元素的宽和高都不等于0 visibility_of : 跟上面的方法做一样的事情,只是上面的方法要传入locator,这个方法直接传定位到的element就好了 presence_of_all_elements_located : 判断是否至少有1个元素存在于dom树中。举个例子,如果页面上有n个元素的class都是‘column-md-3‘,那么只要有1个元素存在,这个方法就返回True text_to_be_present_in_element : 判断某个元素中的text是否 包含 了预期的字符串 text_to_be_present_in_element_value : 判断某个元素中的value属性是否 包含 了预期的字符串 frame_to_be_available_and_switch_to_it : 判断该frame是否可以switch进去,如果可以的话,返回True并且switch进去,否则返回False invisibility_of_element_located : 判断某个元素中是否不存在于dom树或不可见 element_to_be_clickable : 判断某个元素中是否可见并且是enable的,这样的话才叫clickable staleness_of : 等某个元素从dom树中移除,注意,这个方法也是返回True或False element_to_be_selected : 判断某个元素是否被选中了,一般用在下拉列表 element_selection_state_to_be : 判断某个元素的选中状态是否符合预期 element_located_selection_state_to_be : 跟上面的方法作用一样,只是上面的方法传入定位到的element,而这个方法传入locator alert_is_present : 判断页面上是否存在alert
谷歌无图浏览器
--获取百度搜索关键字的返回页
from selenium.webdriver.chrome.options import Options chrome_options = Options() chrome_options.add_argument('--headless') chrome_options.add_argument('--disable-gpu') # 带上这个参数chrome_options=chrome_options 自动操作浏览器wu界面操作 bro = webdriver.Chrome(executable_path=r'D:\爬虫+数据分析\tools\chromedriver.exe',chrome_options=chrome_options) sleep(3) bro.get('https://www.baidu.com/') sleep(3) #find系列的函数可以帮助我们定位到相关的标签 text_input = bro.find_element_by_id('kw') #向文本框中录入一个关键字 text_input.send_keys('中国') sleep(3) btn = bro.find_element_by_id('su') btn.click() sleep(3) #获取当前浏览器显示的页面源码数据(动态加载的数据) page_text = bro.page_source print(page_text) bro.quit()
三.phantomJs
PhantomJS是一款无界面的浏览器,其自动化操作流程和上述操作谷歌浏览器是一致的。由于是无界面的,为了能够展示自动化操作流程,PhantomJS为用户提供了一个截屏的功能,使用save_screenshot函数实现。
- phantomJs:浏览器(无可视化界面)
- 使用方便,只需要有对应文件夹就有了环境,无需安装
----selenium+phantomjs 就是爬虫终极解决方案:有些网站上的内容信息是通过动态加载js形成的,所以使用普通爬虫程序无法回去动态加载的js内容。例如豆瓣电影中的电影信息是通过下拉操作动态加载更多的电影信息。
#爬取更多的电影详情数据(豆瓣) bro = webdriver.PhantomJS(executable_path=r"F:\learn\python爬虫\爬虫+数据,依赖环境\tools\phantomjs-2.1.1-windows\bin\phantomjs.exe") bro.get('https://movie.douban.com/typerank?type_name=%E7%88%B1%E6%83%85&type=13&interval_id=100:90&action=') sleep(3) bro.save_screenshot('./1.png') bro.execute_script('window.scrollTo(0,document.body.scrollHeight)') sleep(3) bro.execute_script('window.scrollTo(0,document.body.scrollHeight)') sleep(3) bro.execute_script('window.scrollTo(0,document.body.scrollHeight)') bro.save_screenshot('./2.png')
expected_conditions