千家信息网

lxml与pyquery解析html的方法

发表于:2025-02-08 作者:千家信息网编辑
千家信息网最后更新 2025年02月08日,本篇内容主要讲解"lxml与pyquery解析html的方法",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"lxml与pyquery解析html的方法"吧!
千家信息网最后更新 2025年02月08日lxml与pyquery解析html的方法

本篇内容主要讲解"lxml与pyquery解析html的方法",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"lxml与pyquery解析html的方法"吧!

lxml

首先来了解一下lxml,很多常用的解析html的库都用到了lxml这个库,例如BeautifulSoup、pyquery。

下面我们介绍一下lxml关于html解析的3个Element。

_Element

_Element获取
from lxml import etreetext = ''''''# lxml.etree._Elementelement = etree.HTML(text)
_Element常用方法
# 通过css选择器获取节点cssselect(expr)# 通过标签或者xpath语法获取第一个匹配find(path)# 通过标签或者xpath语法获取所有匹配findall(path)# 获取属性值get(key)# 获取所有属性items()# 获取所有属性名称keys()# 获取所有属性值values()# 获取子节点getchildren()# 获取父节点getparent()# 获取相邻的下一个节点getnext()# 获取相邻的上一个节点getprevious()# 迭代节点iter(tag)# 通过xpath表达式获取节点xpath(path)
_Element示例
from lxml import etreetext = ''''''element = etree.HTML(text)# css选择器,获取class为item-0的li节点lis = element.cssselect("li.item-0")for li in lis:    # 获取class属性    print(li.get("class"))    # 获取属性名称和值,元组列表    print(li.items())    # 获取节点所有的属性名称    print(li.keys())    # 获取所有属性值    print(li.values())print("--------------")ass = element.cssselect("li a")for a in ass:    # 获取文本节点    print(a.text)print("--------------")# 获取第一个li节点li = element.find("li")# 获取所有li节点lis = element.find("li")# 获取所有的a节点lias = element.iter("a")for lia in lias:    print(lia.get("href"))textStr = element.itertext("a")for ts in textStr:    print(ts)

xpath我们后面单独介绍。

_ElementTree

_ElementTree获取
from io import StringIOfrom lxml import etreetext = ''''''parser = etree.HTMLParser()# lxml.etree._ElementTreeelementTree = etree.parse(StringIO(text), parser)# 可以直接从文件读取# elementTree = etree.parse(r'F:\tmp\etree.html',parser)
_ElementTree常用方法
find(path)findall(path)iter(tag)xpath(path)

_ElementTree方法和 _Element的同名方法使用基本一样。

有很多不同的是_ElementTree的find和findall方法只接受xpath表达式。

_ElementTree示例
from io import StringIOfrom lxml import etreetext = ''''''parser = etree.HTMLParser()elementTree = etree.parse(StringIO(text), parser)lis = elementTree.iter("li")for li in lis:    print(type(li))print("---------")firstLi = elementTree.find("//li")print(type(firstLi))print(firstLi.get("class"))print("---------")ass = elementTree.findall("//li/a")for a in ass:    print(a.text)

HtmlElement

HtmlElement获取
import lxml.htmltext = ''''''# lxml.html.HtmlElementhtmlElement = lxml.html.fromstring(text)

HtmlElement继承了etree.ElementBase和HtmlMixin,etree.ElementBase继承了_Element。

因为HtmlElement继承了_Element,所以_Element中介绍的方法,HtmlElement都可以使用。 HtmlElement还可以使用HtmlMixin中的方法。

HtmlMixin常用方法
# 通过类名获取节点find_class(class_name)# 通过id获取节点get_element_by_id(id)# 获取文本节点text_content()# 通过css选择器获取节点cssselect(expr)

xpath

xpath功能非常强大,并且_Element、_ElementTree、HtmlElement都可以使用xpath表达式,所以最后介绍一下xpath。

