進(jìn)一步了解XPath(利用XPath爬取飛哥的博客)【python爬蟲入門進(jìn)階】(04)

您好外厂,我是碼農(nóng)飛哥梨撞,感謝您閱讀本文俘侠,歡迎一鍵三連哦
本文是爬蟲專欄的第四篇鳖眼,重點介紹lxml庫與XPath搭配使用解析網(wǎng)頁提取網(wǎng)頁內(nèi)容测摔。
干貨滿滿慨仿,建議收藏浴井,系列文章持續(xù)更新晒骇。 小伙伴們?nèi)缬袉栴}及需要,歡迎踴躍留言告訴我哦~ ~ ~磺浙。

前言(為什么寫這篇文章)

上一篇文章我們簡單的介紹了Html與xml的基本概念洪囤,并且重點介紹了XPath的語法。這篇文章就讓我們來實戰(zhàn)一下: 通過本文你將學(xué)會如何 如何利用lxml庫來加載和解析網(wǎng)頁撕氧,然后搭配XPath的語法定位特定元素及節(jié)點信息的知識點瘤缩。

lxml庫的介紹

lxml庫是一個HTML/XML的解析器,主要功能是如何解析和提取HTML/XML的數(shù)據(jù)伦泥。
lxml和正則一樣款咖,也是用C語言實現(xiàn)的何暮,是一款高性能的Python HTML/XML解析器。利用前面學(xué)習(xí)的XPath的語法來快速定位網(wǎng)頁上的特定元素以及節(jié)點信息铐殃。

利用pip安裝lxm庫

pip install lxml

利用lxml庫解析HTML片段

lxml庫可以解析傳入的任何一段XML或者HTML片段,當(dāng)然前提是你的XML或者HTML片段沒有語法錯誤跨新。

#lxml_test.py
from lxml import etree

text = """
<div id="content_views" class="htmledit_views">
    <p style="text-align:center;"><strong>全網(wǎng)ID名:<b>碼農(nóng)飛哥</b></strong></p>
    <p style="text-align:right;"><strong>掃碼加入技術(shù)交流群富腊!</strong></span></p>
    <p style="text-align:right;"><img src="https://img-blog.csdnimg.cn/5df64755954146a69087352b41640653.png"/></p>
    <div style="text-align:left;">個人微信號<img src="https://img-blog.csdnimg.cn/09bddad423ad4bbb89200078c1892b1e.png"/></div>
</div>
"""
# 利用etree.HTML將字符串解析成HTML文檔
html = etree.HTML(text)
print("調(diào)用etree.HTML=", html)
# 將Element對象序列化成字符串
result = etree.tostring(html)
print("將Element對象序列化成字符串=", result)

result2 = etree.tostring(html, encoding='utf-8').decode()
print(result2)

在這里插入圖片描述

從上面的輸出結(jié)果可以看出etree.HTML(text) 方法可以將字符串解析成HTML文檔,也就是一個Element對象域帐。etree.tostring(html) 可以將HTML文檔序列化成字符串赘被,序列化之后的結(jié)果是一個 bytes 對象,中文是不能正常顯示的肖揣。需要通過指定編碼方式為utf-8民假,并且調(diào)用decode()方法中文才能正常輸出,并且輸出的HTML是有格式的龙优。即不是打印成一行羊异。

利用lxml庫加載html文件

lxml庫不僅僅可以解析XML/HTML片段,還可以解析完整的HTML/XML文件 彤断。下面創(chuàng)建了一個名為test.html文件野舶。然后通過 etree.parse方法進(jìn)行解析。

<div id="content_views" class="htmledit_views">
    <p style="text-align:center;"><strong>全網(wǎng)ID名:<b>碼農(nóng)飛哥</b></strong></p>
    <p style="text-align:right;"><strong>掃碼加入技術(shù)交流群宰衙!</strong></p>
    <p style="text-align:right;"><img src="https://img-blog.csdnimg.cn/5df64755954146a69087352b41640653.png"/></p>
    <div style="text-align:left;">個人微信號<img src="https://img-blog.csdnimg.cn/09bddad423ad4bbb89200078c1892b1e.png"/></div>
</div>

然后創(chuàng)建一個html_parse.py的文件進(jìn)行解析平道,需要注意的是該文件跟test.html文件在同一個目錄下。

