三种数据解析方式
数据解析方式之一:xpath
使用流程:
- 下载:pip install lxml
- 导包:from lxml import etree
- 创建etree对象进行指定数据的解析
本地:etree=etree.parse('本地文件路径')
etree.xpath('xpath表达式')
网络:etree=etree.HTML('网络请求到的页面数据')
etree.xpath('xpath表达式')
xpath插件:火狐浏览器右上角——>附加组件——>搜索Try XPath——>添加即可!
案例:
test.html
<html lang="en"> <head> <meta charset="UTF-8" /> <title>测试</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>
xpath语法练习:
from lxml import etree #xpath函数返回的总是一个列表 #创建etree对象进行指定数据解析 tree = etree.parse('./test.html')#./表示当前路径 #属性定位:根据指定的属性定位到指定的节点标签 #tree.xpath('//div[@class="song"] ')#//表示相对路径,所有子代节点,不用考虑是否直接子节点 #层级索引定位 #tree.xpath('//div[@class="tang"]/ul/li[2]/a') #逻辑定位 #tree.xpath('//a[@href="" and @class="du"]') #模糊查询 #tree.xpath('//div[contains(@class, "ng")]') #tree.xpath('//div[starts-with(@class, "ta")]') #取文本 #tree.xpath('//div[@class="song"]/p[1]/text()') #/text()获取当前标签中直系存储的文本数据 #tree.xpath('//div[@class="tang"]//text()') #//text()获取某一个标签下所有子标签中存储的文本数据 #取属性 # tree.xpath('//div[@class="tang"]//li[2]/a/@href') #/表示绝对路径,从根节点选取 #.表示选取当前节点 #..表示选取当前节点的父节点 #@表示 选取属性
需求:利用xpath爬取经典段子网内容
1 import requests 2 from lxml import etree 3 #指定url 4 url='https://ishuo.cn/yulu' 5 #自定义头信息 6 headers = { 7 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.221 Safari/537.36 SE 2.X MetaSr 1.0' 8 } 9 #发起get请求,返回响应对象 10 response=requests.get(url=url,headers=headers) 11 #获取页面数据 12 page_data=response.text 13 #数据解析 14 tree=etree.HTML(page_data) 15 #注:Element类型的对象可以继续调用xpath函数,对该对象表示的局部内容进行指定内容的解析 16 li_list=tree.xpath('//div[@id="content"]/div[2]/ul/li') 17 #不要把文件放在循环体内,浪费资源 18 f=open('./duan.txt','w',encoding='utf-8') 19 for li in li_list: 20 content=li.xpath('./div[@class="content"]//text()')[0] 21 f.write(content+'\n\n')
数据解析之二:正则表达式
常用正则练习:
#提取出python key="javapythonc++php" re.findall('python',key)[0] #提取出hello world key="<html><h1>hello world<h1></html>" re.findall('<h1>hello world<h1>',key)[0] #提取170 string = '我喜欢身高为170的女孩' re.findall('\d+',string) #提取出http://和https:// key='http://www.baidu.com and https://boob.com' re.findall('https{0,1}',key) #提取出hit. key='bobo@hit.edu.com' re.findall('h.*?\.',key) #贪婪模式:根据正则表达式尽可能多的提取出数据 #匹配sas和saas key='saas and sas and saaas' re.findall('sa{1,2}s',key) #匹配出i开头的行 re.S(基于单行) re.M(基于多行) string = '''fall in love with you i love you very much i love she i love her''' re.findall('^i.*',string,re.M) #匹配全部行 string = """<div>静夜思 窗前明月光 疑是地上霜 举头望明月 低头思故乡 </div>""" re.findall('<div>.*</div>',string,re.S)
练习:需求是使用正则对糗事百科的图片数据下载
1 import requests 2 import re 3 import os 4 #指定url 5 url = 'https://www.qiushibaike.com/pic/' 6 headers={ 7 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36', 8 } 9 #发起请求 10 response = requests.get(url=url,headers=headers) 11 #获取页面数据 12 page_text = response.text 13 #数据解析(该列表中存储的就是当前页面源码中所有的图片链接) 14 img_list = re.findall('<div class="thumb">.*?<img src="(.*?)".*?>.*?</div>',page_text,re.S) 15 #创建一个存储图片数据的文件夹 16 if not os.path.exists('./imgs'): 17 os.mkdir('imgs') 18 for url in img_list: 19 #将图片的url进行拼接,拼接成一个完成的url 20 img_url = 'https:' + url 21 #持久化存储:存储的是图片的数据,并不是url。 22 #获取图片二进制的数据值 23 img_data = requests.get(url=img_url,headers=headers).content 24 imgName = url.split('/')[-1] 25 imgPath = 'imgs/'+imgName 26 with open(imgPath,'wb') as fp: 27 fp.write(img_data) 28 print(imgName+'写入成功')
数据解析之三:BS4
python独有。简单便捷和高效。
环境安装:
需要将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
需要安装:pip install bs4
bs4在使用时候需要一个第三方库,把这个库也安装一下 pip install lxml
代码的使用流程:将html文档转换成Beautiful对象,然后调用该对象中的属性和方法进行html文档指定内容的定位查找。
导包:from bs4 import BeautifulSoup 创建Beautiful对象:
如果html文档的来源是来源于本地:
Beautiful('open('本地的html文件')','lxml')
如果html是来源于网络
Beautiful(‘网络请求到的页面数据’,‘lxml’)
属性和方法:
(1)根据标签名查找
- soup.a 只能找到第一个符合要求的标签
(2)获取属性
- soup.a.attrs 获取a所有的属性和属性值,返回一个字典
- soup.a.attrs['href'] 获取href属性
- soup.a['href'] 也可简写为这种形式
(3)获取内容
- soup.a.string /text()
- soup.a.text //text()
- soup.a.get_text() //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//img
div > p > a > .lala 只能是下面一级 div/img
【注意】select选择器返回永远是列表,需要通过下标提取指定的对象
BS4语法练习:
from bs4 import BeautifulSoup fp = open('text.html') soup = BeautifulSoup(fp,'lxml') #根据标签名进行查找 #soup.div #获取标签属性值 #soup.a['href'] #获取内容 #soup.p.string #获取符合要求的标签 #soup.find('div',class_="tang") #soup.findAll('a',limit=2) #select函数的层级选择器: #soup.select('div li')
练习:需求是利用BS4爬取古诗文网中三国小说的标题和内容
1 import requests 2 from bs4 import BeautifulSoup 3 url = 'http://www.shicimingju.com/book/sanguoyanyi.html' 4 headers={ 5 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36', 6 } 7 #根据url获取页面内容中指定的标题所对应的文章内容 8 def get_content(url): 9 content_page = requests.get(url=url,headers=headers).text 10 soup = BeautifulSoup(content_page,'lxml') 11 div = soup.find('div',class_='chapter_content') 12 return div.text 13 page_text = requests.get(url=url,headers=headers).text 14 #数据解析 15 soup = BeautifulSoup(page_text,'lxml') 16 #a_list列表中存储的是一系列的a标签对象 17 a_list = soup.select('.book-mulu > ul > li > a') 18 #type(a_list[0]) 19 #注意:Tag类型的对象可以继续调用响应的解析属性和方法进行局部数据的解析 20 fp = open('./sanguo.txt','w',encoding='utf-8') 21 for a in a_list: 22 #获取了章节的标题 23 title = a.string 24 content_url = 'http://www.shicimingju.com'+a['href'] 25 print(content_url) 26 #获取章节的内容 27 content = get_content(content_url) 28 fp.write(title+':'+content+"\n\n\n") 29 print('写入一个章节内容')