python学习笔记-结构化

#=========================结构化文件存储====================
# 结构数据: 先有的结构,在谈数据
    # JSON文件
        # JSON Path
        # 转换成Python类型进行操作(json类)
    # XML文件
        # 转换成python类型(xmltodict)
        # XPath
        # CSS选择器
        # 正则
# 非结构化数据:先有数据,再谈结构
    # 文本
    # 电话号码
    # 邮箱地址
        # 通常处理此类数据,使用正则表达式
    # Html文件
        # 正则
        # XPath
        # CSS选择器
#===========================XML文件===========================
# 参考资料
    # https://docs.python.org/3/library/xml.etree.elementtree.html
    # http://www.runoob.com/python/python#xml.html
    # https://blog.youkuaiyun.com/seetheworld518/article/details/49535285
  
# XML(eXtensibleMarkupLanguage), 可扩展标记语言
    # 标记语言: 语言中使用尖括号括起来的文本字符串标记
    # 可扩展:用户可以自己定义需要的标记
    # 是w3c组织制定的一个标准
    # XML描述的是数据本身,即数据的结构和语义
    # HTML侧重于如何显示web页面中的数据
    
# XML文档的构成
    #例:
  # 处理指令(可以认为一个文件内只有一个处理指令)
  # 最多只有一行
  # 且必须在第一行
  # 内容是与xml本身处理起相关的一些声明或者指令
  # 以xml关键字开头
  # 一般用于声明XML的版本和采用的编码
      # version属性是必须的
      # encoding属性用来支出xml解释器使用的编码
    <?xml version="1.0" encoding="utf-8" ?>
    
    # 根元素(一个文件内只有一个根元素)
  # 在整个xml文件中,可以把他看作一个树形结构
  # 根元素有且只能有一个
    <root_element attribute="a">  # 属性
        
            # 子元素
      <element attribute="b">
      
          # 内容
          # 表明标签所存储的信息
          <name>content</name>
      </element>
            <element>
              # 注释,起说明作用的信息
        # 注释不能嵌套在标签里
        <name> <!-- content -->   </name> #可以
        <name <!-- content -->>   </name> #不可以,注释在标签内
        
        # 只有在注释的开始和结尾使用双短横线
        <!--c-o-te-nt--> #可以,注释内容可以有一个短横线
        <!--c--o--te--nt-->#不可以,双短横线只能出现在开头或结尾
        
        # 三短横线只能出现在注释的开头而不能用在结尾
        <!---con-tent--> #可以, 三短横线只能出现在开头
        <!---con-tent---> #不可以, 三短横线只能出现在开头   
      </element>
    </root_element>
                
# 保留字符的处理
    # XML中使用的符号可能跟实际符号相冲突,典型的就是左右尖括号
    # 使用实体引用(EntityReference)来表示保留字符
       <score> score>80 </score> #有错误,xml中不能出现">"
       <score> score&gt;80</score> #使用实体引用
       
    # 把含有保留字符的部分放在CDATA块内部,CDATA块把内部信息视为不需要转义
        <![CDATA[
           select name,age
           from Student
           where score>80
           ]]>
                 
    # 常用的需要转移的保留字符和对应实体引用,以&开头并且以分号结尾:
    # & : &amp;
    # < : &lt;
    # > : &gt;
    # ' : &apos;
    # " : &quot;
            
# XML标签的命名规则
    # Pascal命名法
    # 用单词表示,第一个字母大写
    # 大小写严格区分
    # 配对的标签必须一致
    
# 命名空间,为了防止命名冲突
      
    <Student>
      <Name>LiuYing</Name>
      <Age>23</Age>
    </Student>
    <Room>
        <Name>2014</Name>
        <Location>1#23#1</Location>
    </Room>
                    
  # 如果归并上述两个内容信息,会产生冲突
  
    <Schooler>
        <Name>LiuYing</Name>
        <Age>23</Age>
        <Name>2014</Name>
        <Location>1#23#1</Location>
    </Schooler>
                    
  # 为了避免冲突,需要给可能冲突元素添加命名空间
  # xmlns: xml name space 的缩写
  
    <Schooler xmlns:student="http://my_student" xmlns:room="http://my_room">
        <student:Name>LiuYing</student:Name>
        <Age>23</Age>
        <room:Name>2014</room:Name>
        <Location>1#23#1</Location>
    </Schooler>

