ホームページ >ウェブフロントエンド >htmlチュートリアル >lxml を使用して HTML を解析する方法

lxml を使用して HTML を解析する方法

高洛峰
高洛峰オリジナル
2017-03-12 17:51:271999ブラウズ

この記事では、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', 'ターゲット ': '_blank'}
{'href': 'http://www.4399.com/flash/35538​​.htm', 'ターゲット': '_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 '}

3499910bf9dac5ae3c52d5ede73834855db79b134e9f6b82c0b36e0489ee08edの間のコンテンツを取得したい場合は、

for href in hrefs:

print href.text

結果は次のようになります:

青少年育成財団
ロックキングダム
Ola Star
モバイルゲーム
モバイル壁紙
4399 ミニゲーム
91wan ゲーム

lxml を使用する前に注意すべきこと: まず、HTML が utf-8 でデコードされていること、つまり code = html.decode(' utf-8', 'ignore') 、それ以外の場合は解析エラーが発生します。中国語は utf-8 にエンコードされて「/u2541」のような形式になるため、lxml は「/」に遭遇したときにタグが終了するとみなします。

XPATHは基本的にディレクトリツリーのような方法を使ってXML文書内のパスを記述します。たとえば、上位レベルと下位レベルの区切りとして「/」を使用します。最初の「/」はドキュメントのルート ノードを表します (ドキュメントの最も外側のタグ ノードを指すのではなく、ドキュメント自体を指すことに注意してください)。たとえば、HTML ファイルの場合、最も外側のノードは「/html」である必要があります。

特定の HTML タグを見つけるには、page.xpath(u"/html/body/p") などのファイル パスと同様の絶対パスを使用できます。これにより、body ノードの下にあるすべての p タグが検索されます; ファイル パスと同様の相対パスを使用して、次のように使用することもできます: page. %">このページのみの世界ニュース94b3e26ee717c64999d7867364b1b4a3

ああ、ところで、ここにさらにテキストがあります。

e388a4556c0f65e1904146cc1a846bee...これは解析されたフラグメントです...94b3e26ee717c64999d7867364b1b4a3

注: XPATH は必ずしも唯一のノードを返すわけではなく、条件を満たすすべてのノードを返します。上記のように、ボディ内のpタグであれば、ボディの第1階層ノード、第2階層ノード、第3階層ノードのいずれであっても取り出されます。

さらに範囲を絞り込んで、「90ce244b5a5321cadd932bf501f122e4このページの世界ニュースのみ94b3e26ee717c64999d7867364b1b4a3」を直接ターゲットにしたい場合はどうすればよいでしょうか?これにはフィルター条件を追加する必要があります。フィルタリングの方法は、「[""]」を使用してフィルタ条件を追加することです。 lxml にはフィルタリング構文があります:

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

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

このようにして、本文の style font-size:200% を持つ p ノードが取り出されます。 注: この p

変数

lxml.etree ._Elementオブジェクトリスト、p[0].textの結果はこのページのみのワールドニュース、つまり、p[0].values()の結果はフォントです。 -size: 200%、つまりすべての 属性 Value。このうち、@style は属性のスタイルを表します。同様に、@name、@id、@value、@href、@src、@class....タグに属性がない場合はどうなりますか。 ?次に、text()、

position

()、およびその他の関数を使用してフィルタリングできます。関数 text() は、ノードに含まれるテキストを取得することを意味します。例: e388a4556c0f65e1904146cc1a846beehelloe388a4556c0f65e1904146cc1a846beeworld94b3e26ee717c64999d7867364b1b4a36fb279ad3fd4344cbdd93aac6ad173ac では、「p[text()='hello']」を使用して p を取得します。world は p の text() です。関数position()はノードの位置を取得することを意味します。たとえば、「li[position()=2]」は 2 番目の li ノードを取得することを意味します。これは「li[2]」と省略することもできます。 ただし、デジタルポジショニングとフィルター条件の順序に注意する必要があります。たとえば、「ul/li[5][@name='hello']」は、ul の下の 5 番目の項目 li を取得することを意味し、その名前は hello でなければなりません。それ以外の場合は空を返します。ただし、「ul/li[@name='hello'][5]」を使用すると、ul の下にある「hello」という名前の 5 番目の 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”,它的意思是结束节点前面的内容,也就是说在“df250b2156c434f3390392d09b1c9563”与“94b3e26ee717c64999d7867364b1b4a3”之间的内容。它的源码里面的意思是“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 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。