引子
回顾requests模块实现数据爬取的流程
--指定url
--发起请求
--获取响应数据
--持久化存储
其实,在上述流程中还需要较为重要的一步,就是在持久化存储之前需要进行指定数据解析。因为大多数情况下的需求,我们都会指定去使用聚焦爬虫,也就是爬取页面中指定部分的数据值,
而不是整个页面的数据。因此,本次课程中会给大家详细介绍讲解三种聚焦爬虫中的数据解析方式。至此,我们的数据爬取的流程可以修改为:
--指定url
--发起请求
--获取响应数据
--数据解析
--持久化存储
数据解析原理
- 解析的局部的文本内容都会在标签之间或者标签对应的属性中进行存储
1.进行指定标签的定位
2.标签或者标签对应的属性中存储的数据值进行提取(解析)
如何实现数据解析
具体有三种方式:
1. 正则表达式
2. bs4解析
3. xpath解析
下面做逐一说明。
正则表达式解析
正则解析的原理就在从整个页面的源码数据中,利用正则表达式,解析出局部想要爬取的数据,然后进行持久化存储。
import requests import re import os if not os.path.exists('./qiutuLibs'): # 如果没有这个文件夹 创建这个文件夹 os.makedirs('./qiutuLibs')
# UA伪装 headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.92 Safari/537.36' }
# 给出一个url模板 爬取第一页到第三页的图片 url = 'https://www.qiushibaike.com/imgrank/page/%d/' for i in (1,3): new_url = format(url%i) # 获取整张页面的数据 response = requests.get(url=new_url,headers=headers) page_info = response.text # 匹配得到图片的路径 ex = r'<div class="thumb">.*?<img src="(.*?)" alt=.*?</div>' # .* 贪婪匹配 .*? 惰性匹配
image_src = re.findall(ex, page_info, re.S) print(image_src) for src in image_src: fin_src = 'https:'+src fileName = fin_src.split('/')[-1] img_data = requests.get(url=fin_src).content with open('./qiutuLibs/%s'%fileName,'wb') as f: f.write(img_data) print(fin_src+'爬取完成')
ex = r'<div class="thumb">.*?<img src="(.*?)" alt=.*?</div>' """ <div class="thumb"> <a href="/article/123202082" target="_blank"> <img src="//pic.qiushibaike.com/system/pictures/12320/123202082/medium/J90RGHEXAT6L11OZ.jpg" alt="糗事#123202082" class="illustration" width="100%" height="auto"> </a> </div> """
bs4解析
环境安装
- 需要将pip源设置为国内源,阿里源、豆瓣源、网易源等 - windows (1)打开文件资源管理器(文件夹地址栏中) (2)地址栏上面输入 %appdata% (3)在这里面新建一个文件夹 pip (4)在pip文件夹里面新建一个文件叫做 pip.ini ,内容写如下即可 [global] timeout = 6000 index-url = https://mirrors.aliyun.com/pypi/simple/ trusted-host = mirrors.aliyun.com - linux (1)cd ~ (2)mkdir ~/.pip (3)vi ~/.pip/pip.conf (4)编辑内容,和windows一模一样 - 需要安装:pip install bs4 bs4在使用时候需要一个第三方库,把这个库也安装一下 pip install lxml
- 数据解析的原理:
- 1.标签定位
- 2.提取标签、标签属性中存储的数据值
- bs4数据解析的原理:
- 1.实例化一个BeautifulSoup对象,并且将页面源码数据加载到该对象中
- 2.通过调用BeautifulSoup对象中相关的属性或者方法进行标签定位和数据提取
基础使用
使用流程: - 导包:from bs4 import BeautifulSoup - 使用方式:可以将一个html文档,转化为BeautifulSoup对象,然后通过对象的方法或者属性去查找指定的节点内容 (1)转化本地文件: - soup = BeautifulSoup(open('本地文件'), 'lxml') (2)转化网络文件: - soup = BeautifulSoup('字符串类型或者字节类型', 'lxml') (3)打印soup对象显示内容为html文件中的内容 基础巩固: (1)根据标签名查找 - soup.a 只能找到第一个符合要求的标签 (2)获取属性 - soup.a.attrs 获取a所有的属性和属性值,返回一个字典 - soup.a.attrs['href'] 获取href属性 - soup.a['href'] 也可简写为这种形式 (3)获取内容 - soup.a.string - soup.a.text - soup.a.get_text() 【注意】如果标签还有标签,那么string获取到的结果为None,而其它两个,可以获取文本内容 (4)find:找到第一个符合要求的标签 - soup.find('a') 找到第一个符合要求的 - soup.find('a', title="xxx") - soup.find('a', alt="xxx") - soup.find('a', class_="xxx") - soup.find('a', id="xxx") (5)find_all:找到所有符合要求的标签 - soup.find_all('a') - soup.find_all(['a','b']) 找到所有的a和b标签 - soup.find_all('a', limit=2) 限制前两个 (6)根据选择器选择指定的内容 select:soup.select('#feng') - 常见的选择器:标签选择器(a)、类选择器(.)、id选择器(#)、层级选择器 - 层级选择器: div .dudu #lala .meme .xixi 下面好多级 div > p > a > .lala 只能是下面一级 【注意】select选择器返回永远是列表,需要通过下标提取指定的对象
示例:爬取诗词名句网关于三国演义的所有章节信息
import requests from bs4 import BeautifulSoup if __name__=='__main__': url = 'http://www.shicimingju.com/book/sanguoyanyi.html' headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.92 Safari/537.36' } page_text = requests.get(url=url, headers=headers).text soup = BeautifulSoup(page_text,'lxml') # 使用lxml编译器 title_list = soup.select('.book-mulu ul li a') # 层级选择标签 fileName = 'sanguo' f = open('%s.html'%fileName,'w',encoding='utf-8') for title in title_list: # 文章标题 content_title = title.text # 详情src src = title['href'] # 获取href属性 # 完整src content_src = 'http://www.shicimingju.com' + src # 详情内容 detail_page = requests.get(url=content_src, headers=headers).text soup = BeautifulSoup(detail_page, 'lxml') # 将页面文本对象加入解析器 # 所有的文本数据 detail_content = soup.find('div', class_='chapter_content').text # 获取div标签下所有的文本数据 f.write(content_title+' '+detail_content) print(content_title+'爬取完成')
xpath解析(使用最多)
- xpath解析原理:
- 1.实例化一个etree的对象,且需要将被解析的页面源码数据加载到该对象中。
- 2.调用etree对象中的xpath方法结合着xpath表达式实现标签的定位和内容的捕获。
常用的xpath表达式
属性定位: #找到class属性值为song的div标签 //div[@class="song"] 层级&索引定位: #找到class属性值为tang的div的直系子标签ul下的第二个子标签li下的直系子标签a //div[@class="tang"]/ul/li[2]/a 逻辑运算: #找到href属性值为空且class属性值为du的a标签 //a[@href="" and @class="du"] 模糊匹配: //div[contains(@class, "ng")] //div[starts-with(@class, "ta")] 取文本: # /表示获取某个标签下的文本内容 # //表示获取某个标签下的文本内容和所有子标签下的文本内容 //div[@class="song"]/p[1]/text() //div[@class="tang"]//text() 取属性: //div[@class="tang"]//li[2]/a/@href
etree对象实例化
如何实例化一个etree对象:from lxml import etree
- 1.将本地的html文档中的源码数据加载到etree对象中:
etree.parse(filePath)
- 2.可以将从互联网上获取的源码数据加载到该对象中
etree.HTML('page_text')
- xpath('xpath表达式')
示例:爬取58同城二手房的信息
import requests from lxml import etree url = 'https://bj.58.com/ershoufang/' header={ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.92 Safari/537.36' } page_text = requests.get(url=url, headers=header).text # 获取网页的所有数据 tree = etree.HTML(page_text) # 生成etree对象 li_list = tree.xpath("//div[@class='content-side-left']/ul/li") # 标签定位 # xpath返回的是一个列表 f = open('58house.html','w',encoding='utf-8') for li in li_list: house_title = li.xpath('./div[2]//a/text()')[0] house_price = li.xpath('./div[3]/p//text()')[0] # 局部查找该起始元素用./表示 house_meter_price = li.xpath('./div[3]/p//text()')[2] f.write('房型:'+house_title+'-------'+'价格:'+house_price+'万'+' 每平米:'+house_meter_price+' ') f.close() print('爬取完成')