首頁 > web前端 > html教學 > 用lxml解析HTML的方法

用lxml解析HTML的方法

高洛峰
發布: 2017-03-12 17:51:27
原創
2003 人瀏覽過

這篇文章介紹用lxml解析HTML的方法

先示範一段取得頁面連結程式碼範例:

#coding=utf-8
from lxml import etree
html = '''
<html>
  <head>
    <meta name="content-type" content="text/html; charset=utf-8" />
    <title>友情链接查询 - 站长工具</title>
    <!-- uRj0Ak8VLEPhjWhg3m9z4EjXJwc -->
    <meta name="Keywords" content="友情链接查询" />
    <meta name="Description" content="友情链接查询" />
  </head>
  <body>
    <h1 class="heading">Top News</h1>
    <p style="font-size: 200%">World News only on this page</p>
    Ah, and here&#39;s some more text, by the way.
    <p>... and this is a parsed fragment ...</p>
    <a href="http://www.cydf.org.cn/" rel="nofollow" target="_blank">青少年发展基金会</a> 
    <a href="http://www.4399.com/flash/32979.htm" target="_blank">洛克王国</a> 
    <a href="http://www.4399.com/flash/35538.htm" target="_blank">奥拉星</a> 
    <a href="http://game.3533.com/game/" target="_blank">手机游戏</a>
    <a href="http://game.3533.com/tupian/" target="_blank">手机壁纸</a>
    <a href="http://www.4399.com/" target="_blank">4399小游戏</a> 
    <a href="http://www.91wan.com/" target="_blank">91wan游戏</a>
  </body>
</html>
&#39;&#39;&#39;
page = etree.HTML(html.lower().decode(&#39;utf-8&#39;))
hrefs = page.xpath(u"//a")
for href in hrefs:
  print href.attrib
登入後複製

 

列印出的結果為:

{'href': 'http://www.cydf.org.cn/', 'target': '_blank', 'rel': 'nofollow'}
{ 'href': 'http://www.4399.com/flash/32979.htm', 'target': '_blank'}
{'href': 'http://www.4399.com/flash /35538​​.htm', 'target': '_blank'}
{'href': 'http://game.3533.com/game/', 'target': '_blank'}
{' href': 'http://game.3533.com/tupian/', 'target': '_blank'}
{'href': 'http://www.4399.com/', 'target' : '_blank'}
{'href': 'http://www.91wan.com/', 'target': '_blank'}

如果要取得之間的內容,

for href in hrefs:

#  print href.text

結果為:

青少年發展基金會
洛克王國
奧拉星
手機遊戲
手機壁紙
4399小遊戲
91wan遊戲

 

  使用lxml前註意事項:先確保html經過了utf-8解碼,即code = html.decode('utf-8', 'ignore'),否則會出現解析出錯情況。因為中文被編碼成utf-8之後變成 '/u2541' 之類的形式,lxml一遇到 「/」就會認為其標籤結束。

 

  XPATH基本上是用一種類似目錄樹的方法來描述在XML文件中的路徑。例如用“/”來作為上下層級間的分隔。第一個「/」表示文檔的根節點(注意,不是指文檔最外層的tag節點,而是指文檔本身)。例如對於一個HTML檔案來說,最外層的節點應該是"/html"。

定位某一個HTML標籤,可以使用類似檔案路徑裡的絕對路徑,如page.xpath(u"/html/body/p"),它會找到body這個節點下所有的p標籤;也可以使用類似檔案路徑裡的相對路徑,可以這樣使用:page.xpath(u"//p"),它會找到整個html程式碼裡的所有p標籤:

    

World News only on this page


    Ah, and here's some more text, 1. . and this is a parsed fragment ...


注意:XPATH回傳的不一定就是唯一的節點,而是符合條件的所有節點。如上所示,只要是body裡的p標籤,不管是body的第一級節點,還是第二級,第三級節點,都會被取出來。

  如果想進一步縮小範圍,直接定位到「

World News only on this page

」要怎麼做呢?這就需要增加過濾條件。過濾的方法就是用「[」「]」加上過濾條件。 lxml裡有個過濾語法:

    p = page.xpath(u"/html/body/p[@style='font-size: 200%']")

  或: p = page.xpath(u"//p[@style='font-size:200%']")

  這樣就取出了body裡style為font-size:200%的p節點,注意:這個p

變數是一個lxml.etree._Element物件列表,p[0].text結果是World News only on this page,即標籤之間的值;p [0].values()結果為font-size: 200%,即所有屬性值。其中 @style表示屬性style,類似地還可以使用如@name, @id, @value, @href, @src, @class....

  如果標籤裡面沒有屬性怎麼辦?那就可以用text(),

position()等函數來過濾,函數text()的意思是取得節點所包含的文字。例如:

hello

world

< /p>中,用"p[text()='hello']"即可取得這個p,而world則是p的text() 。函數position()的意思是取得節點的位置。例如「li[position()=2]」表示取得第二個li節點,它也可以省略為「li[2]」。

不過要注意的是數字定位和過濾 條件的順序。例如「ul/li[5][@name='hello']」表示取ul下第五項li,其name必須是hello,否則回傳空。而如果用 “ul/li[@name='hello'][5]”的意思就不同,它表示尋找ul下第五個name為"hello“的li節點。

  此外,“*”可以代替所有的节点名,比如用"/html/body/*/span"可以取出body下第二级的所有span,而不管它上一级是p还是p或是其它什么东东。

而 “descendant::”前缀可以指代任意多层的中间节点,它也可以被省略成一个“/”。比如在整个HTML文档中查找id为“leftmenu”的 p,可以用“/descendant::p[@id='leftmenu']”,也可以简单地使用“ //p[@id='leftmenu']”。

text = page.xpath(u"/descendant::*[text()]")表示任意多层的中间节点下任意标签之间的内容,也即实现蜘蛛抓取页面内容功能。以下内容使用text属性是取不到的:

<p class="news">
    1. <b>无流量站点清理公告</b>  2013-02-22<br />
    取不到的内容
    </p>
    <p class="news">
    2. <strong>无流量站点清理公告</strong>  2013-02-22<br />
取不到的内容
</p> <p class="news"> 3. <span>无流量站点清理公告</span>  2013-02-22<br />
取不到的内容
</p> <p class="news"> 4. <u>无流量站点清理公告</u>  2013-02-22<br />
取不到的内容
</p>
登入後複製

这些“取不到的内容”使用这个是取不到的。怎么办呢?别担心,lxml还有一个属性叫做“tail”,它的意思是结束节点前面的内容,也就是说在“
”与“

”之间的内容。它的源码里面的意思是“text after end tag”

  至于“following-sibling::”前缀就如其名所说,表示同一层的下一个节点。"following-sibling::*"就是任意下一个节点,而“following-sibling::ul”就是下一个ul节点。

  如果script与style标签之间的内容影响解析页面,或者页面很不规则,可以使用lxml.html.clean模块。模块 lxml.html.clean 提供 一个Cleaner 类来清理 HTML 页。它支持删除嵌入或脚本内容、 特殊标记、 CSS 样式注释或者更多。

  cleaner = Cleaner(style=True, scripts=True,page_structure=False, safe_attrs_only=False)

  print cleaner.clean_html(html)

  注意,page_structure,safe_attrs_only为False时保证页面的完整性,否则,这个Cleaner会把你的html结构与标签里的属性都给清理了。使用Cleaner类要十分小心,小心擦枪走火。

 

  忽略大小写可以:

  page = etree.HTML(html)
  keyword_tag = page.xpath("//meta[translate(@name,'ABCDEFGHJIKLMNOPQRSTUVWXYZ', 'abcdefghjiklmnopqrstuvwxyz')='keywords']")


以上是用lxml解析HTML的方法的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板