有时候爬取的数据返回的直接是一个混杂着数据和结构的HTML文件,这个时候获取数据需要进行数据解析,python数据解析主要有三种方法:
1. re解析
效率最高,但是有点复杂,对新手不太友好,准确率高
2. bs4解析
最常用和简单,但是效率并不高
3. xpath解析
清晰易懂
1. Re(regular expression) 正则表达式
先看看正则表达的规则:
1-1 元字符
.
===>匹配除换行符外的任意字符
\n
===> 匹配换行符
\w
===> 匹配字母或数字或下划线
\s
===> 匹配任意的空白符
\d
===> 匹配数字
\t
===> 匹配制表符
^
===> 匹配字符串的开始
$
===> 匹配字符串的结尾
\W
===> 匹配非字母或数字或下划线
\D
===> 匹配非数字
\S
===> 匹配非空白符
a|b
===> 匹配a或b
()
===> 匹配括号内的表达式,也表示一个组
[...]
===> 匹配字符组中的字符
[^...]
===> 匹配除了字符组中字符的所有字符
1-2 量词
*
===> 重复零次或更多次
+
===> 重复一次或更多次
?
===> 重复零次或一次
{n}
===> 重复n次
{n,}
===> n重复n次或更多次
{n,m}
===> n重复n次到m次
贪婪匹配
===> .*
惰性匹配
===> .*?
在爬虫里面,惰性匹配用的更多
【Re】Demo - re的方法介绍
import re # findall 以数组的形式返回所有匹配的结果 result = re.findall(r"\d+","我的电话号码是:10010,我对手的电话是:10086") print(result) # finditer 以迭代器的方式返回所有匹配结果,.group()返回匹配到的结果 res = re.finditer(r"\d+","我的电话号码是:10010,我对手的电话是:10086") print(res) for i in res: print(i) print(i.group()) # search() 返回第一个找到的结果并封装在迭代器中 a = re.search(r"\d+","我的电话号码是:10010,我对手的电话是:10086") print(a) print(a.group()) # match() 从头匹配结果并返回在迭代器中 b = re.match(r"\d+","我的电话号码是:10010,我对手的电话是:10086") print(b) c = re.match(r"\d+","10010,我对手的电话是:10086") print(c.group()) # 预加载正则规则 obj = re.compile(r"\d+") resp = obj.findall("我的电话号码是:10010,我对手的电话是:10086") print(resp)
结果截图:
image.png
re.S
——表示可以匹配到换行符
【Re】Demo - re的案例
import re s = ''' <div id="1">CCNU</div> <div id="2">HUST</div> <div id="3">SSE</div> <div id="4">CSUT</div> ''' pattern = re.compile(r'<div id="(?P<id>\d)">(?P<name>.*?)</div>',re.S) res = pattern.finditer(s) for i in res: print(i.group("id")) print(i.group("name"))
image.png
获取豆瓣top250的电影数据并写进csv文件中
import requests import re import csv url = "https://movie.douban.com/top250" headers = { "user-agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36" } res = requests.get(url,headers=headers) if res.status_code == 200: result = res.text pattern = re.compile(r'<li>.*?<div class="item">.*?<span class="title">(?P<title>.*?)</span>' r'.*?<p class="">.*?<br>(?P<year>.*?) ' r'.*?<span class="rating_num" property="v:average">(?P<score>.*?)</span>' r'.*?<span property="v:best" content="10.0"></span>.*?<span>(?P<ratingNum>.*?)人评价</span>',re.S) a = pattern.finditer(result) f = open("doubantop250.csv",mode="w") csvwriter = csv.writer(f) for i in a: # print(i.group("title")) # print(i.group("year").strip()) # print(i.group("score")) # print(i.group("ratingNum")) dic = i.groupdict() dic['year'] = dic["year"].strip() csvwriter.writerow(dic.values()) f.close() res.close()