# XML访问## 读取
# XML读取分两个主要技术,SAX, DOM
# SAX(Simple API for XML):
    # 基于事件驱动的API
    # 利用SAX解析文档设计到解析器和事件处理两部分
    # 特点:
        # 快
        # 流式读取
        
# DOM
    # 是W3C规定的XML编程接口
    # 一个XML文件再缓存中以树形结构保存,读取
    # 用途
        # 定位浏览XML任何一个节点信息
        # 添加删除相应内容
    # minidom
        # minidom.parse(filename):加载读取的xml文件, filename也可以是xml代码
        # doc.documentElement:获取xml文档对象,一个xml文件只有一个对于的文档对象
        # node.getAttribute(attr_name):获取xml节点的属性值
        # node.getElementByTagName(tage_name):得到一个节点对象集合
        # node.childNodes:得到所有孩子节点
        # node.childNodes[index].nodeValue:获取单个节点值
        # node.firstNode:得到第一个节点,等价于node.childNodes[0]
        # node.attributes[tage_name]
  # 实例:

    import xml.dom.minidom
    # 负责解析xml文件
    from xml.dom.minidom import parse

    # 使用minidom打开xml文件
    DOMTree = xml.dom.minidom.parse("student.xml")
    #得到文档对象
    doc = DOMTree.documentElement

    # 显示子元素
    for ele in doc.childNodes:
        if ele.nodeName == "Teacher":
            print("-------Node:{0}-----".format(ele.nodeName))
            childs = ele.childNodes
            for child in childs:
                if child.nodeName == "Name":
                    # data是文本节点的一个属性,表示他的值
                    print("Name: {0}".format(child.childNodes[0].data))
                if child.nodeName == "Mobile":
                    # data是文本节点的一个属性,表示他的值
                    print("Mobile: {0}".format(child.childNodes[0].data))
                if child.nodeName == "Age":
                    # data是文本节点的一个属性,表示他的值
                    print("Age: {0}".format(child.childNodes[0].data))
                    if child.hasAttribute("detail"):
                        print("Age-detail: {0}".format(child.getAttribute("detail")))

    # etree 
        # 以树形结构来表示xml
        # root.getiterator:得到相应的可迭代的node集合
        # root.iter
        # find(node_name):查找指定node_name的节点,返回一个node
        # root.findall(node_name):返回多个node_name的节点
        # node.tag: node对应的tagename
        # node.text:node的文本值
        # node.attrib: 是node的属性的字典类型的内容
  #案例:

    import xml.etree.ElementTree

    root = xml.etree.ElementTree.parse("student.xml")
    print("利用getiterator访问:")
    nodes = root.getiterator()
    for node in nodes:
        print("{0}--{1}".format(node.tag, node.text))

    print("利用find和findall方法:")
    ele_teacher = root.find("Teacher")
    print("{0}--{1}".format(ele_teacher.tag, ele_teacher.text))

    ele_stus = root.findall("Student")
    for ele in ele_stus:
        print("{0}--{1}".format(ele.tag, ele.text))
        for sub in ele.getiterator():
            if sub.tag =="Name":
                if "Other" in sub.attrib.keys():
                    print(sub.attrib['Other'])

