成人午夜视频全免费观看高清-秋霞福利视频一区二区三区-国产精品久久久久电影小说-亚洲不卡区三一区三区一区

利用lxml從網(wǎng)頁(yè)HTML/XML中提取數(shù)據(jù)

今天就跟大家聊聊有關(guān)利用lxml從網(wǎng)頁(yè)HTML/XML中提取數(shù)據(jù),可能很多人都不太了解,為了讓大家更加了解,小編給大家總結(jié)了以下內(nèi)容,希望大家根據(jù)這篇文章可以有所收獲。

目前創(chuàng)新互聯(lián)建站已為數(shù)千家的企業(yè)提供了網(wǎng)站建設(shè)、域名、網(wǎng)絡(luò)空間、綿陽(yáng)服務(wù)器托管、企業(yè)網(wǎng)站設(shè)計(jì)、馬村網(wǎng)站維護(hù)等服務(wù),公司將堅(jiān)持客戶(hù)導(dǎo)向、應(yīng)用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶(hù)和合作伙伴齊心協(xié)力一起成長(zhǎng),共同發(fā)展。

Python 的 lxml 模塊是一個(gè)非常好用且性能高的HTML、XML解析工具,通過(guò)它解析網(wǎng)頁(yè),爬蟲(chóng)就可以輕松的從網(wǎng)頁(yè)中提取想要的數(shù)據(jù)。lxml是基于C語(yǔ)言的libxml2和libxslt庫(kù)開(kāi)發(fā)的,所以速度是相當(dāng)?shù)目臁?/p>

使用lxml提取網(wǎng)頁(yè)數(shù)據(jù)的流程

要從網(wǎng)頁(yè)里面提取數(shù)據(jù),使用lxml需要兩步:

第一步,用lxml把網(wǎng)頁(yè)(或xml)解析成一個(gè)DOM樹(shù)。這個(gè)過(guò)程,我們可以選擇etree、etree.HTML 和 lxml.html 這三種來(lái)實(shí)現(xiàn),它們基本類(lèi)似但又有些許差別,后面我們會(huì)詳細(xì)講到。

第二步,使用xpath遍歷這棵DOM 樹(shù),找到你想要的數(shù)據(jù)所在的節(jié)點(diǎn)并提取。這一步要求我們對(duì)xpath規(guī)則比較熟練,xpath規(guī)則很多,但別怕,我來(lái)總結(jié)一些常用的套路。

生成DOM樹(shù)

上面我們說(shuō)了,可以有三種方法來(lái)把網(wǎng)頁(yè)解析成DOM樹(shù),有選擇困難癥的同學(xué)要犯難了,選擇那種好呢?別急,我們逐一探究一下。下面我通過(guò)實(shí)例來(lái)解析一下下面這段html代碼:

<div class="1">
    <p class="p_1 item">item_1</p>
    <p class="p_2 item">item_2</p>
</div>
<div class="2">
    <p id="p3"><a href="/go-p3">item_3</a></p>
</div>

使用etree.fromstring()函數(shù)

先看看這個(gè)函數(shù)的說(shuō)明(docstring):

In [3]: etree.fromstring?
Signature:      etree.fromstring(text, parser=None, *, base_url=None)
Call signature: etree.fromstring(*args, **kwargs)
Type:           cython_function_or_method
String form:    <cyfunction fromstring at 0x7fe538822df0>
Docstring:
fromstring(text, parser=None, base_url=None)

Parses an XML document or fragment from a string.  Returns the
root node (or the result returned by a parser target).

To override the default parser with a different parser you can pass it to
the ``parser`` keyword argument.

The ``base_url`` keyword argument allows to set the original base URL of
the document to support relative Paths when looking up external entities
(DTD, XInclude, ...).

這個(gè)函數(shù)就是把輸入的html解析成一棵DOM樹(shù),并返回根節(jié)點(diǎn)。它對(duì)輸入的字符串text有什么要求嗎?首先,必須是合法的html字符串,然后我們看看下面的例子:

In [19]: html = ''' 
...: <div class="1"> 
...:     <p class="p_1 item">item_1</p> 
...:     <p class="p_2 item">item_2</p> 
...: </div> 
...: <div class="2"> 
...:     <p id="p3"><a href="/go-p3">item_3</a></p> 
...: </div> 
...: '''

In [20]: etree.fromstring(html)
Traceback (most recent call last):

    File "/home/veelion/.virtualenvs/py3.6/lib/python3.6/site-packages/IPython/core/interactiveshell.py", 
    line 3267, in run_code
exec(code_obj, self.user_global_ns, self.user_ns)

    File "<ipython-input-20-aea2e2c2317e>", line 1, in <module>