# html_parse.py
from lxml import etree
#讀取外部文件 test.html
html = etree.parse('./test.html')
result = etree.tostring(html, encoding='utf-8').decode()
print(result)

解析結(jié)果是:

在這里插入圖片描述

可以看出如果被解析的HTML文件是一個標(biāo)準(zhǔn)的HTML代碼片段的話則可以正常加載供炼,因為這里parse方法默認(rèn)使用的是XML的解析器一屋。
但是當(dāng)HTML文件是一個標(biāo)準(zhǔn)的完整的HTML文件則XML解析器是不能解析。現(xiàn)在將test.html 改下圖2的代碼袋哼,如果直接使用XML解析器解析就會報下面的錯誤冀墨。
圖2

針對HTML文件需要通過HTMLParser方法設(shè)置HTML解析器。然后在parse方法指定該解析器先嬉,就像下面代碼所示的一樣轧苫。

from lxml import etree

# 定義解析器
html_parser = etree.HTMLParser(encoding='utf-8')
# 讀取外部文件 test.html
html = etree.parse('./test.html', parser=html_parser)
result = etree.tostring(html, encoding='utf-8').decode()
print(result)

運行結(jié)果是:


在這里插入圖片描述

實戰(zhàn)開始

了解了lxml方法的基本使用之后,接下來我們就以碼農(nóng)飛哥的博客 為例疫蔓。這里我們的需求是爬取他博客下所有文章(暫不包括文章內(nèi)容)含懊,然后將爬取的數(shù)據(jù)保存到本地txt文件中。首先讓我們來看看他的博客長啥樣衅胀。涉及前面幾篇博客知識點這里不再詳細(xì)介紹了岔乔。這里重點介紹如何通過XPath來快速定位特定的元素和數(shù)據(jù)。

在這里插入圖片描述

第一步: 獲得文章的分組

首先獲取文章的分組滚躯,還是使用萬能的XPath Helper, 通過F12調(diào)出調(diào)試窗口雏门,可以看出每個文章分組都是放在<div class="article-item-box csdn-tracking-statistics xh-highlight"></div> 嘿歌。所以,通過 //div[@class="article-item-box csdn-tracking-statistics"] 表達(dá)式就可以獲取所有的文章分組茁影。

在這里插入圖片描述

代碼示例如下:

from lxml import etree
import requests

response = requests.get("https://feige.blog.csdn.net/", timeout=10)  # 發(fā)送請求
html = response.content.decode()
html = etree.HTML(html)  # 獲取文章分組
li_temp_list = html.xpath('//div[@class="article-item-box csdn-tracking-statistics"]')
print(li_temp_list)

運行結(jié)果是:

在這里插入圖片描述

這里通過html.xpath('//div[@class="article-item-box csdn-tracking-statistics"]') 方法得到40個Element對象宙帝。這40個Element對象就是我們需要爬取的當(dāng)前頁面的所有文章。 每個Element對象就是下面這樣的內(nèi)容募闲。
在這里插入圖片描述

接下來通過result = etree.tostring(li_temp_list[0], encoding='utf-8').decode() 方法序列化Element對象步脓,得到的結(jié)果是:

<div class="article-item-box csdn-tracking-statistics" data-articleid="121003473">
      <img class="settop" src="https://csdnimg.cn/release/blogv2/dist/pc/img/listFixedTop.png" alt=""/>
      <h4 class="">
        <a  data-report-click="{&quot;spm&quot;:&quot;1001.2014.3001.5190&quot;}" target="_blank">
            <span class="article-type type-1 float-none">原創(chuàng)</span>
          淺識XPath(熟練掌握XPath的語法)【python爬蟲入門進(jìn)階】(03)
        </a> 
      </h4>
      <p class="content">
        XPath 利器在手,解析爬蟲無憂
      </p>
      <div class="info-box d-flex align-content-center">
        <p>
          <span class="date">2021-10-28 14:56:05</span>
          <span class="read-num"><img src="https://csdnimg.cn/release/blogv2/dist/pc/img/readCountWhite.png" alt=""/>335</span>
          <span class="read-num"><img src="https://csdnimg.cn/release/blogv2/dist/pc/img/commentCountWhite.png" alt=""/>5</span>
        </p>
      </div>
    </div>