# xml文件写入
    # 更改
        # ele.set:修改属性
        # ele.append: 添加子元素
        # ele.remove:删除元素
        
  # 实例:

    import xml.etree.ElementTree as et

    tree = et.parse(r'to_edit.xml')
    root = tree.getroot()

    for e in root.iter('Name'):
        print(e.text)

    for stu in root.iter('Student'):
        name = stu.find('Name')

        if name != None:
            name.set( 'test', name.text * 2)

    stu = root.find('Student')
    #生成一个新的 元素
    e = et.Element('ADDer')
    e.attrib = {'a':'b'}
    e.text = '我加的'

    stu.append(e)

    # 一定要把修改后的内容写回文件,否则修改无效
    tree.write('to_edit.xml')


  # 生成创建
  # 方法1、SubElement

    import xml.etree.ElementTree as et

    stu = et.Element("Student1")

    name = et.SubElement(stu, 'Name')
    name.attrib = {'lang','en'}
    name.text = 'maozedong'

    age = et.SubElement(stu, 'Age')
    age.text = 18

    et.dump(stu)

  # 方法2、minidom 写入

    import xml.dom.minidom

    #在内存中创建一个空的文档
    doc = xml.dom.minidom.Document()
    #创建一个根节点Managers对象
    root = doc.createElement('Managers')
    #设置根节点的属性
    root.setAttribute('company', 'xx科技')
    root.setAttribute('address', '科技软件园')
    #将根节点添加到文档对象中
    doc.appendChild(root)

    managerList = [{'name' : 'joy',  'age' : 27, 'sex' : '女'},
                   {'name' : 'tom', 'age' : 30, 'sex' : '男'},
                   {'name' : 'ruby', 'age' : 29, 'sex' : '女'}
    ]

    for i in managerList :
      nodeManager = doc.createElement('Manager')
      nodeName = doc.createElement('name')
      #给叶子节点name设置一个文本节点,用于显示文本内容
      nodeName.appendChild(doc.createTextNode(str(i['name'])))

      nodeAge = doc.createElement("age")
      nodeAge.appendChild(doc.createTextNode(str(i["age"])))

      nodeSex = doc.createElement("sex")
      nodeSex.appendChild(doc.createTextNode(str(i["sex"])))

      #将各叶子节点添加到父节点Manager中,
      #最后将Manager添加到根节点Managers中
      nodeManager.appendChild(nodeName)
      nodeManager.appendChild(nodeAge)
      nodeManager.appendChild(nodeSex)
      root.appendChild(nodeManager)
    #开始写xml文档
    fp = open('Manager.xml', 'w')
    doc.writexml(fp, indent='\t', addindent='\t', newl='\n', encoding="utf-8")

  # 方法3、etree创建

    import xml.etree.ElementTree as et
    #在内存中创建一个空的文档
    etree = et.ElementTree()
    e = et.Element('Student')
    etree._setroot(e)
    e_name = et.SubElement(e, 'Name')
    e_name.text = "hahahah"
    etree.write('v06.xml')

#===========================JSON===========================
# 在线工具
  # https://www.sojson.com/
  # http://www.w3school.com.cn/json/
  # http://www.runoob.com/json/json#tutorial.html
  
# JSON(JavaScriptObjectNotation) 
# 轻量级的数据交换格式,基于ECMAScript

# json格式是一个键值对形式的数据集    
    # key: 字符串
    # value:字符串,数字,列表,json
    # json使用大括号包裹
    # 键值对直接用都好隔开  student={
      "name": "wangdapeng",
      "age": 18,
      "mobile":"13260446055"
      }
            
# json和python格式的对应
    # 字符串:字符串
    # 数字:数字
    # 队列:list
    # 对象:dict
    # 布尔值:布尔值
    
# python for json
    #实例

    # 导入json包
    import json

    # 此时student是一个dict格式内容,不是json
    student={
        "name": "luidana",
        "age": 18,
        "mobile":"15578875040"
    }
    
  # json和python对象的转换
    stu_json = json.dumps(student) #对数据编码,把python格式表示成json格式
    stu_dict = json.loads(stu_json)    #对数据解码,把json格式转换成python格式

  # python读取json文件
    with open("t.json", 'w') as f:
        json.dump(data, f)    #把内容写入文件

    with open("t.json", 'r') as f:
        d = json.load(f) #把json文件内容读入python
        print(d)

#===================正则表达式(RegularExpression, re)=====================
# 是一个计算机科学的概念
# 用于使用单个字符串来描述,匹配符合某个规则的字符串
# 常常用来检索,替换某些模式的文本

# 正则的写法
# .(点号):表示任意一个字符,除了\n, 比如查找所有的一个字符 \.
# []: 匹配中括号中列举的任意字符,比如[L,Y,0] , LLY, Y0, LIU
# \d: 任意一个数字
# \D:除了数字都可以
# \s:表示空格,tab键
# \S:除了空白符号
# \w: 单词字符, 就是a-z, A-Z, 0-9, _
# \W: 除了上面单词字符外
# {m,n}:允许前面内容出现最少m次,最多n次
# *: 表示前面内容重复零次或者多次, \w*,等价\w{0,}
# +: 表示前面内容至少出现一次,等价{1,}
# ?: 前面出现的内容零次或者一次,等价{0,1}
# ^:匹配字符串的开始
# $:匹配字符串的结尾
# \b:匹配单词的边界
# ():对正则表达式内容进行分组, 从第一个括号开始,编号逐渐增大
    
    #    例:
    #  验证一个数字: ^\d$
    #  必须有一个数字,最少一位:^\d+$
    #  只能出现数字,且位数为5-10位: ^\d{5,10}$
    #  注册者输入年龄,要求16岁以上,99岁以下: ^[16-99]$
    #  只能输入英文字符和数字: ^[A-Za-z0-9]$
    #  验证qq号码: [0-9]{5,12}
        