表达式描述
/从根节点开始,绝对路径
//从当前节点选取子孙节点,相对路径,不关心位置
.选取当前节点
..选取当前节点的父节点
@选取属性
*通配符,选择所有元素节点与元素名
@*选取所有属性
[@attrib]选取具有给定属性的所有元素
[@attrib='value']选取给定属性具有给定值的所有元素
[tag]选取所有具有指定元素的直接子节点
[tag='text']选取所有具有指定元素并且文本内容是text节点
expression表达式描述
ancestorxpath('./ancestor:: *')选取当前节点的所有先辈节点
ancestor-or-self('./ancestor-or-self:: *')选取当前节点的所有先辈以及节点本身
attributexpath('./attribute:: *')选取当前节点的所有属性
childxpath('./child:: *')返回当前节点的所有子节点
descendantxpath('./descendant:: *')返回当前节点的所有后代节点(子节点、孙节点)
followingxpath('./following:: *')选取文档中当前节点结束标签后的所有节点
following-sibingxpath('./following-sibing:: *')选取当前节点之后的兄弟节点
parentxpath('./parent:: *')选取当前节点的父节点
precedingxpath('./preceding:: *')选取文档中当前节点开始标签前的所有节点
preceding-siblingxpath('./preceding-sibling:: *')选取当前节点之前的兄弟节点
selfxpath('./self:: *')选取当前节点

很多时候我们可以通过浏览器获取xpath表达式:

示例
from lxml.html.clean import Cleanerfrom lxml import etreetext = ''''''# 去除css、scriptcleaner = Cleaner(style=True, scripts=True, page_structure=False, safe_attrs_only=False)print(cleaner.clean_html(text))# _Elementelement = etree.HTML(text)# 文本节点,特殊字符转义print(element.xpath('//text()'))# 文本节点,不转义print(element.xpath('string()'))# find、findall只能使用相对路径,以.//开头print(element.findall('.//a[@rel]'))print(element.find('.//a[@rel]'))# 获取包含rel属性的a节点print(element.xpath('//a[@rel]'))# 获取ul元素下的第一个li节点,注意是列表,因为ul可能有多个print(element.xpath("//ul/li[1]"))# 获取ul元素下rel属性为li2的li节点print(element.xpath("//ul/li[@rel='li2']"))# 获取ul元素下的倒数第2个节点print(element.xpath("//ul/li[last()-1]"))# 获取ul元素下的前2个li节点print(element.xpath("//ul/li[position()<3]"))# 获取li元素下的所有a节点for a in element.xpath("//li/a"):    print(a.text)    print(a.get("href"))# 获取父节点,列表,因为可能匹配多个aprint(element.xpath('//a[@href="link2.html"]/parent::*'))# 获取的是文本节点对象列表print(element.xpath('//li[@class="item-1"]/a/text()'))print("---------------")# 获取a的href属性print(element.xpath('//li/a/@href'))# 获取所有li子孙节点的href属性print(element.xpath('//li//@href'))

xpath示例

