数据解析
聚焦爬虫:爬取页面中指定的页面内容
- 编码流程:
- 指定url
- 发起请求
- 获取响应数据
- 数据解析
- 持久化存储
数据解析分类
- 正则解析
- bs4
- xpath
数据解析原理概述
- 解析的局部文本内容都会在标签之间或者标签对应的属性中进行存储
- 进行指定标签的定位
- 标签或者标签对应的属性中存储的数据进行提取(解析)
正则解析
正则表达式
-
正则练习网址:https://www.codejiaonang.com/
-
正则在线测试网站: https://regexr-cn.com/
-
笔记网址:https://blog.csdn.net/weixin_53312629/article/details/118872820
正则表达式(Regular Expression)是对字符串操作的一种逻辑公式,一般使用正则表达式对字符串进行匹配和过滤
语法:使用元字符进行排列组合来匹配字符串
元字符:具有固定含义的特殊符号
常用元字符:https://www.runoob.com/regexp/regexp-metachar.html
代码 | 说明 |
---|---|
. | 匹配除换行符以外的任意字符 |
\w | 匹配字母或数字或下划线 |
\s | 匹配任意的空白符 |
\d | 匹配数字 |
\n | 匹配一个换行符 |
\t | 匹配一个制表符 |
^ | 匹配字符串的开始 |
$ | 匹配字符串的结束 |
\W | 匹配非字母或数字或下划线 |
\D | 匹配非数字 |
\S | 匹配非空白字符 |
a|b | 逻辑或,匹配a或者b |
() | 匹配括号内的表达式,也表示一个组 |
[…] | 匹配字符组中的字符,如:[0-9a-zA-Z] |
[^…] | ^表示逻辑非,匹配除了字符组中字符的所有字符 |
量词:控制前面元字符出现的次数
代码 | 说明 |
---|---|
* | 重复0次或更多次 |
+ | 重复一次或更多次,如\d+(贪婪匹配) |
? | 重复0次或一次(出现或不出现) |
{n} | 重复n次 |
{n,} | 重复n次或更多次 |
{n,m} | 重复n-m次 |
贪婪匹配和惰性匹配
.* | 贪婪匹配 |
---|---|
.*? | 惰性匹配(尽可能少的匹配内容) |
例: str:玩儿吃鸡游戏,晚上一起玩儿游戏,干嘛呢?打游戏啊
reg:玩儿.*?游戏
此时匹配的结果是:玩儿吃鸡游戏
reg:玩儿.*游戏
此时匹配的结果是:玩儿吃鸡游戏,晚上一起玩儿游戏,干嘛呢?打游戏
re模块
re.findall(r’正则表达式’,str):匹配字符串中所有符合正则的内容
import re
lst = re.findall(r'\d+', '我的电话号码是10086,我男朋友的电话号码是10010')
print(lst)
re.finditer(r’正则表达式’,str):匹配字符串中所有符合正则的内容[返回的是迭代器],从迭代器中拿到内容需要.group()
import re
it = re.finditer(r'\d+', '我的电话号码是10086,我男朋友的电话号码是10010')
print(it)
for item in it:
print(item.group())
re.search():找到一个结果就返回,返回的结果是match对象,拿到内容需要.group()
import re
s = re.search(r'\d+', '我的电话号码是10086,我男朋友的电话号码是10010')
print(s.group())
re.match(r’正则表达式’,str):match从开头开始匹配内容
import re
m = re.search(r'\d+', '我的电话号码是10086,我男朋友的电话号码是10010')
# print(m.group()) 匹配不到内容
new_match = re.search(r'\d+', '10086,我男朋友的电话号码是10010')
print(new_match.group())
预加载正则表达式
obj = re.comple(r‘正则表达式’)
obj.finditer(str)
import re
obj = re.compile(r'\d+')
ret = obj.finditer('我的电话号码是10086,我男朋友的电话号码是10010')
print(ret)
for each_item in ret:
print(each_item.group())
pass
ret = obj.findall('id:10000')
print(ret)
从正则里提取内容
(?P<分组名字>正则) 可以单独从正则匹配的内容中进一步提取内容
import re
s = '''
<div class= 'jay'><span id ='1'>郭麒麟</span></div>
<div class= 'jj'><span id ='2'>宋轶</span></div>
<div class= 'joe'><span id ='3'>大聪明</span></div>
<div class= 'tony'><span id ='4'>胡说八道</span></div>
'''
obj = re.compile(r"<div class= '.*?'><span id ='(?P<id>.*?)'>(?P<wahaha>.*?)</span></div>", re.S)
# re.S: 让.能匹配换行符
# (?P<分组名字>正则) 可以单独从正则匹配的内容中进一步提取内容
result = obj.finditer(s)
for item in result:
print(item.group('wahaha'))
print(item.group('id'))
bs4
数据解析原理:
- 标签定位
- 提取标签、标签属性中存储的数据值
bs4进行数据解析原理:
- 实例化一个BeautifulSoup对象,并将页面源码数据加载到该对象中
- 通过调用BeautifulSoup对象中 相关的属性或者方法进行标签定位和数据提取
环境安装:
- pip install bs4
- pip install lxml
如何实例化BeautifulSoup对象
-
from bs4 import BeautifulSoup
-
对象的实例化
- 将本地的html文档中的数据加载到该对象中
from bs4 import BeautifulSoup fp = open('test.html', 'r', encoding='utf-8') soup = BeautifulSoup(fp,'lxml') fp.close()
- 将互联网上获取到的页面源码加载到该对象中
-
提供的用于数据解析的方法和属性
- soup.tagName 返回html中第一次出现的tagName标签
- soup.find()
- soup.find(‘tagName’)等同于soup.div
- 属性定位(根据属性class/id/attr定位标签)
- soup.find(‘div’, class_/id/attr=‘song’)
- soup.find_all(‘tagName’)返回符合要求的所有标签
- select:(‘某种选择器’):返回符合要求的所有标签列表
- 属性选择器
- soup.select(’.tang > ul >li > a’): >表示一个层级
- soup.select(‘.tang > ul a’):空格表示多个层级
-
获取标签之间的文本数据
- soup.a.text/string/get_text()
- text/get_text():可以获取某一个标签中所有的文本内容
- string:只可以获取该标签下直系的文本内容
-
获取标签中的属性值
- soup.a[‘href’]
xpath
xpath解析原理:
- 实例化一个etree的对象,且需要将被解析的页面源码数据加载到该对象中。
- 调用etree对象中的xpath方法结合者xpath表达式实现标签的定位和内容的捕获。
环境的安装:
- pip install lxml
如何实例化etree对象
-
from lxml import etree
-
将本地的html文档中的源码加载到etree对象中:
etree.parse(filePath)
-
可以将从互联网上获取的源码数据加载到该对象中
etree.HTML(page_text)
-
xpath(‘xpath表达式’)
xpath表达式
- /:作用于最左侧表示从根节点开始定位;作用于两个标签中间表示一个层级,相当于bs4中的>
- //:作用于开头表示从任意位置开始定位;作用于两个标签中间,表示多个层级,相当于bs4中的空格
- 属性定位://div[@class=“song”] tag[@attrName=‘attrValue’]
- 索引定位://div[@class=“song”]/p[3] 索引从1开始
- 取文本:
- /text():获取的是标签中直系的文本内容
- //text(): 获取的是标签中非直系的文本内容
- 取属性:
- /@attrName 如:img/@src
注意:xpath无法匹配tbody标签