>  기사  >  웹 프론트엔드  >  lxml을 사용하여 HTML을 구문 분석하는 방법

lxml을 사용하여 HTML을 구문 분석하는 방법

高洛峰
高洛峰원래의
2017-03-12 17:51:271950검색

이 기사에서는 lxml

먼저 페이지 링크를 가져오는 코드 예제를 보여줍니다.

#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/', '대상': '_blank'}
{' href': 'http://game.3533.com/tupian/', '대상': '_blank'}
{'href': 'http://www.4399.com/', ' target' : '_blank'}
{'href': 'http://www.91wan.com/', 'target': '_blank'}

3ed8bec1d105f4dcb8f1f75d1c6c2d63,

hrefs의 href에 대한

print href.text

결과는 다음과 같습니다.

Youth Development Foundation
Rock Kingdom
Aola Star
모바일 게임
모바일 배경화면
4399 미니 게임
91wan 게임

lxml을 사용하기 전에 주의할 사항: utf-8 디코딩 후 html, 즉 code = html.decode('utf-8', 'ignore')인지 확인하세요. 그렇지 않으면 구문 분석 오류가 발생합니다. 중국어는 utf-8로 인코딩된 후 '/u2541'과 같은 형식이 되기 때문에 lxml은 "/"를 만나면 해당 태그가 끝나는 것으로 생각합니다.

XPATH는 기본적으로 디렉토리 트리와 같은 방법을 사용하여 XML 문서의 경로를 설명합니다. 예를 들어 "/"를 사용하여 상위 수준과 하위 수준을 구분합니다. 첫 번째 "/"는 문서의 루트 노드를 나타냅니다. 이는 문서의 가장 바깥쪽 태그 노드를 나타내는 것이 아니라 문서 자체를 나타냅니다. 예를 들어 HTML 파일의 경우 가장 바깥쪽 노드는 "/html"이어야 합니다.

특정 HTML 태그를 찾으려면 파일 경로와 유사한 절대 경로(예: page.xpath(u"/html/body/p"))를 사용할 수 있습니다. 본문 노드 찾기 모든 p 태그 찾기; 파일 경로와 유사한 상대 경로를 사용할 수도 있습니다. 다음과 같이 사용할 수 있습니다: page.xpath(u"//p"), 전체에서 모든 p 태그를 찾습니다. html 코드:

  90ce244b5a5321cadd932bf501f122e4이 페이지에만 있는 세계 뉴스94b3e26ee717c64999d7867364b1b4a3
  아, 그런데 여기에 텍스트가 더 있습니다.
  e388a4556c0f65e1904146cc1a846bee.. . 그리고 이것은 구문 분석된 조각입니다 ...94b3e26ee717c64999d7867364b1b4a3

참고: XPATH는 반드시 유일한 노드를 반환하는 것이 아니라 조건을 충족하는 모든 노드를 반환합니다. 위와 같이 본문에 p 태그만 있으면 본문의 첫 번째 수준 노드, 두 번째 수준, 세 번째 수준 노드인지 여부에 관계없이 제거됩니다.

범위를 더 좁혀서 "90ce244b5a5321cadd932bf501f122e4이 페이지에만 세계 뉴스94b3e26ee717c64999d7867364b1b4a3"를 직접 찾고 싶다면 어떻게 해야 할까요? 이를 위해서는 필터 조건을 추가해야 합니다. 필터링 방법은 "[""]"를 사용하여 필터 조건을 추가하는 것입니다. lxml에는 필터 구문이 있습니다:

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

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

이런 식으로, 글꼴 크기:200% 스타일의 p 노드는 참고: 이 p 변수는 lxml.etree._Element 개체의 목록입니다. p[0].text의 결과는 이 페이지에만 있습니다. 즉, 태그 사이의 값입니다. p [0].values()의 결과는 글꼴 크기: 200%, 즉 모든 속성 값입니다. 그 중 @style은 속성 스타일을 나타냅니다. 마찬가지로 @name, @id, @value, @href, @src, @class....

를 사용할 수도 있습니다. 태그에는 그런 것이 없습니다. 속성은 어떻게 해야 하나요? 그런 다음 text(), position() 및 기타 함수 를 사용하여 필터링할 수 있습니다. text() 함수는 노드에 포함된 텍스트를 가져오는 것을 의미합니다. 예: e388a4556c0f65e1904146cc1a846beehelloe388a4556c0f65e1904146cc1a846beeworld94b3e26ee717c64999d7867364b1b4a36fb279ad3fd4344cbdd93aac6ad173ac, "p[text()='hello']"를 사용하여 p를 가져오고 world는 p의 text()입니다. position() 함수는 노드의 위치를 ​​얻는 것을 의미합니다. 예를 들어, "li[position()=2]"는 두 번째 li 노드를 얻는다는 의미이며 "li[2]"로 생략할 수도 있습니다.

단, 수치 위치 지정 순서와 필터 조건에 주의해야 합니다. 예를 들어, "ul/li[5][@name='hello']"는 ul 아래의 다섯 번째 항목 li를 가져오고 해당 이름은 hello여야 함을 의미합니다. 그렇지 않으면 빈 값을 반환합니다. 하지만 "ul/li[@name='hello'][5]"를 사용하면 의미가 달라집니다. 이는 ul 아래에 이름이 "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”,它的意思是结束节点前面的内容,也就是说在“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 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.