Python之旅的第2^4天(shelve、xml模块和re模块部分)

实在是没想到今天的内容会这么精彩,特别是re模块,我激动了,这不就是数据抓取的基础吗?哈哈哈

一、shelve模块

import shelve
# shelve模块,功能上类似于json和pickle,但是操作起来比较简单,是将传入数据转化为一个字典
# 但是在写入过程中我们看不到字典的存在,同时不能跨语言进行传输

# f = shelve.open(r'shelve_test1')    #此时会生成3个文件,但是你完全不用理会,因为你看不懂
# f['stu1_info1'] = {'name':'alex','age':18}   #将传入的字典{'name':'alex','age':18} 变成一个v值,
#                                              # 与我们写入的'stu1_info1'行程一个键值对,就是转换成为字典
# f['stu1_info2'] = {'name':'zhoujielun','age':28}
# f['shelve_test'] = {'k1':'v1'}
# f.close()

# print(f.get('stu1_info1')['name'])  #用f.get(k值)获取你要找到的字典,然后用字典内的k值得到对应的v
                                    #输出结果为:'alex'

二、xml模块

# 关于xml模块的引入
import xml.etree.ElementTree as ET  #部分调用的模块由于名称太长,我们可以定义缩写
                                    #as后面跟随的内容就是缩写
# xml当然就是用来解析xml文件的
# 首先引入xml的文件内容,这里要明白xml中标签(tag)、属性(attrib)、标签数值(text)
# 下面是xml文件内的内容,请对照进行操作
# <data>
#     <country name="Liechtenstein">
#         <rank updated="yes">2</rank>
#         <year updated="yes">2010</year>
#         <gdppc>141100</gdppc>
#         <neighbor direction="E" name="Austria" />
#         <neighbor direction="W" name="Switzerland" />
#     </country>
#     <country name="Singapore">
#         <rank updated="yes">5</rank>
#         <year updated="yes">2013</year>
#         <gdppc>59900</gdppc>
#         <neighbor direction="N" name="Malaysia" />
#     </country>
#     <country name="Panama">
#         <rank updated="yes">69</rank>
#         <year updated="yes">2013</year>
#         <gdppc>13600</gdppc>
#         <neighbor direction="W" name="Costa Rica" />
#         <neighbor direction="E" name="Colombia" />
#     </country>
# </data>

# 以文件内容的第三行为例<rank updated="yes">2</rank>
# 其中<rank></rank>  'rank'就是xml文件中的标签值
# updated = "yes"  就是rank的属性
# 两个括号中间的'2'就是他们的数值

#ET.parse 打开一个xml文件,这里的parse的意思是解析,即为解析一个文件
# tree = ET.parse('xml_lesson')
#这时我们就将打开文件的句柄复制给了tree,这里用tree命名非常合适
#xml文件机构非常像一棵树,树根<data>  第一次分叉<country>
# <country>下面还会分出很多分支标签、对应的数值和属性

# tree.getroot() 就是获得根节点的意思
# root = tree.getroot()
# print(root)      #输出的结果:<Element 'data' at 0x0000028F1BB4A318>
#得到这样的结果就表示,root是一个对象,是可以被遍历的

#我们可以尝试去打印root下一级的子标签
# for i in root:
#     print(i.tag)   #输出了data下面包含的三个country
#我们再向下便利一层
    # for a in i:
    #     print(a.tag)   #输出rank、year、gdppc、neighbor、neighbor三次
    #                    #表示三个country下面的所有对应标签内容

#.attrib 就是刚才介绍在第一个尖括号里面出现的等号两边的连起来的东西
#<rank updated="yes">2</rank>  里面的updated="yes"就是属性
# for i in root:
#     print(i.attrib)   #输出{'name': 'Liechtenstein'}、{'name': 'Singapore'}、{'name': 'Panama'}
#                       #分别是<data>下面三个country中对应的属性 name="Liechtenstein" 等
#                       #最终表现形式是以字典的形式输出的
# print(root.attrib)      #root 即<data>没有属性值,所以输出一个空的字典

# .text 获取其中的值,<rank updated="yes">2</rank>当中的2
# for child in root:
#     print(child.tag, child.attrib)
#     for i in child:
#         print(i.tag, i.attrib, i.text)
#
# 输出结果是:
# country {'name': 'Liechtenstein'}
# rank {'updated': 'yes'} 2
# year {'updated': 'yes'} 2010
# gdppc {} 141100
# neighbor {'direction': 'E', 'name': 'Austria'} None
# neighbor {'direction': 'W', 'name': 'Switzerland'} None
# country {'name': 'Singapore'}
# rank {'updated': 'yes'} 5
# year {'updated': 'yes'} 2013
# gdppc {} 59900
# neighbor {'direction': 'N', 'name': 'Malaysia'} None
# country {'name': 'Panama'}
# rank {'updated': 'yes'} 69
# year {'updated': 'yes'} 2013
# gdppc {} 13600
# neighbor {'direction': 'W', 'name': 'Costa Rica'} None
# neighbor {'direction': 'E', 'name': 'Colombia'} None

#可以看出,没有返回值的时候返回None

#.iter 指定遍历其中的某一个节点,比如'year'
# 请记住iter方法是放在了root根目录下进行执行的
# for node in root.iter('year'):
#     print(node.tag, node.attrib, node.text)
#输出结果:
# year {'updated': 'yes'} 2010
# year {'updated': 'yes'} 2013
# year {'updated': 'yes'} 2013

# 对其中year的值进行修改
# tree = ET.parse('xml_lesson')
# root = tree.getroot()

# for node in root.iter('year'):
#     new_year = int(node.text) + 1
#     node.text = str(new_year)
#     node.set('update','yes')
# tree.write('xml_lesson')
#此时对应的<year>部分的数值已经增加了1

