Python爬虫笔记3-解析库Xpat

发布时间:2019-09-25 08:13:24编辑:auto阅读(1678)

    当爬取到Html数据后,可以用正则对数据进行提取,但有时候正则表达式编写起来不方便,而且万一写错了,可能导致匹配失败。这时候就需要借助其他解析工具了。

    XML引入

    什么是XML?

    • XML 指可扩展标记语言(EXtensible Markup Language)
    • XML 是一种标记语言,很类似 HTML
    • XML 的设计宗旨是传输数据,而非显示数据
    • XML 的标签需要我们自行定义。
    • XML 被设计为具有自我描述性。
    • XML 是 W3C 的推荐标准

    W3School官方文档:http://www.w3school.com.cn/xm...

    XML和HTML的区别

    语法要求不同

    • 在html中不区分大小写,在xml中严格区分。
    • 在HTML中,有时不严格,如果上下文清楚地显示出段落或者列表键在何处结尾,那么你可以省略</p>或者</li>之类的结束标记。在XML中,是严格的树状结构,绝对不能省略掉结束标记。
    • 在XML中,拥有单个标记而没有匹配的结束标记的元素必须用一个/ 字符作为结尾。这样分析器就知道不用查找结束标记了。
    • 在XML中,属性值必须分装在引号中。在HTML中,引号是可用可不用的。
    • 在HTML中,可以拥有不带值的属性名。在XML中,所有的属性都必须带有相应的值。
    • 在XML文档中,空白部分不会被解析器自动删除;但是html是过滤掉空格的。

    设计目标不同

    • XML被设计为传输和存储数据,其焦点是数据的内容。
    • HTML显示数据以及如何更好显示数据。

    XML的节点关系

    1、父(parent)
    每个元素以及属性都有一个父。
    下面是一个简单的XML例子中,book 元素是 title、author、year 以及 price 元素的父:

    <?xml version="1.0" encoding="utf-8"?>
    
    <book>
      <title>Harry Potter</title>
      <author>J K. Rowling</author>
      <year>2005</year>
      <price>29.99</price>
    </book>
    

    2、 子(Children)
    元素节点可有零个、一个或多个子。
    在下面的例子中,title、author、year 以及 price 元素都是 book 元素的子:

    <?xml version="1.0" encoding="utf-8"?>
    
    <book>
      <title>Harry Potter</title>
      <author>J K. Rowling</author>
      <year>2005</year>
      <price>29.99</price>
    </book>
    

    3、 同胞(Sibling)
    拥有相同的父的节点
    在下面的例子中,title、author、year 以及 price 元素都是同胞:

    <?xml version="1.0" encoding="utf-8"?>
    
    <book>
      <title>Harry Potter</title>
      <author>J K. Rowling</author>
      <year>2005</year>
      <price>29.99</price>
    </book>
    

    4、 先辈(Ancestor)
    某节点的父、父的父,等等。
    在下面的例子中,title 元素的先辈是 book 元素和 bookstore 元素:

    <?xml version="1.0" encoding="utf-8"?>
    
    <bookstore>
    
    <book>
      <title>Harry Potter</title>
      <author>J K. Rowling</author>
      <year>2005</year>
      <price>29.99</price>
    </book>
    
    </bookstore>
    

    5、 后代(Descendant)
    某个节点的子,子的子,等等。
    在下面的例子中,bookstore 的后代是 book、title、author、year 以及 price 元素:

    <?xml version="1.0" encoding="utf-8"?>
    
    <bookstore>
    
    <book>
      <title>Harry Potter</title>
      <author>J K. Rowling</author>
      <year>2005</year>
      <price>29.99</price>
    </book>
    
    </bookstore>
    

    Xpath

    什么是Xpath?

    Xpath,全称XML Path Language,即XML路径语言,它是一门在XML文档中查找信息的语言,可用来在 XML 文档中对元素和属性进行遍历。。最初是用来搜寻XML文档的,但是它也适用与HTML文档的搜索。
    所以在做爬虫时,可以使用XPath来做相应的信息抽取。

    W3School官方文档:http://www.w3school.com.cn/xp...

    Xpath开发工具

    1. 开源的XPath表达式编辑工具:XMLQuire(XML格式文件可用)
    2. Chrome插件 XPath Helper
    3. Firefox插件 XPath Checker

    使用Xpath

    XPath 使用路径表达式来选取 XML 文档中的节点或者节点集。这些路径表达式和我们在常规的电脑文件系统中看到的表达式非常相似。
    1、Xpath常用规则

    表达式 描述
    nodename 选取此节点的所有子节点
    / 从当前节点选取直接子节点
    // 从当前节点选取子孙节点
    . 选取当前节点
    .. 选取当前节点的父节点
    @ 选取属性

    2、Xpath使用示例
    以下面xmL文档为例:

    <?xml version="1.0" encoding="utf-8"?>
    
    <bookstore>
    
    <book>
      <title>Harry Potter</title>
      <author>J K. Rowling</author>
      <year>2005</year>
      <price>29.99</price>
    </book>
    
    </bookstore>
    路径表达式 结果
    bookstore 选取bookstore元素的所有子节点
    /bookstore 选取根元素bookstore。注:假如路径起始于正斜杠/,则此路径代表某元素的绝对路径
    bookstore/book 选取属于bookstore的子元素的所有book元素
    //book 选取所有book元素,不管在文档的任何位置
    bookstore//book 选择属于 bookstore 元素的后代的所有 book 元素,而不管它们位于 bookstore 之下的什么位置。
    //@lang 选取名为lang的所有属性

    lxml库使用

    lxml库安装

    1、window安装
    cmd进入命令行模式,执行

    pip3 install lxml
    

    2、ubuntu16.04安装
    ctrl+alt+t进入终端模式,执行:

    sudo apt-get install -y build-essential libssl-devl libffi-dev libxml2-dev libxslt1-dev zlib1g-dev
    

    安装依赖的类库后,执行pip安装:

    sudo pip3 install lxml
    

    3、验证安装
    导入lxml模块,如果没有报错就安装成功。

    $ python3
    >>> import lxml
    

    etree模块使用

    初步使用
    文件名lxml_test.py

    # 使用 lxml 的 etree 库
    from lxml import etree 
    
    text = '''
    <div>
        <ul>
             <li class="item-0"><a href="link1.html">first item</a></li>
             <li class="item-1"><a href="link2.html">second item</a></li>
             <li class="item-inactive"><a href="link3.html">third item</a></li>
             <li class="item-1"><a href="link4.html">fourth item</a></li>
             <li class="item-0"><a href="link5.html">fifth item</a> # 注意,此处缺少一个 </li> 闭合标签
         </ul>
     </div>
    '''
    
    #利用etree.HTML,将字符串解析为HTML文档,etree模块可自动修正HTML文本
    html = etree.HTML(text) 
    
    # 按字符串序列化HTML文档
    ret = etree.tostring(html) 
    
    # torstring()方法返回的结果是bytes类型,这里用decode()方法将其转化为字符串
    print(ret.decode('utf-8'))
    

    输出结果:

    <html><body>
    <div>
        <ul>
             <li class="item-0"><a href="link1.html">first item</a></li>
             <li class="item-1"><a href="link2.html">second item</a></li>
             <li class="item-inactive"><a href="link3.html">third item</a></li>
             <li class="item-1"><a href="link4.html">fourth item</a></li>
             <li class="item-0"><a href="link5.html">fifth item</a></li>
    </ul>
     </div>
    </body></html>

    etree模块可以自动修正 html 代码,例子里不仅补全了 li 标签,还添加了 body,html 标签。

    文件读取
    除了直接读取字符串,lxml还支持从文件里读取内容。这里我将上面的lxml_test.py文件执行后的内容保存为test.html

    python lxml_test.py >> test.html
    

    内容就是上面的输出结果 cat test.html:

    <div>
        <ul>
             <li class="item-0"><a href="link1.html">first item</a></li>
             <li class="item-1"><a href="link2.html">second item</a></li>
             <li class="item-inactive"><a href="link3.html"><span class="bold">third item</span></a></li>
             <li class="item-1"><a href="link4.html">fourth item</a></li>
             <li class="item-0"><a href="link5.html">fifth item</a></li>
         </ul>
     </div>
    

    使用etree.parse()方法来读取文件。

    from lxml import etree
    
    html = etree.parse('./test.html',HTMLParser())
    
    ret = etree.tostring(html)
    print(ret.decode('utf-8'))

    输出结果

    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
    <html><body>
    <div>
        <ul>
             <li class="item-0"><a href="link1.html">first item</a></li>
             <li class="item-1"><a href="link2.html">second item</a></li>
             <li class="item-inactive"><a href="link3.html">third item</a></li>
             <li class="item-1"><a href="link4.html">fourth item</a></li>
             <li class="item-0"><a href="link5.html">fifth item</a></li>
    </ul>
     </div>
    </body></html>

    输出结果多了一个DOCTYPE声明,对解析结果没影响。

关键字