日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

备份 CSDN 博客(上)

發布時間:2025/3/15 编程问答 10 豆豆
生活随笔 收集整理的這篇文章主要介紹了 备份 CSDN 博客(上) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

    • 背景
    • 思路解析
    • 如何獲得每篇文章的 URL
      • urllib.request
      • HTML 的元素構成
      • BeautifulSoup
        • 根據標簽和屬性識別
        • 根據標簽和內容識別
        • 其他操作
    • 代碼
    • 參考資料

背景

因為 CSDN 的博客沒有批量導出功能,所以我就琢磨寫個腳本可以一鍵備份博客,最好是 markdown 格式。

搜了一波,極少有能拿來就用的,那就自己探索吧。

思路解析

思路很簡單:

  • 得到每篇文章的鏈接(URL)
  • 根據 URL 下載每篇文章,轉換成 markdown 格式
  • 囿于篇幅,這篇文章先解決第 1 個問題。

    其實我不太懂 python 爬蟲和前端,算是現學現賣,說得不對的地方,請您指正。

    如何獲得每篇文章的 URL

    如圖所示,我的博客總共有 7 頁,第 2 頁的文章列表的地址是:https://blog.csdn.net/longintchar/article/list/2

    第 3 頁的文章列表的地址是:

    https://blog.csdn.net/longintchar/article/list/3

    其中的規律很明顯,就是在 https://blog.csdn.net/longintchar/article/list/ 后面加上頁碼

    當你把鼠標懸停在標題上,就能看到左下角會顯示這篇文章的 URL(我用的是谷歌瀏覽器)。所以,從文章列表頁面就可以解析出本頁面每一篇文章的 URL

    以第 1 頁舉例,我們要做的事情有 2 個

  • 把這頁內容爬下來(從網站獲取源代碼)
  • 從里面提取每篇文章的 URL
  • urllib.request

    urllib 是 Python 內建的 HTTP 庫,使用 urllib 可以只需要很簡單的步驟就能高效采集數據。

    urllib 包含以下4個子模塊

  • urllib.request
  • urllib.error
  • urllib.parser
  • urllib.robotparser
  • 其中 urllib.request 子模塊是最常用的,用來從網站獲取源代碼

    一個簡單的示例:

    # 引入 urllib.request import urllib.request # 打開 URL response = urllib.request.urlopen('http://www.zhihu.com') # 讀取內容 html = response.read() # 解碼 html = html.decode('utf-8') print(html)

    第 4 行:urlopen() 方法返回的是一個 http.client.HTTPResponse 對象(<class ‘http.client.HTTPResponse’>),需要通過 read() 方法做進一步的處理

    第 6 行:調用 read() 方法,返回的數據類型為 bytes 類型

    第 8 行:bytes 類型經過 decode() 解碼轉換成 string 類型

    照貓畫虎,對于我們要下載的頁面,代碼是

    import urllib.requesturl = 'https://blog.csdn.net/longintchar/article/list/1' res = urllib.request.urlopen(url) html = res.read().decode('utf-8') print(html)

    第 6 行打印結果,結果如下圖(截取了一小部分)

    注意第 900 行,這里面就有我們要的文章 URL,如何把這些 URL 提取出來呢?

    HTML 的元素構成

    爬取網頁信息,可以理解成從 HTML 代碼中抽取我們需要的信息。HTML 由一系列的“元素”組成,這是從網上搜來的一張圖:

    我們要做的,可以分成兩部分

    • 精確定位元素
    • 從元素中提取信息

    比如下面這個元素

    <p><a href='www.wenzi.com'>hello</a></p>

    一般要提取“hello”部分,或者鏈接 www.wenzi.com 部分

    如何精確定位到某個元素呢?可以利用標簽名(比如上面的 “p”)和標簽屬性來識別。

    例如:

    <title>標題</title> <body><ul class='list1'><li>列表1第1項</li><li>列表1第2項</li></ul><p class='first'>文字1</p><p class='second'>文字2</p><ul class='list2'><li>列表2第1項</li><li>列表2第2項</li></ul> </body>
    • 如果要提取“標題”,只需要使用標簽名 title 來識別,因為只出現過一次 title 標簽
    • 如果要提取“文字1”,不能只使用p標簽,因為“文字2”也對應了p標簽,所以要用p標簽且class屬性值是'first'來識別
    • 如果“文字1”和“文字2”都要,就可以通過獲取所有p標簽提取內容
    • 如果想提取列表1中的兩項,就不能靠獲取所有li標簽,因為列表2中也有li標簽。此時需要先識別其父節點,即先定位到<ul class='list1'>這個標簽上(通過ul標簽和class屬性值是list1定位)。在這個標簽里,所有li都是我們想要的

    BeautifulSoup

    BeautifulSoup 是一個 HTML/XML 的解析器,用來解析和提取 HTML/XML 數據,利用它不用編寫正則表達式也能方便地抓取網頁信息。

    這里展示一下使用 BeautifulSoup 實現上述提取的代碼,以對這個庫的提取思路有一個大致的了解。

    a = '''<title>標題</title> <body><ul class='list1'><li>列表1第1項</li><li>列表1第2項</li></ul><p class='first'>文字1</p><p class='second'>文字2</p><ul class='list2'><li>列表2第1項</li><li>列表2第2項</li></ul> </body>'''from bs4 import BeautifulSoup soup = BeautifulSoup(a, "html.parser") # 1. 如果要提取“標題”,只需要使用`title`標簽名來識別,因為只出現過一次`title`標簽 # 提取元素的內容:使用.text print(soup.title.text) # 2. 提取“文字1” # 注意,find方法,只能找到第一個 print(soup.find('p', attrs={'class':'first'}).text)# 3. 提取“文字1”和“文字2” print(soup.find_all('p')) # 再分別從中提取文字,這里略# 4. 提取列表1中的兩項 print(soup.find('ul', attrs={'class':'list1'}).find_all('li'))

    運行結果是:

    標題 文字1 [<p class="first">文字1</p>, <p class="second">文字2</p>] [<li>列表1第1項</li>, <li>列表1第2項</li>]

    第 16 行,第二個參數指明解析器。BeautifulSoup 提供了三個解析器,它們各自的優缺點如下

    • html.parser :內置不依賴擴展,容錯能力強,速度適中
    • lxml:速度最快,容錯能力強,但是依賴 C 擴展
    • html5hib:速度最慢,容錯能力最強,依賴擴展

    第 30 行,當需要根據屬性來篩選的時候,可以用 attrs={屬性名:值}指定屬性的鍵值對。

    根據標簽和屬性識別

    我們再看幾個例子,請仔細看注釋和輸出結果。

    a = ''' <p id='p1'>段落1</p> <p id='p2'>段落2</p> <p class='p3'>段落3</p> <p class='p3' id='pp'>段落4</p> '''from bs4 import BeautifulSoup soup = BeautifulSoup(a, "html.parser")# 第一種,直接將屬性名作為參數名,但是有些屬性不行,比如像"a-b"這樣的屬性 print(soup.find_all('p', id = 'p1') )# 一般情況 print(soup.find_all('p', class_='p3') )# class是保留字比較特殊,需要后面加一個_# 最通用的方法 print(soup.find_all('p', attrs={'class':'p3'}) )# 包含這個屬性就算,而不是僅有這個屬性 print(soup.find_all('p', attrs={'class':'p3','id':'pp'}) )# 使用多個屬性匹配 print(soup.find_all('p', attrs={'class':'p3','id':False}) )# 指定不能有某個屬性 print(soup.find_all('p', attrs={'id':['p1','p2']}) )# 屬性值是p1或p2 print(soup.find_all('p', attrs={'class':True})) # 含有class屬性即可 # 正則表達式匹配 import re print(soup.find_all('p', attrs={'id':re.compile('^p')})) # 使用正則表達式,id以p開頭 [<p id="p1">段落1</p>] [<p class="p3">段落3</p>, <p class="p3" id="pp">段落4</p>][<p class="p3">段落3</p>, <p class="p3" id="pp">段落4</p>] //16[<p class="p3" id="pp">段落4</p>] //17[<p class="p3">段落3</p>] //18[<p id="p1">段落1</p>, <p id="p2">段落2</p>] //19[<p class="p3">段落3</p>, <p class="p3" id="pp">段落4</p>] //20[<p id="p1">段落1</p>, <p id="p2">段落2</p>, <p class="p3" id="pp">段落4</p>]

    需要說明的是:

    • find 方法:只能找到第一個符合要求的標簽
    • find_all 方法:找到所有符合要求的標簽,返回一個 list,如果只找到一個也是返回 list,可以用[0]提取

    根據標簽和內容識別

    繼續舉例子

    a = ''' <p id='p1'>段落1</p> <p class='p3'>段落2</p> <p class='p3'>文章</p> <p></p> ''' from bs4 import BeautifulSoup soup = BeautifulSoup(a, "html.parser")print(soup.find_all('p', text='文章')) print(soup.find_all('p', text=['段落1','段落2']))# 正則表達式 import re print(soup.find_all('p', text=re.compile('段落')))# 傳入函數 def nothing(c):return c not in ['段落1','段落2','文章'] print(soup.find_all('p',text=nothing))def something(c):return c in ['段落1','段落2','文章'] print(soup.find_all('p',text=something))def nothing(c): return c is None print(soup.find_all('p',text=nothing))

    運行結果

    [<p class="p3">文章</p>] [<p id="p1">段落1</p>, <p class="p3">段落2</p>] [<p id="p1">段落1</p>, <p class="p3">段落2</p>] // 第15行 [<p></p>] // 第20行 [<p id="p1">段落1</p>, <p class="p3">段落2</p>, <p class="p3">文章</p>] // 第24行 [<p></p>] // 第29行

    注意,代碼第 17 行和后面,舉例如何使用函數來過濾

    20:把 nothing 這個函數作用在 text 上面,如果返回 True,則符合條件,其他類似。

    find_all() 函數和 BeautifulSoup 的詳細說明,可以看官方文檔,地址是

    https://beautifulsoup.readthedocs.io/zh_CN/v4.4.0/

    其他操作

    包括嵌套標簽的提取、獲取內容、獲取屬性值

    a = ''' <body><h><a href='www.biaoti.com'>標題</a></h><p>段落1</p><p>段落2</p> </body> '''from bs4 import BeautifulSoup soup = BeautifulSoup(a, 'html.parser')# 提取內容for p in soup.find_all('p'):print(p.text)print(soup.h.text) # 多層嵌套也可以直接返回,即提取內層標簽 a 的內容 print(soup.h.a.text) # 也可以這樣 print(soup.a.text) # 也可以這樣print(soup.body.text) # 里面有多個內容時 # 提取屬性值,像字典一樣提取 print(soup.h.a['href']) print(soup.a['href']) # 也可以這樣 print(soup.h.a.get('href')) # 也可以這樣

    運行結果

    段落1 段落2 標題 // 18-20 標題 標題標題 // 23 段落1 段落2www.biaoti.com // 26-28 www.biaoti.com www.biaoti.com

    代碼

    終于鋪墊完了,可以講代碼了。

    文件名:get_id.py

    此模塊的功能是提取我所有文章的 URL

    import urllib.request from bs4 import BeautifulSoupdef getid(x):url = 'https://blog.csdn.net/longintchar/article/list/' + str(x)res = urllib.request.urlopen(url) html = res.read().decode('utf-8')soup = BeautifulSoup(html,'html.parser')divs = soup.find_all('div', attrs={'class':'article-item-box csdn-tracking-statistics'})for div in divs:print(div.h4.a['href'])for i in range(1, 8):getid(i)

    因為我的博客有 7 頁,所以第 14 行 range 的參數是(1,8)

    6:最開頭已經分析了,我的博客列表地址是 https://blog.csdn.net/longintchar/article/list/1 到 https://blog.csdn.net/longintchar/article/list/7

    7-8:前文已經講了,利用 urllib.request 子模塊從網站獲取源代碼

    9:利用 BeautifulSoup 解析 HTML 源碼

    通過分析 HTML 的代碼,我發現我需要的鏈接在某些 div 標簽中,準確地說,是 div.h4.a 的 href 屬性對應的值。這個 div 標簽有特點,特點是其 class 屬性的值是 “article-item-box csdn-tracking-statistics”,靠這個屬性值就可以排除其他 div 標簽。

    所以,就有這幾行代碼

    divs = soup.find_all('div', attrs={'class':'article-item-box csdn-tracking-statistics'})for div in divs:print(div.h4.a['href'])

    運行 get_id.py,就可以輸出所有博文的鏈接。

    如:

    第一個問題已經搞定,下篇博文我們看看如何下載每篇文章,轉換成 markdown 格式。


    參考資料

    【1】BeautifulSoup全面總結

    總結

    以上是生活随笔為你收集整理的备份 CSDN 博客(上)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。