# \A: 只匹配字符串开头, \Aabcd, 则abcd
# \Z: 仅匹配字符串末尾, abcd\Z, abcd
# |: 左右任意一个
# (?P<name>...): 分组,除了原来的编号再制定一个别名, (?P<id>12345){2}, 1234512345
# (?P=name): 引用分组, 

#========================RE使用===================
#1、使用compile将表示正则的字符串编译为一个pattern对象
#2、通过pattern对象提供一系列方法对文本进行查找匹配,获得匹配结果,一个Match对象
#3、最后使用Match对象提供的属性和方法获得信息,根据需要进行操作#    Re常用函数
    #实例:

    import re
    # r表示字符不转义
    # re.l表示忽略大小写
    p = re.compile(r'([a-z]+) ([a-z]+)', re.l)
    # 在字符串中查找,按照规则进行查找
    # 返回结果是None,表示没有找到,否则返回Match对象
    # 参数3,6表示字符串中查找的范围
    # 查找到的结果只包含一个,表示第一次
    m = p.match("ljfa lkjf324 a2j43d afass gt4df", 3, 26)
    
    m.group() #表示匹配的结果

    m.start(0) #表示匹配的结果从哪个位置出发的
    m.end(0) #表示匹配的结果从哪个位置结束的
    m.span(0)    # 返回匹配成功的整个子串的跨度

    # 正则常用方法:
    # match(str): 从开始位置开始查找,一次匹配
    # search(str, [pos, [endpos]]):从任何位置查找,一次匹配,pos和endpos表示起止位置
    # findall: 全部匹配,返回列表, 案例v26
    # finditer: 全部匹配,返回迭代器, 案例v26
    # split: 分割字符串,返回列表
    # sub:替换
    
    f = p.findall("ljfa lkjf324 a2j43d afass gt4df")
    f.group(0) #表示整个匹配的结果
    f.group(1)    #表示第一组的结果
    f.start(1)
    f.end(1))
    f.span(1)    # 返回匹配成功的第一个子串的跨度
    
    #表示所有组的结果
    f.groups() #返回所有子串,tuple类型,等价于m.gourp(1), m.group(2)..


# sub替换找到的文本

    import re
    p = re.compile(r'(\w+) (\w+)')
    s = "aad dfa ggg dfd"
    rst = p.sub(r'替换的文本', s)

# 匹配中文
    #大部分中文内容表示范围是[u4e00-u9fa5],不包含全角标点
    re.compile(r'[\u4e00-\u9fa5]+')
    
# 贪婪和非贪婪
    # 贪婪:尽可能多的匹配,用"*"表示
    # 非贪婪:找到符合条件的最小内容即可,用"?"表示
    # 正则默认使用贪婪匹配
        # 例如:
        # 查找文本abbbbbbccc
        # re是 ab*
        # 贪婪模式: 结果是abbbbbb
        # 非贪婪: 结果是a
        
    # 默认贪婪
    re.compile(r".*")
    # 非贪婪
    re.compile(r".*?")
    
#========================XPath=====================
# 在XML文件中查找信息的一套规则/语言,根据XML的元素或者属性进行遍历
# 参见:http://www.w3school.com.cn/xpath/index.asp

# XPath 开发工具
# 开源的XPath表达式编辑工具:XMLQuire
# Chrome插件:XPath Helper
# Firefox插件: XPath Checker

# 选取节点
  Nodename # 选取此节点的所有子节点
  / # 从根节点开始选取
  例:/Student # 没有结果
  例:/School # 选取School节点
  // # 选取节点,不考虑位置
  例://age # 选取出三个节点,一般组成列表返回
  . # 选取当前节点
  .. # 选取当前节点的父节点
  @ # 选取属性
# xpath中查找一般按照路径方法查找,一下是路径表示方法
  School/Teacher # 返回Teacher节点
  School/Student # 返回两个Student节点
  //Student # 选取所有Studetn的节点,不考虑位置
  School//Age # 选取School后代中所有Age节点
  //@Other # 选取Other属性
  //Age[@Detail] # 选取带有属性Detail的Age元素