etree.fromstring(html)

    File "src/lxml/etree.pyx", line 3213, in lxml.etree.fromstring

    File "src/lxml/parser.pxi", line 1877, in lxml.etree._parseMemoryDocument

    File "src/lxml/parser.pxi", line 1758, in lxml.etree._parseDoc

    File "src/lxml/parser.pxi", line 1068, in lxml.etree._BaseParser._parseUnicodeDoc

    File "src/lxml/parser.pxi", line 601, in lxml.etree._ParserContext._handleParseResultDoc

    File "src/lxml/parser.pxi", line 711, in lxml.etree._handleParseResult

    File "src/lxml/parser.pxi", line 640, in lxml.etree._raiseParseError

    File "<string>", line 6
    XMLSyntaxError: Extra content at the end of the document, line 6, column 1

竟然報(bào)錯(cuò)了!究其原因,我們的html是兩個(gè)并列的<div>標(biāo)簽,沒(méi)有一個(gè)單獨(dú)的root節(jié)點(diǎn)。那么給這個(gè)html再加一個(gè)最外層的<div>標(biāo)簽?zāi)兀?/p>

In [22]: etree.fromstring('<div>' + html + '</div>')
Out[22]: <Element div at 0x7fe53aa978c8>

這樣就可以了,返回了root節(jié)點(diǎn),它是一個(gè)Element對(duì)象,tag是div。

總結(jié)一下,etree.fromstring()需要最外層是一個(gè)單獨(dú)的節(jié)點(diǎn),否則會(huì)出錯(cuò)。這個(gè)方法也適用于生成 XML 的DOM樹(shù)。

使用etree.HTML()函數(shù)

這個(gè)函數(shù)更像是針對(duì) HTML 的,看看它的docstring:

In [23]: etree.HTML?
Signature:      etree.HTML(text, parser=None, *, base_url=None)
Call signature: etree.HTML(*args, **kwargs)
Type:           cython_function_or_method
String form:    <cyfunction HTML at 0x7fe538822c80>
Docstring:     
HTML(text, parser=None, base_url=None)

Parses an HTML document from a string constant.  Returns the root
node (or the result returned by a parser target).  This function
can be used to embed "HTML literals" in Python code.

To override the parser with a different ``HTMLParser`` you can pass it to
the ``parser`` keyword argument.

The ``base_url`` keyword argument allows to set the original base URL of
the document to support relative Paths when looking up external entities
(DTD, XInclude, ...).

接口參數(shù)跟etree.fromstring()一模一樣,實(shí)操一下:

In [24]: etree.HTML(html)
Out[24]: <Element html at 0x7fe53ab03748>

輸入兩個(gè)并列節(jié)點(diǎn)的html也沒(méi)有問(wèn)題。等等,返回的root節(jié)點(diǎn)對(duì)象Element的標(biāo)簽是html?把它用etree.tostring()還原成html代碼看看:

In [26]: print(etree.tostring(etree.HTML(html)).decode())
<html><body><div class="1">
    <p class="p_1 item">item_1</p>
    <p class="p_2 item">item_2</p>
</div>
<div class="2">
    <p id="p3"><a href="/go-p3">item_3</a></p>
</div>
</body></html>

In [27]: print(html)

<div class="1">
    <p class="p_1 item">item_1</p>
    <p class="p_2 item">item_2</p>
</div>
<div class="2">
    <p id="p3"><a href="/go-p3">item_3</a></p>
</div>

也就是說(shuō),etree.HTML()函數(shù)會(huì)補(bǔ)全html代碼片段,給它們加上<html>和<body>標(biāo)簽。

使用lxml.html函數(shù)

lxml.html是lxml的子模塊,它是對(duì)etree的封裝,更適合解析html網(wǎng)頁(yè)。用這個(gè)子模塊生成DOM樹(shù)的方法有多個(gè):
lxml.html.document_fromstring()
lxml.html.fragment_fromstring()
lxml.html.fragments_fromstring()
lxml.html.fromstring()

它們的docstring可以在ipython里面查一下,這里就不再列舉。通常,我們解析網(wǎng)頁(yè)用最后一個(gè)fromstring()即可。這個(gè)fromstring()函數(shù)也會(huì)給我們的樣例html代碼最頂層的兩個(gè)并列節(jié)點(diǎn)加一個(gè)父節(jié)點(diǎn)div。

上面三種方法介紹完,相信你自己已經(jīng)有了選擇,那必須是lxml.html。

因?yàn)樗槍?duì)html做了封裝,所以也多了寫(xiě)特有的方法:

