数据解析
数据解析
概念:
将一整张页面中的局部数据进行提取/解析
作用:
用来实现聚焦爬虫
实现方式:
正则
bs4
xpath
pyquery
数据解析的通用原理
标签的定位
数据的提取
页面中的相关的字符串的数据的存储位置
标签中间
标签的属性中
基于聚焦爬虫的编码流程
指定url
发起请求
获取响应数据
数据解析
持久化存储
爬取图片数据
- 基于requests|
- 基于urllib
- 区别:urllib中的urlretrieve不可以进行UA伪装(headers)
import requests headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36' }
requests
#基于requests的图片爬取 url ='http://pic.netbian.com/uploads/allimg/180128/113416-1517110456633d.jpg' img_data = requests.get(url,headers=headers).content with open('./123.jpg','wb') as fp: fp.write(img_data)
urllib
#基于urllib的图片爬取 from urllib import request url ='http://pic.netbian.com/uploads/allimg/180128/113416-1517110456633d.jpg' request.urlretrieve(url,'./456.jpg')
正则解析
将煎蛋网中的图片数据进行爬取且存储在本地
import requests from urllib import request #正则匹配 import re import os dirName = './imgLibs' if not os.path.exists(dirName): os.mkdir(dirName) url = 'http://jandan.net/pic/MjAxOTEwMDktNjY=#comments' page_text = requests.get(url,headers=headers).text #解析数据:img标签的src的属性值 ex = '<div class="text">.*?<img src="(.*?)" referrerPolicy.*?</div>' img_src_list = re.findall(ex,page_text,re.S) for src in img_src_list: if 'org_src' in src: src = re.findall('org_src="(.*?)" onload',src)[0] src = 'http:'+src imgName = src.split('/')[-1] imgPath = dirName+'/'+imgName request.urlretrieve(src,imgPath) print(imgName,'下载成功!!!')
bs4
环境的安装:
pip install bs4
pip install lxml # lxml解释器
bs4的解析原理:
实例化一个BeautifulSoup的一个对象,把即将被解析的页面源码数据加载到该对象中
需要调用BeautifulSoup对象中的相关的方法和属性进行标签定位和数据的提取
BeautifulSoup的实例化
BeautifulSoup(fp,'lxml'):将本地存储的html文档中的页面源码数据加载到该对象中 (fp文件句柄,lxml解释器)
BeautifulSoup(page_text,'lxml'):将从互联网中请求道的页面源码数据加载到改对象中 (page_text网络源码)
标签的定位
soup.tagName:只可以定位到第一个tagName标签
属性定位:soup.find('tagName',attrName='value'),只可以定位到符合要求的第一个标签
- findAll:返回值是一个列表。可以定位到符合要求的所有标签 class在这里要class_
选择器定位:soup.select('选择器')
- 选择器:id,class,tag,层级选择器(大于号表示一个层级,空格表示多个层级)
取文本
text:将标签中所有的文本取出
string:将标签中直系的文本取出
取属性
tag['attrName']
例子
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<html lang="en"> <head> <meta charset="UTF-8" /> <title>测试bs4</title> </head> <body> <div> <p>百里守约</p> </div> <div class="song"> <p>李清照</p> <p>王安石</p> <p>苏轼</p> <p>柳宗元</p> <a href="http://www.song.com/" title="赵匡胤" target="_self"> <span>this is span</span> 宋朝是最强大的王朝,不是军队的强大,而是经济很强大,国民都很有钱</a> <a href="" class="du">总为浮云能蔽日,长安不见使人愁</a> <img src="http://www.baidu.com/meinv.jpg" alt="" /> </div> <div class="tang"> <ul> <li><a href="http://www.baidu.com" title="qing">清明时节雨纷纷,路上行人欲断魂,借问酒家何处有,牧童遥指杏花村</a></li> <li><a href="http://www.163.com" title="qin">秦时明月汉时关,万里长征人未还,但使龙城飞将在,不教胡马度阴山</a></li> <li><a href="http://www.126.com" alt="qi">岐王宅里寻常见,崔九堂前几度闻,正是江南好风景,落花时节又逢君</a></li> <li><a href="http://www.sina.com" class="du">杜甫</a></li> <li><a href="http://www.dudu.com" class="du">杜牧</a></li> <li><b>杜小月</b></li> <li><i>度蜜月</i></li> <li><a href="http://www.haha.com" id="feng">凤凰台上凤凰游,凤去台空江自流,吴宫花草埋幽径,晋代衣冠成古丘</a></li> </ul> </div> </body> </html>
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
# bs4 from bs4 import BeautifulSoup fp = open('./text.html',encoding='utf-8') soup = BeautifulSoup(fp,'lxml') # soup.find('div',class_='song') # soup.select('#feng')[0] # soup.select('.tang > ul > li > a') # soup.select('.tang li > a') # soup.select('.tang a') # tag = soup.b # tag.string # div_tag = soup.find('div',class_='tang') # div_tag.text # a_tag = soup.select('#feng')[0] # a_tag['href']
三国演义例子
需求:使用bs4解析三国演义小说的标题和内容,存储到本地
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
main_url = 'http://www.shicimingju.com/book/sanguoyanyi.html' page_text = requests.get(url=main_url,headers=headers).text #数据解析:章节的标题和详情页的url soup = BeautifulSoup(page_text,'lxml') a_list = soup.select('.book-mulu > ul > li > a') fp = open('./sanguo.txt','w',encoding='utf-8') for a in a_list: title = a.string detail_url = 'http://www.shicimingju.com'+a['href'] detail_page_text = requests.get(url=detail_url,headers=headers).text #数据解析:章节内容 detail_soup = BeautifulSoup(detail_page_text,'lxml') div_tag = detail_soup.find('div',class_='chapter_content') content = div_tag.text fp.write(title+':'+content+'\n') print(title,'写入成功!!!') fp.close()
xpath解析
环境的安装
pip install lxml
解析原理
实例化一个etree的对象,且把即将被解析的页面源码数据加载到该对象中
调用etree对象中的xpath方法结合这不同形式的xpath表达式进行标签定位和数据提取
etree对象的实例化
etree.parse('fileName') 本地文件
etree.HTML(page_text) 网页源码
标签定位
最左侧的/:一定要从根标签开始进行标签定位
非最左侧的/:表示一个层级
最左侧的//:可以从任意位置进行指定标签的定位
非最左侧的//:表示多个层级
属性定位://tagName[@attrName="value"]
索引定位://tagName[@attrName="value"]/li[2],索引是从1开始
逻辑运算:
找到href属性值为空且class属性值为du的a标签
//a[@href="" and @class="du"]
模糊匹配:
//div[contains(@class, "ng")]
//div[starts-with(@class, "ta")]
取文本
/text():直系的文本内容
//text():所有的文本内容
取属性
/@attrName
例子
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<html lang="en"> <head> <meta charset="UTF-8" /> <title>测试bs4</title> </head> <body> <div> <p>百里守约</p> </div> <div class="song"> <p>李清照</p> <p>王安石</p> <p>苏轼</p> <p>柳宗元</p> <a href="http://www.song.com/" title="赵匡胤" target="_self"> <span>this is span</span> 宋朝是最强大的王朝,不是军队的强大,而是经济很强大,国民都很有钱</a> <a href="" class="du">总为浮云能蔽日,长安不见使人愁</a> <img src="http://www.baidu.com/meinv.jpg" alt="" /> </div> <div class="tang"> <ul> <li><a href="http://www.baidu.com" title="qing">清明时节雨纷纷,路上行人欲断魂,借问酒家何处有,牧童遥指杏花村</a></li> <li><a href="http://www.163.com" title="qin">秦时明月汉时关,万里长征人未还,但使龙城飞将在,不教胡马度阴山</a></li> <li><a href="http://www.126.com" alt="qi">岐王宅里寻常见,崔九堂前几度闻,正是江南好风景,落花时节又逢君</a></li> <li><a href="http://www.sina.com" class="du">杜甫</a></li> <li><a href="http://www.dudu.com" class="du">杜牧</a></li> <li><b>杜小月</b></li> <li><i>度蜜月</i></li> <li><a href="http://www.haha.com" id="feng">凤凰台上凤凰游,凤去台空江自流,吴宫花草埋幽径,晋代衣冠成古丘</a></li> </ul> </div> </body> </html>
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
from lxml import etree tree = etree.parse('./text.html') # tree.xpath('/html//title') # tree.xpath('//div') # tree.xpath('//div[@class="tang"]') # tree.xpath('//div[@class="tang"]/ul/li[2]') # tree.xpath('//p[1]/text()') # tree.xpath('//div[@class="song"]//text()') tree.xpath('//img/@src')[0]
虎牙案例查看
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
url = 'https://www.huya.com/g/xingxiu' page_text = requests.get(url=url,headers=headers).text # 数据解析 tree = etree.HTML(page_text) li_list = tree.xpath('//div[@class="box-bd"]/ul/li') for li in li_list: #实现的是页面局部数据的指定数据的解析 title = li.xpath('./a[2]/text()')[0] author = li.xpath('./span/span[1]/i/text()')[0] hot = li.xpath('./span/span[2]/i[2]/text()')[0] print(title,author,hot)
爬取http://pic.netbian.com/4kmeinv/中前五页的图片数据
中文乱码的处理 多页码数据的爬取
将乱码的内容(img_name)转码
img_name.encode('iso-8859-1').decode('gbk')+'.jpg'
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
# url = 'http://pic.netbian.com/4kmeinv/' #第一页 #指定一个通用的url模板:不可变的 url = 'http://pic.netbian.com/4kmeinv/index_%d.html' dirName = './MZLib' if not os.path.exists(dirName): os.mkdir(dirName) for page in range(1,6): if page == 1: new_url = 'http://pic.netbian.com/4kmeinv/' else: new_url = format(url%page) page_text = requests.get(url=new_url,headers=headers).text #数据解析:图片地址&图片名称 tree = etree.HTML(page_text) li_list = tree.xpath('//div[@class="slist"]/ul/li') for li in li_list: img_name = li.xpath('./a/img/@alt')[0] img_name = img_name.encode('iso-8859-1').decode('gbk')+'.jpg' img_src = 'http://pic.netbian.com'+li.xpath('./a/img/@src')[0] img_data = requests.get(img_src,headers=headers).content #图片的二进制类型数据 img_path = dirName+'/'+img_name with open(img_path,'wb') as fp: fp.write(img_data) print('第{}页爬取完毕!!!'.format(page))
爬取全国城市的名称 https://www.aqistudy.cn/historydata/
tree.xpath( I ) 可以加管道符来增加条件
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
url = 'https://www.aqistudy.cn/historydata/' page_text = requests.get(url,headers=headers).text tree = etree.HTML(page_text) # hot_cities = tree.xpath('//div[@class="bottom"]/ul/li/a/text()') # all_cities = tree.xpath('//div[@class="bottom"]/ul/div[2]/li/a/text()') tree.xpath('//div[@class="bottom"]/ul/div[2]/li/a/text() | //div[@class="bottom"]/ul/li/a/text()')
小结:
1.你是如何理解数据解析的? 就是将一张页面源码中的局部的数据进行提取 2.在爬虫中有哪些实现数据解析的方式?
正则
bs4
xpath
pyquery 3.数据解析的作用是什么?
用来实现聚焦爬虫 4.数据解析的通用原理是什么?
标签的定位
数据的提取 5.bs4实现的数据解析中常用的方法和属性有哪些?各自的作用是什么? soup.tagName find/findAll() select() text/string tag['attrName] 6.写出常用的xpath表达式? 属性定位 索引定位 取文本 取属性