[python爬虫笔记]
💕学习爬虫的第四天💕
今天给大家分享一些有关数据解析的概述。python爬虫中存在三种不同的数据解析方法。分别是RE(正则表达式)解析、bs4中的Beautifulsoup解析以及xpath解析。今天主要介绍一下RE的用法。
概述
当我们使用python爬虫拿到了页面的源码之后就不知道该这么办了,有的还沉浸在拿到源码的兴奋中(嘻嘻~呃……这么说话会不会有人打我😱),当然对于像我一样的小白来说,拿到了源码自然很高兴。
但是拿到了源码只是爬虫的第一步,真正的核心在于对数据的解析提取。一般来说,爬虫的解析方式有三种:
- RE(正则表达式)解析;
- bs4中的Beautifulsoup解析;
- xpath解析。
注:这三种方式可以混合进行使用,完全以结果作导向,只要能拿到想要的数据,用什么方式不重要。另外bs4写起来简单,但性能差,re最快,性能高,不易理解。
RE解析(Regular Expression)
在Python中需要通过正则表达式对字符串进⾏匹配的时候,可以使⽤⼀个python自带的模块,名字为re。
正则表达式,是一种使用表达式的方式对字符串进行匹配的语法规则。
- 正则的优点:速度快,效率高,准确性高;
- 正则的缺点:新手上手难度高。
抓取的网页源代码本质上就是一个超长的字符串;
正确的语法:使用元字符进行排列组合用来匹配字符串,在线测试正则表达式在线工具 —— OSCHINA.NET社区(https://tool.oschina.net/)
元字符:具有固定含义的特殊符号。
具体学习链接:==正则表达式30分钟入门教程 | 菜鸟教程 (runoob.com)==
常用元字符:
. 匹配除换行符以外的任意字符
\w 匹配字母或数字或下划线
\s 匹配任意的空白符
\d 匹配数字
\n 匹配一个换行符
\t 匹配一个制表符
# 以下两个用在校验最多
^ 匹配字符串的开始
$ 匹配字符串的结尾
\W 匹配非字母或数字或下划线
\D 匹配非数字
\S 匹配非空白符
a|b 匹配字符a或字符b
() 匹配括号内的表达式,也表示一个组···这里面的表达式必须是连续写
#以下连个为组,想要连续匹配时不能有分割符
[...] 匹配字符组中的字符 组里边有的才会被匹配
[^...] 匹配除了字符组中字符的所有字符
量词:控制前面的元字符出现的次数
* 重复零次或更多次
? 重复零次或一次
+ 重复一次或更多次
{n} 重复n次 比如\d{5}=>表示\d被重复了5次
{n,} 重复n次或更多次
{n,m} 重复n到m次
贪婪匹配和惰性匹配
.* 贪婪匹配 => 尽可能多的让*匹配
.*? 惰性匹配 => 尽可能少的让.*匹配
爬虫中用的最多的就是惰性匹配
这些符号并不是要求全部记住,用的时候再拿来用就行了,但是必须要知道其中的含义和语法。
好了,既然我们已经了解了大致的语法,那我们接下来说一说常用的查询函数。
一般常用的函数包括4种:
- findall:匹配字符串中所有符合正则的内容
- finditer:匹配字符串中所有的内容【返回的是迭代器】,从迭代器中拿到内容需要.group()
- search,为全文搜索。找到一个结果就返回,返回的结果是match对象。拿到数据需要.group()
- match是从头开始匹配,默认在表达式中添加了一个^,若前面有不符合正则表达式的字符则会报错.
这4种函数的参数包含三个,分别为pattern、string、flags 关键参数在于pattern、string
具体的实例如下:
# 使用RE
import re
# 1. findall:匹配字符串中所有符合正则的内容
lst = re.findall(r"\d+", "我的电话号是:10086,女朋友的电话号是10010")
print(lst) # ['10086', '10010'] 列表的效率不高
# 2. finditer:匹配字符串中所有的内容【返回的是迭代器】,从迭代器中拿到内容需要.group()
it = re.finditer(r"\d+", "我的电话号是:10086,女朋友的电话号是10010")
# <callable_iterator object at 0x000001652885BE20>
print(it)
for i in it:
# print(i)
"""
match对象:
<re.Match object; span=(7, 12), match='10086'>
<re.Match object; span=(21, 26), match='10010'>
"""
print(i.group()) # 10086 10010
print("")
# 3. search,为全文搜索。找到一个结果就返回,返回的结果是match对象。拿到数据需要.group()
s = re.search(r"\d+", "我的电话号是:10086,女朋友的电话号是10010")
# match对象:<re.Match object; span=(7, 12), match='10086'>
print(s.group()) # 10086
print("-------")
# 4. match是从头开始匹配,默认在表达式中添加了一个^,若前面有不符合正则表达式的字符则会报错
# st = re.match(r"\d+", "我的电话号是:10086,女朋友的电话号是10010")
# print(st) # None
# print(st.group()) # AttributeError: 'NoneType' object has no attribute 'group' => 表明st是空的
st2 = re.match(r"\d+", "10086,女朋友的电话号是10010")
print(st2) # <re.Match object; span=(0, 5), match='10086'>
print(st2.group()) # 10086
除此之外,为了避免一直这4种函数或者说提高效率和代码可读性,我们可以采用预加载正则。
所谓“预加载正则”,顾名思义。就是规定一个样式,这个样式可以是多条的,使用这个提前加载好的规则去匹配想要的内容。主要用到的函数是compile()
预加载正则种可以正常调用所需函数。
使用的样式如下:
# 预加载正则表达式 compile()
odj = re.compile(r"\d+") # 预加载正则
result = odj.finditer("我的电话号是:10086,女朋友的电话号是10010") # 这里只需要填写字符串
for item in result:
print(item.group()) # 10086 10010
说了这么多,不知道你有没有看的明白💝。
算了,给你来点《实例》让你瞧瞧。
# 使用RE中的预加载
# 快速向下复制粘贴:ctrl+D
import re
s = """
<div class='jfaj'><span id='1001'>张杰</span></div>
<div class='gsa'><span id='1002'>邓紫棋</span></div>
<div class='hdfs'><span id='1003'>王嘉欣</span></div>
<div class='hdsr'><span id='1004'>白月光</span></div>
"""
# 原始预加载
# odj = re.compile(r"<div class='.*?'><span id='.*?'>.*?</span></div>", re.S) # re.S => 让.能匹配换行符
# 想要进一步获取内容,需要设置一个名字.在取名字的时候要注意是大写的P (?P<名字>正则)
odj2 = re.compile(r"<div class='.*?'><span id='.*?'>(?P<aaa>.*?)</span></div>", re.S) # re.S => 让.能匹配换行符
result = odj2.finditer(s)
for i in result:
# print(i.group())
"""
<div class='jfaj'><span id='1001'>张杰</span></div>
<div class='gsa'><span id='1002'>邓紫棋</span></div>
<div class='hdfs'><span id='1003'>王嘉欣</span></div>
<div class='hdsr'><span id='1004'>白月光</span></div>
"""
# 想要拿到其中的任意内容,就要将对应组名作为参数传递给group
print(i.group("aaa"))
"""
张杰
邓紫棋
王嘉欣
白月光
好了,今天分享到这儿,明天再见💕~