from lxml import etreetext = '''
  • 解忧杂货店

    [日] 东野圭吾 / 李盈春 / 南海出版公司 / 2014-5 / 39.50元
    8.5 (537322人评价)

    现代人内心流失的东西,这家杂货店能帮你找回--僻静的街道旁有一家杂货店,只要写下烦恼投进卷帘门的投信口,第二天就会在店后的牛奶箱里得到回答。因男友身患绝...

  • '''element = etree.HTML(text)# 查找符合xpath(//li/div/a)的节点aeles = element.xpath("//li/div/a")for aele in aeles: # 获取href属性 print(aele.get("href")) # 查找img标签,并且获取src属性 print(aele.find("img").get("src"))# 返回列表的原因是:虽然我们只取了第一个a节点,但是上级xpath(//li/div[@class='info']/h3)可能匹配多个for a in element.xpath("//li/div[@class='info']/h3/a[1]"): print(a.get("href")) print(a.text) # print(a.get("title"))# 指定div的class属性for pu in element.xpath("//li/div[@class='info']/div[@class='pub']"): print(pu.text)# 使用到contains函数和or运算符spans = element.xpath("//li/div[@class='info']/div[@class='star clearfix']/span[contains(@class,'rating_nums') or " "contains(@class,'pl')]")for span in spans: print(span.text.strip())for content in element.xpath("//li/div[@class='info']/p"): print(content.text)# 如果确定只有一个或者只需要第一个可以使用find,注意find使用xpath为参数的时候使用相对路径(.//开头)print(element.find(".//li/div[@class='info']/p").text)

    pyquery

    构造PyQuery

    从字符串:

    from pyquery import PyQuery as pqhtml = ''with open(r"F:\tmp\db.html", "r", encoding='utf-8') as f:    html = f.read()doc = pq(html)

    从URL:

    from pyquery import PyQuery as pqheaders = {    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:69.0) Gecko/20100101 Firefox/69.0'}doc = pq('https://book.douban.com/tag/小说', headers=headers)

    从文件:

    from pyquery import PyQuery as pqdoc = pq(filename=r"F:\tmp\db.html")

    从文件有一个问题就是不能指定文件编码,所以一般都是自己读取文件,然后从字符串构造。

    选择器

    pyquery最强大的地方就在于,它可以像jQuery使用css选择器一样获取节点。

    常用的一些选择器:

    id选择器(#id) 类选择器(.class) 属性选择器(a[href="xxx"]) 伪类选择器(:first :last :even :odd :eq :lt :gt :checked :selected)

    前面我们已经知道怎样构造一个PyQuery,上面我们有知道了怎么通过选择器获取节点,下面我们通过一个小示例来具体了解一下。

    from pyquery import PyQuery as pqhtml = '''                    pyquery                 
    • li1
    • li2
    • li3
    '''doc = pq(html)# id选择器,outerHtml输出整体的htmlprint(doc("#container").outerHtml())print("----------")# 类选择器print(doc(".li1").outerHtml())print("----------")# 伪类选择器# 选择第2个li节点,并通过text获取该li节点的值print(doc('li:nth-child(2)').text())# 获取第1个li节点print(doc('li:first-child').text())# 获取最后一个li节点,并通过attr获取该节点的data-type属性值print(doc('li:last-child').attr("data-type"))print(doc("li:contains('li3')").attr("data-type"))print("----------")# 属性选择器# 选择li的data-type的属性值为3的节点print(doc("li[data-type='3']").outerHtml())

    首先我们通过html字符串构造了一个PyQuery对象,然后就可以通过选择器愉快的获取我们想要的节点了。

    注意:上面的text方法是获取节点的文本,attr是获取节点的属性,非常常用

    这里就补贴输出代码了,如果感兴趣可以自己动手尝试一下,看一下输出。

    查找与过滤节点

    很多时候,我们并不能直接通过选择器一步到位的获取到我们需要的节点,所以我们需要另外一些查找、过滤、遍历节点的方法,例如:find、filter、eq、not_、items、each等,下面我们还是通过一个小例子来介绍一下这些方法。

    from pyquery import PyQuery as pqhtml = '''                    pyquery                 
    • li1
    • li2
    • li3
    '''doc = pq(html)# find的语法和直接使用选择器一样print("---find:")print(doc.find("li").show())# 输出li的个数print(doc.find("li").size())# filter过滤得到满足条件的print("---filter:")print(doc.find("li").filter(".li3").show())# eq选择第n个,下标从0开始print("---eq:")print(doc.find("li").eq(1).show())# not_排除满足条件的节点print("---not_:")print(doc.find("li").not_("li[data-type='3']").show())lis = doc.find("li")# 输出PyQueryprint(type(lis))# each输出的类型是lxml.etree._Elementprint("---each:")lis.each(lambda i, e: print(type(e)))print("---for:")for li in lis: print(type(li))# items获取到的类型才是PyQueryprint("---items:")for li in lis.items(): print(type(li))

    这些方法还是比较基础的,看代码中的注释就能知道是什么意思了,如果有疑问,可以自己动手调试一下。

    注意lis是PyQuery类型,PyQuery的each是lxml.etree._Element类型,items才是PyQuery

    这意味着使用for\each循环不能使用PyQuery的find、filter、text、attr这些方法。

    需要使用lxml.etree._Element的方法。

    到此,相信大家对"lxml与pyquery解析html的方法"有了更深的了解,不妨来实际操作一番吧!这里是网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

    0