比如我們要獲得某個(gè)節(jié)點(diǎn)下包含所有子節(jié)點(diǎn)的文本內(nèi)容時(shí),通過(guò)etree得到的節(jié)點(diǎn)沒(méi)辦法,它的每個(gè)節(jié)點(diǎn)有個(gè)text屬性只是該節(jié)點(diǎn)的,不包括子節(jié)點(diǎn),必須要自己遍歷獲得子節(jié)點(diǎn)的文本。而lxml.html有一個(gè)text_content()方法可以方便的獲取某節(jié)點(diǎn)內(nèi)包含的所有文本。

再比如,好多網(wǎng)頁(yè)的鏈接寫(xiě)的都是相對(duì)路徑而不是完整url:<a href="/index.html">,我們提取鏈接后還要自己手動(dòng)拼接成完整的url。這個(gè)時(shí)候可以用lxml.html提供的make_links_absolute()方法,這個(gè)方法是節(jié)點(diǎn)對(duì)象Element的方法,etree的Element對(duì)象卻沒(méi)有。

使用xpath提取數(shù)據(jù)

我們還以下面這段html代碼為例,來(lái)看看如何定位節(jié)點(diǎn)提取數(shù)據(jù)。

<div class="1">
    <p class="p_1 item">item_1</p>
    <p class="p_2 item">item_2</p>
</div>
<div class="2">
    <p id="p3"><a href="/go-p3">item_3</a></p>
</div>

首先導(dǎo)入lxml.html模塊,生成DOM樹(shù):

In [50]: import lxml.html as lh

In [51]: doc = lh.fromstring(html)

(1)通過(guò)標(biāo)簽屬性定位節(jié)點(diǎn)
比如我們要獲取<div class="2">這節(jié)點(diǎn):

In [52]: doc.xpath('//div[@class="2"]')
Out[52]: [<Element div at 0x7fe53a492ea8>]

In [53]: print(lh.tostring(doc.xpath('//div[@class="2"]')[0]).decode())
<div class="2">
    <p id="p3"><a href="/go-p3">item_3</a></p>
</div>

(2)contains語(yǔ)法
html中有兩個(gè)<p>標(biāo)簽的class含有item,如果我們要提取這兩個(gè)<p>標(biāo)簽,則:

In [54]: doc.xpath('//p[contains(@class, "item")]')
Out[54]: [<Element p at 0x7fe53a6a3ea8>, <Element p at 0x7fe53a6a3048>]

## 獲取<p>的文本:
In [55]: doc.xpath('//p[contains(@class, "item")]/text()')
Out[55]: ['item_1', 'item_2']

(3)starts-with語(yǔ)法
跟(2)一樣的提取需求,兩個(gè)<p>標(biāo)簽的class都是以p_開(kāi)頭的,所以:

In [60]: doc.xpath('//p[starts-with(@class, "p_")]')
Out[60]: [<Element p at 0x7fe53a6a3ea8>, <Element p at 0x7fe53a6a3048>]

## 獲取<p>的文本:
In [61]: doc.xpath('//p[starts-with(@class, "p_")]/text()')
Out[61]: ['item_1', 'item_2']

(4)獲取某一屬性的值
比如,我們想提取網(wǎng)頁(yè)中所有的鏈接:

In [63]: doc.xpath('//@href')
Out[63]: ['/go-p3']

看完上述內(nèi)容,你們對(duì)利用lxml從網(wǎng)頁(yè)HTML/XML中提取數(shù)據(jù)有進(jìn)一步的了解嗎?如果還想了解更多知識(shí)或者相關(guān)內(nèi)容,請(qǐng)關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝大家的支持。

分享名稱(chēng):利用lxml從網(wǎng)頁(yè)HTML/XML中提取數(shù)據(jù)
網(wǎng)頁(yè)鏈接:http://jinyejixie.com/article12/pgipgc.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供定制開(kāi)發(fā)、網(wǎng)站制作網(wǎng)站設(shè)計(jì)公司、建站公司、網(wǎng)站收錄、云服務(wù)器

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話(huà):028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

h5響應(yīng)式網(wǎng)站建設(shè)
凤山市| 阿拉善左旗| 河西区| 将乐县| 屯留县| 湖南省| 延庆县| 山阴县| 化隆| 特克斯县| 洞头县| 十堰市| 十堰市| 商都县| 吉林市| 土默特右旗| 天台县| 迁安市| 古浪县| 桐乡市| 资阳市| 华蓥市| 本溪市| 楚雄市| 伊金霍洛旗| 友谊县| 普格县| 辉南县| 定安县| 丽水市| 江油市| 西乡县| 巴马| 广宗县| 连平县| 柯坪县| 彭泽县| 岳西县| 兴国县| 高邑县| 牙克石市|