特点:数据以行为单位,每一个数据表示一个实体。每一行数据的属性都是一样的。
举例:关系型数据库中的表就是结构化数据。
处理方法:sql
特点:结构化数据的另一种形式。他并不符合关系型数据的特点,不能用关系型模型来描述。但是这种数据包含相关标记,有用来分割语义元素以及字段进行分层的描述。因此也被称为自描述结构。
举例:xml,html,json
处理方法:正则,xpath,jsonpath,css选择器。
特点:没有固定结构的数据。
举例:文档、图片、音频、视频。
处理方法:常常用二进制形式来做整体保存。
json 是 js 语言中用来保存对象和数组的一种数据结构。json 数据本质上是字符串。
js 的数组:
var array = ['aaa','bb','cc'] // 和python中的列表对应
js 的对象:
var obj = {name:'zhangsan',age:10} //和python中的字典对应
name = obj.name
json模块。
对字符串的操作:
json.loads(json_str) --->python的list或者dict
json.dumps(python的list或者dict) --->json_str
对 json文件的操作:
json.load(fp) --->从json文件中读出json数据,返回一个python的list或者dict
json.dump(python的list或者dict,fp) --->python的list或者dict转化成json_str保存到fp对应的文件中。
json 作为数据格式进行传输,具有较高的效率。
json 不像 xml 那样具有严格的闭合标签,所以 json 作为数据传输的时候,他的数据有效占比比 xml 高很多。在相同流量下, json 比 xml 作为数据传输,传输的数据更多。
^ | 行首 |
---|---|
$ | 行尾 |
? | 0次或1次 |
---|---|
* | > =0次 |
+ | > =1次 |
{n} | n次 |
{n,} | > n次 |
{n,m} | >=n ,<=m |
[ ] | 匹配括号中任意一个字符,单字符 |
---|---|
[abc] | 匹配 a 或者 b 或者 c |
\d | 0-9任意数字 |
\w | 数字字母下划线 |
\s | 空白字符:换行符、制表符、空格 |
\b | 单词边界 |
. | 除换行符以外的任意字符 |
python 中 re 模块是用来做正则处理的。
# 1、导包
import re
# 2、将正则表达式编译成一个pattern对象
pattern = re.compile(
r'正则表达式', # r表示元字符
'匹配模式'
)
# 3、用pattern对象来使用相应的方法来匹配内容。
Pattern 对象的一些常用方法主要有:
match | 从起始位置开始查找,只匹配一次 |
---|---|
search | 从任何位置开始查找,只匹配一次 |
findall | 全部匹配,返回列表 |
finditer | 全部匹配,返回迭代器 |
split | 分割字符串,返回列表 |
sub | 替换 |
# match方法:默认从头开始,只匹配一次,返回一个match对象。
pattern.match(
'匹配的目标字符串',
start, # 开始的位置 ---缺省,默认为start=0
end, # 结束的位置 ---缺省,默认为end=-1
)
match 对象的属性:
match.group() # 获取匹配内容
match.span() # 匹配的范围
match.start() # 开始位置
match.end() # 结束位置
# 这些方法都可以带一个参数0,但是不能写1,1表示取第一分组。
match.group(0)
match.span(0)
match.start(0)
match.end(0)
match.groups() # 将所有分组的内容,按顺序放到一个元组中返回
match方法示例:
示例一
import re
pattern = re.compile(r'\d+')
content = 'one1two2three3four4'
m1 = pattern.match(content) # 从0位置开始匹配
m2 = pattern.match(content,2,10) # 从e位置开始匹配
m3 = pattern.match(content,3,10) # 从1位置开始匹配
print(m1)
print(m2)
print(m3.group())
print(m3.group(0)) # 可以省略0
print(m3.span(0))
print(m3.start(0))
print(m3.end(0))
运行结果:
None
None
12
12
(3,5)
3
5
示例二
import re
pattern = re.compile(r'([a-z]+) ([a-z]+)',re.I) # re.I表示忽略大小写
m = pattern.match('Hello World Wide Web')
# 匹配成功,返回一个match对象
print(m)
# 返回匹配成功的子串
print(m.group())
# 返回匹配成功的整个子串的索引
print(m.span(0))
# 返回第一个分组匹配成功的子串
print(m.group(1))
# 返回第一个分组匹配成功的子串索引
print(m.span(1))
# 等价于m.group(1),m.group(2)
print(m.groups()) # 将所有分组的内容,按顺序放到一个元组中返回
运行结果:
<re.Match object; span=(0, 11), match='Hello World'>
Hello World
(0, 11)
Hello
(0,5)
('Hello','World')
# search方法:从任意位置开始匹配,只匹配一次,返回一个match对象。
pattern.search(
'匹配的目标字符串',
start, # 开始的位置 ---缺省,默认为start=0
end, # 结束的位置 ---缺省,默认为end=-1
)
search方法示例:
示例一
import re
pattern = re.compile(r'\d+')
content = 'one12twothree34four'
m = pattern.search(content)
print(m)
print(m.group())
m = pattern.search(content,10,30) # 指定字符串区间
print(m)
print(m.group())
print(m.span())
运行结果:
<re.Match object; span=(3, 5), match='12'>
12
<re.Match object; span=(13, 15), match='34'>
34
(13, 15)
示例二
import re
# 将正则表达式对象编译成pattern对象
pattern = re.compile(r'\d+')
content2 = 'hello 123456 789'
# 使用search查找匹配的子串,如果不匹配就返回None
m = pattern.search(content2)
if m:
# 使用 match 获取分组信息
print(m.group())
# 起始位置和结束位置
print(m.span())
运行结果:
123456
(6, 12)
# findall方法:全文匹配,匹配多次,将每次匹配到的结果放到list中返回。
pattern.findall(
'匹配的目标字符串',
start, # 开始的位置 ---缺省,默认为start=0
end, # 结束的位置 ---缺省,默认为end=-1
)
findall 方法实例:
示例一
import re
# 将正则表达式编译成一个pattern对象
pattern = re.compile(r'we')
# 使用findall方法全局搜索 we 返回列表 ['we','we','we']
m = pattern.findall('we work well welcome')
print(m)
示例二
# 使用\b元字符进行匹配,只匹配出 we 单词,不匹配出其他的含有 we的单词。
import re
# 将正则表达式编译成一个pattern对象
pattern = re.compile(r'\bwe\b')
# 使用findall方法全局搜索 we 返回列表 ['we','we','we']
m = pattern.findall('we work well welcome')
print(m)
示例三
import re
# 生成pattern对象,查找连续的数字
pattern = re.compile(r'\d+')
result1 = pattern.findall('hello 123456 789')
# 从0开始 1对应的是下标3,2对应的是下标7,匹配下标0-7的数字
result2 = pattern.findall('one1two2three3four4',0,8)
print(result1) # ['123456','789']
print(result2) # ['1','2']
# finditer方法:全文匹配,匹配多次,返回一个迭代器。
pattern.finditer(
'匹配的目标字符串',
start, # 开始的位置 ---缺省,默认为start=0
end, # 结束的位置 ---缺省,默认为end=-1
)
例子:
import re
pattern = re.compile(r'\d+')
content1 = 'hello 123456 789'
content2 = 'one1two2three3four4'
result_iter1 = pattern.finditer(content1)
result_iter2 = pattern.finditer(content2,0,10)
print(type(result_iter1))
print(type(result_iter2))
print('result1.....')
for m1 in result_iter1:
print('matching string:{},position:{}'.format(m1.group(), m1.span()))
print('result2.....')
for m2 in result_iter2:
print('matching string:{},position:{}'.format(m2.group(), m2.span()))
运行结果:
<class 'callable_iterator'>
<class 'callable_iterator'>
result1.....
matching string:123456,position:(6, 12)
matching string:789,position:(13, 16)
result2.....
matching string:1,position:(3, 4)
matching string:2,position:(7, 8)
# split方法:切分,按照正则所表示内容进行切分字符串,返回切分后的每个字串。
pattern.split(
'要切分的字符串',
'切分次数', # 默认是全部切分
)
例子:
import re
pattern = re.compile(r'[\s\,\;]+')
a = pattern.split('a,b;,;c ;,; d')
print(a) # ['a', 'b', 'c', 'd']
# sub方法:用指定字符串,替换正则表达式所匹配到的内容。
pattern.sub(
repl, # 替换成什么
content, # 替换什么
count, # 替换次数,默认替换所有
) --->替换后的字符串。
"""
repl替换内容可以使用函数:
函数要求:
1、函数必须有参数,参数就是正则匹配目标字符串所得到的每个match对象。
2、这个函数必须要有返回值,返回值必须是字符串,这个字符串将来就作为替换的内容。
"""
例子:
import re
p = re.compile(r'(\w+) (\w+)')
s = 'hello 123,hello 456'
# 使用'hello world'替换'hello 123'和'hello 456'
print(p.sub(r'hello world',s))
# 将 二分组和一分组互换位置
print(p.sub(r'\2 \1',s)) # 引用分组
import re
def add(m):
return str(int(m.group()) + 1000)
# 涨工资每个人涨1000
content = 'zhangsan:3000,lisi:4000'
p = re.compile('\d+')
result = p.sub(add,content)
print(result)
分组在正则表达式中使用()来表示,一个括号就是一个分组。
分组的作用:
1、筛选特定内容。
2、可以在同一个表达式中引用前面的分组。
\1:引用第一分组
\2:引用第二分组
3、findall配合分组使用
import re
content = '正则表达式
'
p = re.compile(r'<(html)><(h1)>(.*)\2>\1>')
print(p.findall(content)) # [('html', 'h1', '正则表达式')]
import re
# 贪婪和非贪婪来控制表示次数的元字符
# pattern = re.compile(r'ab??') # [0,3][0,1]
# result = pattern.findall('abbbc')
# print(result)
s = 'aatest1bbtest2cc'
# ['test1', 'test2']
pattern = re.compile('.*?')
# ['test1bbtest2']
# pattern = re.compile('.*')
result = pattern.findall(s)
print(result)
re.S | .可以匹配换行符 |
---|---|
re.I | 忽略大小写 |
.*?(尽可能少匹配任意内容)配合re.S使用
import json
import re
import requests
# 将数据写入json文件中
def write_to_json(infos):
with open('movie.json','w',encoding='utf-8') as fp:
json.dump(infos,fp)
# 解析页面内容
def parse_page(html_str):
# 测试页面内容是否能拿到,这一步必须要测试
# print(html_str)
# 正则筛选页面的原则:一步步缩小匹配范围。
dl_p = re.compile(r'(.*?)
',re.S)
dl_content = dl_p.search(html_str).group()
dd_p = re.compile(r'(.*?) ',re.S)
dd_list = dd_p.findall(dl_content)
# print(dd_list)
"""
电影名称
主演
上映时间
评分
详情url
"""
for dd in dd_list:
name_p = re.compile(r'" title="(.*?)" class="',re.S)
name = name_p.search(dd).group(1) # 电影名称
# print(name)
actor_p = re.compile(r'(.*?)
',re.S)
actor = actor_p.search(dd).group(1).strip() # 主演
# print(actor)
releasetime_p = re.compile(r'(.*?)
',re.S)
releasetime = releasetime_p.search(dd).group(1) # 上映时间
# print(releasetime)
score_p = re.compile(r'(.*?)(.*?)
',re.S)
# score = score_p.search(dd).group(1) + score_p.search(dd).group(2)
score = score_p.findall(dd) # [('9.', '5')]
score = ''.join(score[0]) # 评分
# print(score)
detail_url_p = re.compile(r',re.S)
detail_url = 'https://maoyan.com' + detail_url_p.search(dd).group(1) # 详情页url
# print(detail_url)
# 设置爬取数据
item = {}
item['name'] = name
item['actor'] = actor
item['releasetime'] = releasetime
item['score'] = score
item['detail_url'] = detail_url
# print(item)
infos.append(item)
# 保存到json文件
# 一个方法做一件事情
def main():
# 确定基础url
base_url = 'https://maoyan.com/board/4?offset=%s'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36'
}
# 分页
for i in range(10):
response = requests.get(base_url % (i*10),headers=headers)
parse_page(response.text)
if __name__ == '__main__':
infos = []
# 提取数据,将数据添加到infos中
main()
# 将数据写入文件
write_to_json(infos)
# 从 movie.json文件中读出电影数据
# infos = json.load(open('movie.json','r'))
# for item in infos:
# print(item)
1、字段
阅读
评论
标题
作者
更新时间
详情页
2、10页内容保存到 json 文件。