第二步: 獲取文章的鏈接

從上面的代碼我們可以看出文章的鏈接在<a > 中浩螺,而a元素的父元素是h4元素靴患,h4元素的父元素是 <div class="article-item-box csdn-tracking-statistics">元素。

在這里插入圖片描述

換成XPath的表達(dá)式就是//div[@class="article-item-box csdn-tracking-statistics"]/h4/a/@href 要出,即首先通過//div[@class="article-item-box csdn-tracking-statistics"] 選取所有的<div class="article-item-box csdn-tracking-statistics"> 然后通過/h4找到他的子元素h4鸳君,在通過/a找到h4的子元素a。最后就是通過/@href 找到鏈接內(nèi)容患蹂。

不過第一步我們已經(jīng)獲取到了<div class="article-item-box csdn-tracking-statistics"> 元素的Element對象或颊。所以,這里就不需要在重復(fù)寫//div[@class="article-item-box csdn-tracking-statistics"]了况脆,只需要通過. 代替饭宾,表示在當(dāng)前目錄下找。參考代碼如下:

#省略第一步的代碼
href = li_temp_list[0].xpath('./h4/a/@href')[0]
print(href)

得到的結(jié)果是:https://feige.blog.csdn.net/article/details/121003473 格了。需要注意的是.xpath方法返回的是一個列表看铆,所以需要提取其第一個元素

第三步:獲取標(biāo)題內(nèi)容

按照獲取鏈接的思想,我們同樣可以獲取標(biāo)題內(nèi)容盛末。標(biāo)題的內(nèi)容就直接在a標(biāo)簽里弹惦。這里只需要多一步就是通過text()方法提取a標(biāo)簽的內(nèi)容。表達(dá)式就是//div[@class="article-item-box csdn-tracking-statistics"]/h4/a/text()悄但。

在這里插入圖片描述

參考代碼是:

title_list = li_temp_list[0].xpath('./h4/a/text()')
print(title_list)
print(title_list[1])

運行結(jié)果是:

['\n            ', '\n          淺識XPath(熟練掌握XPath的語法)【python爬蟲入門進(jìn)階】(03)\n        ']

          淺識XPath(熟練掌握XPath的語法)【python爬蟲入門進(jìn)階】(03)

因為列表中的第一個元素是\n棠隐,所以需要獲取第二個元素。

完整的參考代碼

import requests
from lxml import etree
import json
import os


class FeiGe:
    # 初始化
    def __init__(self, url, pages):
        self.url = url
        self.pages = pages
        self.headers = {
            "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 Safari/537.36"}

    def get_total_url_list(self):
        """
         獲取所有的urllist
        :return:
        """
        url_list = []
        for i in range(self.pages):
            url_list.append(self.url + "/article/list/" + str(i + 1) + "?t=1")
        return url_list

    def parse_url(self, url):
        """
        一個發(fā)送請求檐嚣,獲取響應(yīng)助泽,同時etree處理html
        :param url:
        :return:
        """
        print('parsing url:', url)
        response = requests.get(url, headers=self.headers, timeout=10)  # 發(fā)送請求
        html = response.content.decode()
        html = etree.HTML(html)
        return html

    def get_title_href(self, url):
        """
        獲取一個頁面的title和href
        :param url:
        :return:
        """
        html = self.parse_url(url)
        # 獲取文章分組
        li_temp_list = html.xpath('//div[@class="article-item-box csdn-tracking-statistics"]')
        total_items = []
        # 遍歷分組
        for i in li_temp_list:
            href = i.xpath('./h4/a/@href')[0] if len(i.xpath('./h4/a/@href')) > 0 else None
            title = i.xpath('./h4/a/text()')[1] if len(i.xpath('./h4/a/text()')) > 0 else None
            summary = i.xpath('./p')[0] if len(i.xpath('./p')) > 0 else None
            # 放入字典
            item = dict(href=href, text=title.replace('\n', ''), summary=summary.text.replace('\n', ''))
            total_items.append(item)
        return total_items

    def save_item(self, item):
        """
        保存一個item
        :param item:
        :return:
        """
        with open('feige_blog.txt', 'a') as f:
            f.write(json.dumps(item, ensure_ascii=False, indent=2))
            f.write("\n")

    def run(self):

        # 找到url規(guī)律,url_list
        url_list = self.get_total_url_list()
        os.remove('feige_blog.txt')
        for url in url_list:
            # 遍歷url_list發(fā)送請求嚎京,獲得響應(yīng)
            total_item = self.get_title_href(url)
            for item in total_item:
                print(item)
                self.save_item(item)