#.remove 删除某一节点的内容
#.findall  感觉有点类似于iter,但是感觉只是用来找寻下一层的
#.find     感觉有点类似于iter,
# 要求是删除掉<rank>值大于50的<country>所有信息
# for country in root.findall('country'):
#     rank = int(country.find('rank').text)
#     if rank > 50:
#         root.remove(country)
# tree.write('new_xml_lesson')
#最终生成新文件,并删除了最后一个<country>

#生成一个新的xml文件

# new_xml = ET.Element('new_xml_test.xml')
# name = ET.SubElement(new_xml , 'name' , attrib = {'xiaowang': 'alex'})
# age = ET.SubElement(name , 'age' ,attrib = {'zhoujielun':'18'})
# sex = ET.SubElement(name, "sex")
# sex.text = '33'  #数值的写入方式很特别
# name2 = ET.SubElement(new_xml, "name", attrib={"enrolled": "no"})
# age = ET.SubElement(name2, "age")
# age.text = '19'
#
# et = ET.ElementTree(new_xml)  #表示生成文档对象
# et.write('test.xml',encoding = 'utf-8',xml_declaration = True)  #写入文件
#
# ET.dump(new_xml)   #打印生成的格式
#以上是xml的全部内容

三、re模块的元字符部分

import re
# re模块,即正则表达式,主要针对字符串进行相关处理,由c语言编制而成,运行效率很高
# 是一个小型的高度专业的语言,主要用作模糊匹配
# re模块包含的元字符有   .  ^  $  *  +  ?  {}  []  |  ()  
# 先引入一个re模块的方法re.findall('查找规则','查找内容')
# 输出一个列表,表示找到的内容

# . 表示通配符,可以表示任何字符,一以对应
# print(re.findall('a..x','adasalexdasdaayex'))
#输出:['alex', 'ayex']

# ^ 表示必须以尖角号后面的字符为开头
# print(re.findall('^a..x','alexdadsaalex'))
#输出:['alex']  此时只能显示在最开始出现的'alex'

# $ 美元符,表示必须以美元符前面的字符为结尾
# print(re.findall('a..x$','alexdadsaalex'))
#输出:['alex']   此时输出的'alex'是字符串最末尾的alex

# *  和  + 分表表示该字符串出现次数为:
# * 表示(0,正无穷大)
# + 表示(1,正无穷大)
#同时他们都是贪婪匹配,以匹配到最多为结果
# print(re.findall('alex*','aledsasfafa'))   #['ale']
# print(re.findall('alex*','alexxxxxsadada'))   #['alexxxxx']
#
# print(re.findall('alex+','aledsasfafa'))    #[]
# print(re.findall('alex+','alexxxxxsadada'))   #['alexxxxx']

# ? 表示该字符匹配0或者1次
# print(re.findall('alex?','aledsasfafa'))    #['ale']
# print(re.findall('alex?','alexxxxxsadada'))   #['alex']

# {} 大括号,可以设定出现次数的范围,如果只填写一个数字,则表示指定了出现次数
# {0,正无穷} == *
# {1,正无穷} == +
# {0,1} == ?

# [] 中括号是一个非常关键的符号,他表示其中任意一个与外面的匹配符合
# 在[]中,除了- ^ 三个特殊符号外,里面的任何符号都是没有意义的
# [] 中他们三个的意思分别是
# - 表示范围
# print(re.findall('x[a-z]','xdasdsaxdas'))   #['xd', 'xd']
# print(re.findall('x[a-z]*','xdasdsaxdas'))   #['xdasdsaxdas']  之所以这样是因为*是贪婪匹配,有多少拿多少
# print(re.findall('[a-z]*x','xdasdsaxdas'))   #['xdasdsax']
# print(re.findall('^[a-z]x','xdasdsaxdas'))   #[]

# ^ 表示非这些字符
# print(re.findall('[^a-z]x','9xdasdsa0xdas'))   #['9x', '0x']

#  转义符,好像括号内外都一样
# 首先是能让没意义的有意义
# d  匹配任何十进制数;它相当于类 [0-9]。
# D 匹配任何非数字字符;它相当于类 [^0-9]。
# s  匹配任何空白字符;它相当于类 [ 	

fv]。
# S 匹配任何非空白字符;它相当于类 [^ 	

fv]。
# w 匹配任何字母数字字符;它相当于类 [a-zA-Z0-9_]。
# W 匹配任何非字母数字字符;它相当于类 [^a-zA-Z0-9_]
#   匹配一个特殊字符边界,比如空格 ,&,#等

# 能让有意义的没有意义
# 给了一个5+(9*8-5*(3-1))
# 取出3-1部分的内容
# a = '5+(9*8-5*(3-1))'
# b = re.findall('([^()]*)',a)
# print(b)   #此时可得到['(3-1)']

# * 和 + 后面增加上?
# 会由原来的贪婪匹配,转换成为惰性匹配
# print(re.findall('alex*','alexxxxxsadada'))   #['alexxxxx']
# print(re.findall('alex*?','alexxxxxsadada'))   #['ale']
#
# print(re.findall('alex+','alexxxxxsadada'))   #['alexxxxx']
# print(re.findall('alex+?','alexxxxxsadada'))   #['alex']

#关于re模块真非常神奇
#比如可以以身份证号为参考,获取以612开头的,并且是1990年之后出生的人的身份证号码
# 使用正则表达式  ^612...1990+*

# 比如获取'das12dadsa123asd45'当中所有的数字d+即可实现

就是这些了,没想到今天的三个小时这么精彩,非常的激动,期待明天re的新发现哦

原文地址:https://www.cnblogs.com/xiaoyaotx/p/12452860.html