# 谓语-Predicates
  /School/Student[1] # 选取School下面的第一个Student节点
  /School/Student[last()] # 选取School下面的最后一个Student节点
  /School/Student[last()-1] # 选取School下面的倒数第二个Student节点
  /School/Student[position()<3] # 选取School下面的前二个Student节点
  //Student[@score] # 选取带有属性score的Student节点
  //Student[@score="99"] # 选取带有属性score并且属性值是99的Student节点
  //Student[@score]/Age # 选取带有属性score的Student节点的子节点Age

# 通配符
    # `*` : 任何元素节点
    # @*: 匹配任何属性节点
    # node(): 陪陪任何类型的节点
# 选取多个路径
    # //book/tile  | //book/author : 选取book元素中的title和author元素
    # //tile | //price: 选取文档中所有的title和price元素
    
# 其余不常见XPath运算符号包括+, - , *, div, >, <   # lxml库,etree
# python的HTML/XML的解析器
# 官方文档:   http://lxml.de/index.html
# 功能:
    # 解析HTML,修正HTML代码:
        # 利用etree.HTML把字符串解析成HTML文档
        text = 'xxxxxxxxx'
            html = etree.HTML(text)
            s = etree.tostring(html)
    # 文件读取如下案例
    # etree和XPath的配合使用:

    
from lxml import etree

# 只能读取xml格式内容,html报错
html = etree.parse("./x.xml")
# etree.tostring(html, pretty_print=True)
            
rst = html.xpath('//book')
# xpath的意识是,查找带有category属性值为sport的book元素
rst = html.xpath('//book[@category="sport"]')
# xpath的意识是,查找带有category属性值为sport的book元素下的year元素
rst = html.xpath('//book[@category="sport"]/year')
            
rst = rst[0]
print(type(rst))
print(rst.tag) #属性名
print(rst.text) #属性值

#====================CSS选择器  BeautifulSoup4===================
# http://beautifulsoup.readthedocs.io/zh_CN/v4.4.0/
# 几个常用提取信息工具的比较:
    # 正则: 很快,不好用,无需安装
    # beautifulsoup:慢,使用简单,安装简单
    # lxml: 比较快,使用简单,安装一般
    
# 四大对象
    # Tag
    # NavigableString
    # BeautifulSoup
    # Comment
# Tag
    # 对应Html中的标签
    # 可以通过soup.tag_name
    # tag两个重要属性
        # name
        # attrs
# NavigableString
    # 对应内容值
  
# BeautifulSoup
    # 表示的是一个文档的内容,大部分可以把他当做tag对象
    # 一般我们可以用soup来表示
# Comment
    # 特殊类型的NavagableString对象, 
    # 对其输出,则内容不包括注释符号
    
# 四大对象案例

from urllib import request
from bs4 import BeautifulSoup

url = "http://xxxxxxx"
rsp = request.urlopen(url)
content = rsp.read()
soup = BeautifulSoup(content, 'lxml')
        
print(soup.prettify()) # bs自动转码,得到所有html
        
print(soup.tag_name)    #html里的tag_name如head/link/...第一个标签
print(soup.tag_name.name) #tag_name标签里的标签名称
print(soup.tag_name.attrs)    #tag_name标签里的所有属性,返回字典类型
print(soup.tag_name.attrs['type']) #tag_name标签里的type属性值

print(soup.tag_name.string]) #tag_name标签里的内容
        
print(soup.name) #返回document
print(soup.attrs)

# 遍历文档对象
    # contents: tag的子节点以列表的方式给出 
    # children: 子节点以迭代器形式返回 
    # descendants: 所子孙节点
    # string
    
# 搜索文档对象
    # find_all(name, attrs, recursive, text, ** kwargs)  
        # name:按照那个字符串搜索,可以传入的内容为
            # 字符串
            # 正则表达式
            # 列表
        # kewwortd参数,可以用来表示属性
        # text: 对应tag的文本值
        
        tags = soup.find_all(re.compile('^me'), content="always")
        for tag in tags:
            print(tag)
            
# css选择器
    # 使用soup.select, 返回一个列表
    # 通过标签名称: soup.select("title")            
    # 通过类名: soup.select(".content")
    # id查找: soup.select("#name_id")
    # 组合查找: soup.select("div #input_content")
    # 属性查找: soup.select("img[class='photo'])
    # 获取tag内容: tag.get_text
        titles = soup.select("title")
        print(titles[0])
        metas = soup.select("meta[content='always']")
        print(metas[])
        
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值