一.数据解析的方式
- re(正则)
- bs4
- xpath
二.数据解析的目的
精准获取我们在网页中想得到的数据
三.re(正则)方式解析数据
1.爬取爬取糗事百科中所有的糗图图片数据
import os
import requests
import re
from urllib import request
if not os.path.exists('./qiutu'):
os.mkdir('./qiutu')
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36'
}
url = 'https://www.qiushibaike.com/pic/'
page_text = requests.get(url=url,headers=headers).text
#这里使用了正则,将要爬取的内容用()包住,如果有多个括号返回元组
ex = '<div class="thumb">.*?<img src="(.*?)" alt.*?</div>'
#下面的re.S表示.也匹配换行符等一些字符,不加不行!
img_url = re.findall(ex,page_text,re.S)
for url in img_url:
url = 'https:'+url
img_name = url.split('/')[-1]
img_path = './qiutu/'+img_name
request.urlretrieve(url,img_path)
print(img_name,'下载成功!!!')
2.正则基础回顾
单字符:
. : 除换行以外所有字符
[] :[aoe] [a-w] 匹配集合中任意一个字符
\d :数字 [0-9]
\D : 非数字
\w :数字、字母、下划线、中文
\W : 非\w
\s :所有的空白字符包,括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。
\S : 非空白
数量修饰:
* : 任意多次 >=0
+ : 至少1次 >=1
? : 可有可无 0次或者1次
{m} :固定m次 hello{3,}
{m,} :至少m次
{m,n} :m-n次
边界:
$ : 以某某结尾
^ : 以某某开头
分组:
(ab)
贪婪模式: .*
非贪婪(惰性)模式: .*?
re.I : 忽略大小写
re.M :多行匹配
re.S :单行匹配
re.sub(正则表达式, 替换内容, 字符串)
三.bs4模块解析
1.原理
- 实例化一个Beautifulsoup的对象,且将页面源码数据加载到该对象中
- 使用该对象的相关属性和方法实现标签定位和数据提取
2.安装
pip install bs4
pip install lxml
3.实例化Beautifulsoup对象
i.文件
需要拿到文件句柄
fp = open("a.html","r",encoding="utf8")
BeautifulSoup(fp,'lxml')
ii.字符串
BeautifulSoup(page_text,'lxml'):
4.find方法
find只能找到符合要求的第一个标签,他返回的是一个对象
soup.find('a')
soup.find('a', class_='xxx')
soup.find('a', title='xxx')
soup.find('a', id='xxx')
soup.find('a', id=re.compile(r'xxx'))
5.find_all方法
返回一个列表,列表里面是所有的符合要求的对象
soup.find_all('a')
soup.find_all('a', class_='wang')
soup.find_all('a', id=re.compile(r'xxx'))
soup.find_all('a', limit=2) #提取出前两个符合要求的a
6.select方法
使用类似css选择器方式获得元素
i.常用的选择器
1.层级选择器**
div h1 a 后面的是前面的子节点即可
div > h1 > a 后面的必须是前面的直接子节点
2.属性选择器 input[name=‘hehe’]
select('选择器的')#返回的是一个列表,列表里面都是对象
#find find_all select不仅适用于soup对象,还适用于其他的子对象,如果调用子对象的select方法,那么就是从这个子对象里面去找符合这个选择器的标签
ii.不适用伪元素原则器
我们要获得ul第一个li时,不能使用:first-child,应该用
select("ul li")[0]
7.获取标签属性和文本
-
属性
soup.a.attrs["href"] #返回一字典,里面是所有属性和值 soup.a['href'] #获取href属性,不使用
-
文本
soup.a.string #当前元素的文本 soup.a.text #包括子元素和当前元素的文本 soup.a.get_text()#包括子元素和当前元素的文本
8.爬取古诗文网的三国演义小说
url = 'http://www.shicimingju.com/book/sanguoyanyi.html'
page_text = requests.get(url=url,headers=headers).text
#数据解析:标题和url
soup = BeautifulSoup(page_text,'lxml')
li_list = soup.select('.book-mulu > ul > li')
fp = open('./sanguo.txt','w',encoding='utf-8')
for li in li_list:
title = li.a.string
detail_url = 'http://www.shicimingju.com'+li.a['href']
#单独对详情页发起请求获取源码数据
detail_page_text = requests.get(url=detail_url,headers=headers).text
soup = BeautifulSoup(detail_page_text,'lxml')
content = soup.find('div',class_="chapter_content").text
fp.write(title+'\n'+content+'\n')
print(title,':下载成功!')
fp.close()
四.xpath解析
1.特性
- 解析效率比较高
- 通用性最强,适用于其他语言
- 普遍使用的方式(最重要)
2.安装
pip install lxml
3.解析原理
- 实例化一个etree对象且将即将被解析的页面源码数据加载到该对象中
- 使用etree对象中的xpath方法结合着xpath表达式进行标签定位和数据提取
4.实例化etree对象
etree.parse('本地文件路径')
etree.HTML(page_text)
5.xpath格式
i.标签关系
r = tree.xpath('/html/body/div')# /表示父子
r = tree.xpath('/html//div') # //表示下级
r = tree.xpath('//div')
r = tree.xpath('//div | //section')#两个用 | 隔开
ii.属性
r = tree.xpath('//div[@class="song"]') #表示class为song的div标签
iii.获取文本
r = tree.xpath('//div[@class="tang"]//li[5]/a/text()')[0]#表示class 为tang的div标签下的第5个li下的a下的文本信息,返回一个列表
r = tree.xpath('//li[7]//text()') #第7个li下的所有文本信息,包括子元素
r = tree.xpath('//div[@class="tang"]//text()')
iv.获取属性
r = tree.xpath('//div[@class="song"]/img/@src') #获取src属性的值
v.爬取58同城2手房名称
import requests
from lxml import etree
if __name__ == '__main__':
url = "https://bj.58.com/hezu/"
headers = {
'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.193 Safari/537.36'
}
res = requests.get(url=url)
res.encoding = "utf8"
htm = res.text
et = etree.HTML(htm)
print(et.xpath('//li[@class="house-cell"]/div[@class="des"]/h2/a/text()'))