if __name__ == '__main__':
    fei_ge = FeiGe("https://feige.blog.csdn.net/", 8)
    fei_ge.run()

運行結(jié)果是:


在這里插入圖片描述

該類主要分為幾大塊嗡贺。

  1. 初始化方法__init__(self, url, pages) 主要設(shè)置需要爬取的博客的域名,以及博客的頁數(shù)鞍帝,以及初始化請求頭诫睬。
  2. 獲取所有頁數(shù)的鏈接的方法get_total_url_list(self) ,這里需要注意的鏈接的規(guī)律帕涌。
    在這里插入圖片描述
  3. parse_url(self, url) 方法主要就是根據(jù)傳入的url獲得該url的html頁面摄凡。
  4. get_title_href(self, url) 方法主要分為兩塊续徽,第一塊就是調(diào)用parse_url(self, url) 方法得到鏈接對應(yīng)的html頁面。第二塊就是解析HTML頁面以定位到我們需要的數(shù)據(jù)的元素亲澡,并將元素放在列表total_items中返回钦扭。
  5. save_item(self, item) 方法就是將第四步返回的total_items中的數(shù)據(jù)保存到feige_blog.txt文件中。
  6. run(self) 方法是主入口床绪,統(tǒng)籌調(diào)用各個方法土全。

總結(jié)

本文通過碼農(nóng)飛哥演示了如何在實戰(zhàn)中使用XPath來爬取我們想要的數(shù)據(jù)。

粉絲專屬福利

軟考資料:實用軟考資料

面試題:5G 的Java高頻面試題

學(xué)習(xí)資料:50G的各類學(xué)習(xí)資料

脫單秘籍:回復(fù)【脫單】

并發(fā)編程:回復(fù)【并發(fā)編程】

                                            ???? 驗證碼 可通過搜索下方 公眾號 獲取???? 

全網(wǎng)同名【碼農(nóng)飛哥】会涎。不積跬步,無以至千里瑞凑,享受分享的快樂
我是碼農(nóng)飛哥末秃,再次感謝您讀完本文

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末籽御,一起剝皮案震驚了整個濱河市练慕,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌技掏,老刑警劉巖铃将,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異哑梳,居然都是意外死亡劲阎,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進(jìn)店門鸠真,熙熙樓的掌柜王于貴愁眉苦臉地迎上來悯仙,“玉大人,你說我怎么就攤上這事吠卷∥ⅲ” “怎么了?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵祭隔,是天一觀的道長货岭。 經(jīng)常有香客問我,道長疾渴,這世上最難降的妖魔是什么千贯? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮程奠,結(jié)果婚禮上丈牢,老公的妹妹穿的比我還像新娘。我一直安慰自己瞄沙,他們只是感情好己沛,可當(dāng)我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布慌核。 她就那樣靜靜地躺著,像睡著了一般申尼。 火紅的嫁衣襯著肌膚如雪垮卓。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天师幕,我揣著相機與錄音粟按,去河邊找鬼。 笑死霹粥,一個胖子當(dāng)著我的面吹牛灭将,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播后控,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼庙曙,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了浩淘?” 一聲冷哼從身側(cè)響起捌朴,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎张抄,沒想到半個月后砂蔽,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡署惯,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年左驾,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片泽台。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡什荣,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出怀酷,到底是詐尸還是另有隱情稻爬,我是刑警寧澤,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布蜕依,位于F島的核電站桅锄,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏样眠。R本人自食惡果不足惜友瘤,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望檐束。 院中可真熱鬧辫秧,春花似錦、人聲如沸被丧。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至柿究,卻和暖如春邮旷,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蝇摸。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工婶肩, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人貌夕。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓律歼,卻偏偏與公主長得像,于是被迫代替她去往敵國和親啡专。 傳聞我的和親對象是個殘疾皇子苗膝,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內(nèi)容