美文网首页
lxml 及 HtmlElement

lxml 及 HtmlElement

作者: lifeLL | 来源:发表于2019-06-09 15:48 被阅读0次
    .attrib 属性和 .get()方法
    
    前者是html tag的属性集合,以字典表示;后者是取得某个属性的值,相当于字典的.get()方法。看示例:
    
    In [35]: doc = lxml.html.fromstring('<div class="post" id="123"><p class="para">abc<a href="/to-go">link</a></p></div>')
    
    In [37]: doc.attrib
    Out[37]: {'class': 'post', 'id': '123'}
    
    In [38]: doc.get('class')
    Out[38]: 'post'
    
    .drop_tag()方法
    
    移除该html tag,但保留它的子节点和文本并合并到该tag的父节点。
    
    In [46]: doc = lxml.html.fromstring('<div class="post" id="123"><p class="para">abc<a href="/to-go">link</a></p></div>')
    In [47]: doc.find('.//p').drop_tag()
    
    In [48]: lxml.html.tostring(doc)
    Out[48]: b'<div class="post" id="123">abc<a href="/to-go">link</a></div>'
    
    .drop_tree()方法   ('.//p')
    
    移除该节及其子节点和文本,而它后面的文本(tail text)合并到前面一个节点或父节点。
    
    In [50]: doc = lxml.html.fromstring('<div class="post" id="123"><p class="para">abc<a href="/to-go">link</a></p></div>')
    In [51]: doc.find('.//p').drop_tree()
    
    In [52]: lxml.html.tostring(doc)
    Out[52]: b'<div class="post" id="123"></div>'
    
    .drop_tree()方法
    
    移除该节及其子节点和文本,而它后面的文本(tail text)合并到前面一个节点或父节点。
    
    In [50]: doc = lxml.html.fromstring('<div class="post" id="123"><p class="para">abc<a href="/to-go">link</a></p></div>')
    In [51]: doc.find('.//p').drop_tree()
    
    In [52]: lxml.html.tostring(doc)
    Out[52]: b'<div class="post" id="123"></div>'
    
    通过path(Xpath)或tag查找特定节点,前者返回找到的第一个,第二个返回找到的全部HTMLElement,第三个返回找到的第一个的节点的文本(.text)
    
    In [55]: doc = lxml.html.fromstring('<div class="post" id="123"><p class="para">abc<a href="/to-go">link</a></p></div>')
    
    In [56]: doc.find('p')
    Out[56]: <Element p at 0x7fc40a4dd6d8>
    
    In [57]: doc.find('.//a')
    Out[57]: <Element a at 0x7fc409fee4a8>
    
    In [58]: doc.findall('p')
    Out[58]: [<Element p at 0x7fc40a4dd6d8>]
    
    In [76]: doc.findtext('.//a')
    Out[76]: 'link'
    
    
    .find_class(class_name)方法
    
    通过class名称查找所有含有class_name的元素,返回HtmlElement的列表
    
    In [70]: doc = lxml.html.fromstring('<div class="post" id="123"><p class="para">abc<a href="/to-go">link</a></p><p class="para p2"></p></div>')
    
    In [71]: doc.find_class('para')
    Out[71]: [<Element p at 0x7fc40a3ff278>, <Element p at 0x7fc40a3ffc78>]
    
    
    .get_element_by_id(id) 方法
    
    得到第一个id为输入id的节点。如果有多个相同id的节点(按道理讲,一个HTML文档里面的id是唯一的)只返回第一个。
    
    In [79]: doc = lxml.html.fromstring('<div class="post" id="123"><p class="para">abc<a href="/to-go">link</a></p></div>')
    
    In [80]: doc.get_element_by_id('123')
    Out[80]: <Element div at 0x7fc409fda2c8>
    
    .getchildren()、getparent() 方法
    
    顾名思义,获取 孩子节点和父节点。需要注意的是,还是可以有多个(返回list),父亲只有一个。
    
    In [83]: doc = lxml.html.fromstring('<div class="post" id="123"><p class="para">abc<a href="/to-go">link</a></p></div>')
    
    In [84]: doc.getchildren()
    Out[84]: [<Element p at 0x7fc410836b38>]
    
    In [85]: doc.getparent()
    Out[85]: <Element body at 0x7fc40a3ff9a8>
    # 注意:输入的本没有body,div已经是最上层节点,它的父节点就是body了
    
    .getnext() .getprevious() 方法
    
    获取后一个或前一个节点,如果没有则返回None。
    
    In [109]: doc = lxml.html.fromstring('<div><p>abc</p><p>xyz</p></div>')
    In [110]: doc.getnext()
    
    In [111]: doc.find('p').getnext()
    Out[111]: <Element p at 0x7fc409fdad68>
    
    In [112]: doc.find('p').getprevious()
    
    .getiterator()、.iter() 方法
    
    从该节点开始,按文档顺序(深度优先)遍历所有子节点。可以指定只遍历某些tag。
    
    In [127]: doc = lxml.html.fromstring('<div class="post" id="123"><p class="para">abc<a href="/to-go">link</a></p></div>')
    In [128]: for itr in doc.getiterator():
         ...:     print(itr.tag)
         ...: 
    div
    p
    a
    In [129]: for itr in doc.iter():
         ...:     print(itr.tag)
         ...: 
    div
    p
    a
    
    .iterchildren() 方法
    
    只遍历子节点。
    
    .iterancestors() .iterdescendants()方法
    
    前者遍历前辈(从父亲节点开始),后者遍历后辈(从子辈开始),都跳过该节点。
    
    In [134]: doc = lxml.html.fromstring('<div class="post" id="123"><p class="para">abc<a href="/to-go">link</a></p></div>')
    
    In [135]: a = doc.find('.//a')
    
    In [136]: for itr in doc.iterancestors():
         ...:     print(itr.tag)
         ...: 
    body
    html
    
    In [137]: for itr in a.iterancestors():
         ...:     print(itr.tag)
         ...: 
    p
    div
    body
    html
    
    In [138]: for itr in doc.iterdescendants():
         ...:     print(itr.tag)
         ...: 
    p
    a
    
    .iterfind(path) 方法
    
    遍历所有符合path的子节点,类似于findall()
    
    .make_links_absolute(base_url)
    
    很多网页的链接都是类似href=”/path/a.html”没有写全网址,这个方法的作用就是补全网址。
    
    .tag 属性
    
    该节点的html tag 名称
    
    .text  and  .tail 属性
    
    都是该节点的文本内容,不同的是一个在tag内,一个在尾部:
    
    <p>text</p>tail
    再看下面的代码
    
    In [173]: doc = lxml.html.fromstring('<div><p class="para">abc<a href="/to-go">link</a>worod</p>apple</div>')
    
    In [174]: p = doc.find('p')
    
    In [175]: p.text
    Out[175]: 'abc'
    
    In [176]: p.tail
    Out[176]: 'apple'
    
    
    .text_content() 方法
    
    返回给节点及其子节点包含的所有文本
    
    In [178]: doc.text_content()
    Out[178]: 'abclinkworodapple'
    
    lxml.html 从html字符串生成文档树结构
    
    我们下载得到的网页就是一串html字符串,如何把它输入给lxml.html模块,从而生成html文档的树结构呢?
    该模块提供了几种不同的方法:
    
    parse(filename_url_or_file):
    输入的是一个文件名、URL或文件对象(有read()方法)。
    document_fromstring(string):
    输入的是一个html的字符串,创建一个HTML文档树结构,它的根节点就是, 和 子节点。
    fragment_fromstring(string, create_parent=False):
    返回输入字符串的HTML片段。这个片段壁纸只含有一个element(元素),也就是单一节点,除非给出了create_parent 参数,否则会报错。
    fragments_fromstring(string):
    返回包含输入字符串中所有片段的列表。
    fromstring(string):
    返回值依据输入字符串而定,如果输入看起来像是一个文档,则返回document_fromstring(string),如果是一个单一片段,则返回fragment_fromstring(string)。
    下面我们通过具体示例来说明上面几个方法的不同。
    
    document_fromstring 的使用方法
    
    In [1]: import lxml.html  as lh
    
    In [2]: z = lh.document_fromstring('<span>abc</span><span>xyz</span>')
    # 可以看到,它自动加了根节点<html>
    In [3]: z
    Out[3]: <Element html at 0x7fc410667b88>
    
    In [4]: z.tag
    Out[4]: 'html'
    # 还加了<body>节点
    In [5]: z.getchildren()
    Out[5]: [<Element body at 0x7fc4101a3ae8>]
    # 把字符串的两个节点放在了<body>里面
    In [6]: z.getchildren()[0].getchildren()
    Out[6]: [<Element span at 0x7fc410092bd8>, <Element span at 0x7fc410667c28>]
    fragment_fromstring 的使用
    
    In [11]: z = lh.fragment_fromstring(‘<div>abc</div><div>xyz</div>’)
    ---------------------------------------------------------------------------
    ParserError                               Traceback (most recent call last)
    <ipython-input-11-a11f9a0f71d1> in <module>()
    ----> 1 z = lh.fragment_fromstring(‘<div>abc</div><div>xyz</div>’)
    
    ~/.virtualenvs/py3.6/lib/python3.6/site-packages/lxml/html/__init__.py in fragment_fromstring(html, create_parent, base_url, parser, **kw)
        850         raise etree.ParserError(
        851             “Multiple elements found (%s)”
    --> 852             % ‘, ‘.join([_element_name(e) for e in elements]))
        853     el = elements[0]
        854     if el.tail and el.tail.strip():
    ParserError: Multiple elements found (div, div)
    # 可以看到,输入是两个节点(element)时就会报错
    # 如果加上 create_parent 参数,就没问题了
    In [12]: z = lh.fragment_fromstring('<div>abc</div><div>xyz</div>', create_parent='p')
    
    In [13]: z.tag
    Out[13]: 'p'
    
    In [14]: z.getchildren()
    Out[14]: [<Element div at 0x7fc40a41a818>, <Element div at 0x7fc40a41aea8>]
    
    fragments_fromstring 的使用
    
    # 输入字符串含有一个节点,则返回包含这一个节点的列表
    In [17]: lh.fragments_fromstring('<div>abc</div>')
    Out[17]: [<Element div at 0x7fc40a124ea8>]
    
    # 输入字符串含有多个节点,则返回包含这多个节点的列表
    In [18]: lh.fragments_fromstring('<div>abc</div><div>xyz</div>')
    Out[18]: [<Element div at 0x7fc40a124b88>, <Element div at 0x7fc40a124f98>]
    fromstring 的使用
    
    
    In [27]: z = lh.fromstring('<div>abc</div><div>xyz</div>')
    
    In [28]: z
    Out[28]: <Element div at 0x7fc40a0eb368>
    
    In [29]: z.getchildren()
    Out[29]: [<Element div at 0x7fc410135548>, <Element div at 0x7fc40a0eb2c8>]
    
    In [30]: type(z)
    Out[30]: lxml.html.HtmlElement
    
    这里,fromstring输入的如果是多个节点,它会给加一个父节点并返回。但是像html网页都是从节点开始的,我们使用fromstring() 和 document_fromstring() 都可以得到完整的网页结构。
    
    从上面代码中我们可以看到,那几个函数返回的都是HtmlElement对象
    

    from : https://www.yuanrenxue.com/crawler/extract-data-lxml-xpath.html

    相关文章

      网友评论

          本文标题:lxml 及 HtmlElement

          本文链接:https://www.haomeiwen.com/subject/mvhnxctx.html