CSDN文章保存為MD文檔(二)

免責聲明

文章僅做經驗分享用途,利用本文章所提供的信息而造成的任何直接或者間接的后果及損失,均由使用者本人負責,作者不為此承擔任何責任,一旦造成后果請自行承擔!!!

import sys
sys.path.append("")
import requests
from bs4 import BeautifulSoup
from utils import Parser

def html2md(url, md_file, with_title=False):
? ? response = requests.get(url,headers = header)
? ? soup = BeautifulSoup(response.content, 'html.parser', from_encoding="utf-8")
? ? html = ""
? ? for child in soup.find_all('svg'):
? ? ? ? child.extract()
? ? if with_title:
? ? ? ? for c in soup.find_all('div', {'class': 'article-title-box'}):
? ? ? ? ? ? html += str(c)
? ? for c in soup.find_all('div', {'id': 'content_views'}):
? ? ? ? html += str(c)

? ? parser = Parser(html,markdown_dir)
? ? with open(md_file, 'w',encoding="utf-8") as f:
? ? ? ? f.write('{}\n'.format(''.join(parser.outputs)))
? ? ? ??
def download_csdn_single_page(article_url, md_dir, with_title=True, pdf_dir='pdf', to_pdf=False):
? ? response = requests.get(article_url,headers = header)
? ? soup = BeautifulSoup(response.content, 'html.parser', from_encoding="utf-8")
? ? title = soup.find_all('h1', {'class': 'title-article'})[0].string ?## 使用 html 的 title 作為 md 文件名
? ? title = title.replace('*', '').strip().split()
? ? md_file = md_dir+'/'+title[0] + '.md'
? ? print('Export Markdown File To {}'.format(md_file))
? ? html2md(article_url, md_file, with_title=with_title)

header = {
? ? ? ? "Accept": "application/json, text/plain, */*",
? ? ? ? "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,und;q=0.7",
? ? ? ? "Connection": "keep-alive",
? ? ? ? "Content-Type": "application/json;charset=UTF-8",
? ? ? ? "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36",
? ? ? ? "x-requested-with": "XMLHttpRequest"
? ? ? ? }

article_url = '' #csdn博客鏈接
markdown_dir = '' #保存文件夾
download_csdn_single_page(article_url,markdown_dir)

utils.py:

# -*- coding: utf-8 -*-
"""
Created on Wed Dec ?1 10:10:19 2021

@author: Y
"""
from bs4 import BeautifulSoup, Tag, NavigableString, Comment
import os
from os.path import join, exists
import re
from urllib.request import urlretrieve
? ??

special_characters = {
? ? "&lt;": "<", "&gt;": ">", "&nbsp": " ",
? ? "&#8203": "",
}

class Parser(object):
? ? def __init__(self, html,markdown_dir):
? ? ? ? self.html = html
? ? ? ? self.soup = BeautifulSoup(html, 'html.parser')
? ? ? ? self.outputs = []
? ? ? ? self.fig_dir = markdown_dir
? ? ? ? self.pre = False
? ? ? ? self.equ_inline = False

? ? ? ? if not exists(self.fig_dir):
? ? ? ? ? ? os.makedirs(self.fig_dir)
? ? ? ? self.recursive(self.soup)

? ? def remove_comment(self, soup):
? ? ? ? if not hasattr(soup, 'children'): return
? ? ? ? for c in soup.children:
? ? ? ? ? ? if isinstance(c, Comment):
? ? ? ? ? ? ? ? c.extract()
? ? ? ? ? ? self.remove_comment(c)

? ? def recursive(self, soup):
? ? ? ? if isinstance(soup, Comment): return
? ? ? ? elif isinstance(soup, NavigableString):
? ? ? ? ? ? for key, val in special_characters.items():
? ? ? ? ? ? ? ? soup.string = soup.string.replace(key, val)
? ? ? ? ? ? self.outputs.append(soup.string)
? ? ? ? elif isinstance(soup, Tag):
? ? ? ? ? ? tag = soup.name
? ? ? ? ? ? if tag in ['h1', 'h2', 'h3', 'h4', 'h5']:
? ? ? ? ? ? ? ? n = int(tag[1])
? ? ? ? ? ? ? ? soup.contents.insert(0, NavigableString('\n' + '#'*n + ' '))
? ? ? ? ? ? ? ? soup.contents.append(NavigableString('\n'))
? ? ? ? ? ? elif tag == 'a' and 'href' in soup.attrs:
? ? ? ? ? ? ? ? soup.contents.insert(0, NavigableString('['))
? ? ? ? ? ? ? ? soup.contents.append(NavigableString("]({})".format(soup.attrs['href'])))
? ? ? ? ? ? elif tag in ['b', 'strong']:
? ? ? ? ? ? ? ? soup.contents.insert(0, NavigableString('**'))
? ? ? ? ? ? ? ? soup.contents.append(NavigableString('**'))
? ? ? ? ? ? elif tag in ['em']:
? ? ? ? ? ? ? ? soup.contents.insert(0, NavigableString('*'))
? ? ? ? ? ? ? ? soup.contents.append(NavigableString('*'))
? ? ? ? ? ? elif tag == 'pre':
? ? ? ? ? ? ? ? self.pre = True
? ? ? ? ? ? elif tag in ['code', 'tt']:
? ? ? ? ? ? ? ? if self.pre:
? ? ? ? ? ? ? ? ? ? if not 'class' in soup.attrs:
? ? ? ? ? ? ? ? ? ? ? ? language = 'bash' ?# default language
? ? ? ? ? ? ? ? ? ? else:
? ? ? ? ? ? ? ? ? ? ? ? for name in ['cpp', 'bash', 'python', 'java']:
? ? ? ? ? ? ? ? ? ? ? ? ? ? if name in ' '.join(list(soup.attrs['class'])): # <code class="prism language-cpp">
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? language = name
? ? ? ? ? ? ? ? ? ? soup.contents.insert(0, NavigableString('\n```{}\n'.format(language)))
? ? ? ? ? ? ? ? ? ? soup.contents.append(NavigableString('```\n'))
? ? ? ? ? ? ? ? ? ? self.pre = False ?# assume the contents of <pre> contain only one <code>
? ? ? ? ? ? ? ? else:
? ? ? ? ? ? ? ? ? ? soup.contents.insert(0, NavigableString('`'))
? ? ? ? ? ? ? ? ? ? soup.contents.append(NavigableString('`'))
? ? ? ? ? ? elif tag == 'p':
? ? ? ? ? ? ? ? if soup.parent.name != 'li':
? ? ? ? ? ? ? ? ? ? # print(soup.parent)
? ? ? ? ? ? ? ? ? ? soup.contents.insert(0, NavigableString('\n'))
? ? ? ? ? ? elif tag == 'span':
? ? ? ? ? ? ? ? if 'class' in soup.attrs:
? ? ? ? ? ? ? ? ? ? if ('katex--inline' in soup.attrs['class'] or
? ? ? ? ? ? ? ? ? ? ? ?'katex--display' in soup.attrs['class']): ## inline math
? ? ? ? ? ? ? ? ? ? ? ? self.equ_inline = True if 'katex--inline' in soup.attrs['class'] else False
? ? ? ? ? ? ? ? ? ? ? ? math_start_sign = '$' if self.equ_inline else '\n\n$$'
? ? ? ? ? ? ? ? ? ? ? ? math_end_sign = '$' if self.equ_inline else '$$\n\n'
? ? ? ? ? ? ? ? ? ? ? ? equation = soup.find_all('annotation', {'encoding': 'application/x-tex'})[0].string
? ? ? ? ? ? ? ? ? ? ? ? equation = math_start_sign + str(equation) + math_end_sign
? ? ? ? ? ? ? ? ? ? ? ? self.outputs.append(equation)
? ? ? ? ? ? ? ? ? ? ? ? self.equ_inline = False
? ? ? ? ? ? ? ? ? ? ? ? return
? ? ? ? ? ? elif tag in ['ol', 'ul']:
? ? ? ? ? ? ? ? soup.contents.insert(0, NavigableString('\n'))
? ? ? ? ? ? ? ? soup.contents.append(NavigableString('\n'))
? ? ? ? ? ? elif tag in ['li']:
? ? ? ? ? ? ? ? soup.contents.insert(0, NavigableString('+ '))
? ? ? ? ? ? # elif tag == 'blockquote':
? ? ? ? ? ? ? ? # soup.contents.insert(0, NavigableString('> '))
? ? ? ? ? ? elif tag == 'img':
? ? ? ? ? ? ? ? src = soup.attrs['src']
? ? ? ? ? ? ? ? # pattern = r'.*\.png'
? ? ? ? ? ? ? ? pattern = r'(.*\..*\?)|(.*\.(png|jpeg|jpg))'
? ? ? ? ? ? ? ? result_tuple = re.findall(pattern, src)[0]
? ? ? ? ? ? ? ? if result_tuple[0]:
? ? ? ? ? ? ? ? ? ? img_file = result_tuple[0].split('/')[-1].rstrip('?')
? ? ? ? ? ? ? ? else:
? ? ? ? ? ? ? ? ? ? img_file = result_tuple[1].split('/')[-1].rstrip('?')
? ? ? ? ? ? ? ? # img_file = re.findall(pattern, src)[0][0].split('/')[-1].rstrip('?') ## e.g. https://img-blog.csdnimg.cn/20200228210146931.png?
? ? ? ? ? ? ? ? img_file = join(self.fig_dir, img_file)
? ? ? ? ? ? ? ? # download_img_cmd = 'aria2c --file-allocation=none -c -x 10 -s 10 -o {} {}'.format(img_file, src)
? ? ? ? ? ? ? ? # if not exists(img_file):
? ? ? ? ? ? ? ? # ? ? os.system(download_img_cmd)
? ? ? ? ? ? ? ? urlretrieve(src, img_file)
? ? ? ? ? ? ? ? # soup.attrs['src'] = img_file
? ? ? ? ? ? ? ? # self.outputs.append('\n' + str(soup.parent) + '\n')
? ? ? ? ? ? ? ? code = '![{}]({})'.format(img_file, img_file)
? ? ? ? ? ? ? ? self.outputs.append('\n' + code + '\n')
? ? ? ? ? ? ? ? return
? ? ? ? if not hasattr(soup, 'children'): return
? ? ? ? for child in soup.children:
? ? ? ? ? ? self.recursive(child)


if __name__ == '__main__':
? ? # html = '<body><!-- cde --><h1>This is 1 &lt;= 2<!-- abc --> <b>title</b></h1><p><a href="www.hello.com">hello</a></p><b>test</b>'
? ? html = '<body><!-- cde --><h1>hello</h1><h2>world</h2></body>'
? ? parser = Parser(html)
? ? print(''.join(parser.outputs))


結語

沒有人規定,一朵花一定要成長為向日葵或者玫瑰。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/162339.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/162339.shtml
英文地址,請注明出處:http://en.pswp.cn/news/162339.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【HarmonyOS】 低代碼平臺組件拖拽使用技巧之登錄組件

【關鍵字】 HarmonyOS、低代碼平臺、組件拖拽、登錄組件、代碼編輯器 1、寫在前面 前面我們介紹了低代碼中堆疊容器、滾動容器、網格布局、頁簽容器以及一些常用容器和組件的拖拽使用方法&#xff0c;本篇我們來介紹一個新的組件&#xff0c;這個組件是屬于業務組件——登錄組…

Modbus轉Profinet網關:PLC與天信流量計通訊的經典案例

無論您是PLC或工業設備的制造商&#xff0c;還是工業自動化系統的維護人員&#xff0c;可能會遇到需要將不同協議的設備連接組合并通訊的情況&#xff0c;Modbus和Profinet是現代工業自動化中常見的兩種通信協議&#xff0c;在工業控制領域中被廣泛應用。 在這種情況絕大多數會…

快速上手Banana Pi BPI-M4 Zero 全志科技H618開源硬件開發開發板

Linux[編輯] 準備[編輯] 1. Linux鏡像支持SD卡或EMMC啟動&#xff0c;并且會優先從SD卡啟動。 2. 建議使用A1級卡&#xff0c;至少8GB。 3. 如果您想從 SD 卡啟動&#xff0c;請確保可啟動 EMMC 已格式化。 4. 如果您想從 EMMC 啟動并使用 Sdcard 作為存儲&#xff0c;請確…

《微信小程序開發從入門到實戰》學習二十六

3.4 開發參與投票頁面 參與投票頁面同樣需要收集用戶提交的信息&#xff0c;哪個用戶在哪個投票選擇了什么選項&#xff0c;因此它也是一個表單頁面 3.4.1 如何獲取投票信息 假設用戶A在投票創建頁面后填了表單&#xff08;1.創建投票&#xff09;&#xff0c;用戶A 點了提交…

docker容器生成鏡像并上傳個人賬戶

登錄到 Docker Hub 賬戶&#xff1a; docker login這將提示你輸入你的 Docker Hub 賬戶名和密碼。 為容器創建鏡像 docker commit <容器名或容器ID> <你的用戶名>/<鏡像名:標簽>例子 docker commit my_container yourusername/my_image:latest推送鏡像到…

山西電力市場日前價格預測【2023-11-24】

日前價格預測 預測說明&#xff1a; 如上圖所示&#xff0c;預測明日&#xff08;2023-11-24&#xff09;山西電力市場全天平均日前電價為415.13元/MWh。其中&#xff0c;最高日前電價為685.26元/MWh&#xff0c;預計出現在18:00。最低日前電價為296.84元/MWh&#xff0c;預計…

Web實戰:基于Django與Bootstrap的在線計算器

文章目錄 寫在前面實驗目標實驗內容1. 創建項目2. 導入框架3. 配置項目前端代碼后端代碼 4. 運行項目 注意事項寫在后面 寫在前面 本期內容&#xff1a;基于Django與Bootstrap的在線計算器 實驗環境&#xff1a; vscodepython(3.11.4)django(4.2.7)bootstrap(3.4.1)jquery(3…

美國DDoS服務器:如何保護你的網站免遭攻擊?

?  在當今數字化時代&#xff0c;互聯網已經成為人們生活中不可或缺的一部分。隨著互聯網的普及和發展&#xff0c;網絡安全問題也日益嚴重。其中&#xff0c;DDoS攻擊是目前最常見和具有破壞性的網絡攻擊之一。那么&#xff0c;如何保護你的網站免遭DDoS攻擊呢?下面將介紹…

C#開發的OpenRA游戲之屬性Selectable(9)

C#開發的OpenRA游戲之屬性Selectable(9) 在游戲里,一個物品是否具有選中的能力,是通過添加屬性Selectable來實現的。當一個物品不能被用戶選取,那么就不要添加這個屬性。 這個屬性定義在下面這段描述里: ^Selectable: Selectable: SelectionDecorations: WithSpriteCon…

CSS畫一條線

<p style"border: 1px solid rgba(0, 0, 0, 0.1);"></p> 效果&#xff1a;

MATLAB中imbothat函數用法

目錄 語法 說明 示例 使用底帽和頂帽濾波增強對比度 imbothat函數的功能是對圖像進行底帽濾波。 語法 J imbothat(I,SE) J imbothat(I,nhood) 說明 J imbothat(I,SE) 使用結構元素 SE 對灰度或二值圖像 I 執行形態學底帽濾波。底帽濾波計算圖像的形態學閉運算&#…

蘋果手機內存滿了怎么清理?這里有你想要的答案!

手機內存不足是一個比較普遍的現象。由于現在手機應用程序的功能越來越強大&#xff0c;所以占用的內存也越來越大。同時用戶會在手機中存儲大量的數據&#xff0c;如照片、視頻、文檔等&#xff0c;這些都會占用大量的手機空間。那么&#xff0c;蘋果手機內存滿了怎么清理&…

C++數組中重復的數字

3. 數組中重復的數字 題目鏈接 牛客網 題目描述 在一個長度為 n 的數組里的所有數字都在 0 到 n-1 的范圍內。數組中某些數字是重復的,但不知道有幾個數字是重復的,也不知道每個數字重復幾次。請找出數組中任意一個重復的數字。 Input: {2, 3, 1, 0, 2, 5}Output: 2解題…

Altium Designer學習筆記10

再次根據圖紙進行布局走線&#xff1a; 這個MT2492 建議的布局走線。 那我這邊應該是盡量按照該圖進行布局&#xff1a; 其中我看到C1的電容的封裝使用的是電感的封裝&#xff0c;需要進行更換處理&#xff1a; 執行Validate Changes和Execute Changes操作&#xff0c;更新&a…

程序員最奔潰的瞬間

身為程序員哪一個瞬間讓你最奔潰&#xff1f; *程序員最奔潰的瞬間&#xff0c; 勇士&#xff1f; or 無知&#xff1f;

Ant Design Pro生產環境部署

Ant Design Pro是通過URL路徑前綴/api訪問后端服務器&#xff0c;因此在nginx配置以下代理即可。 location / {index.html } location /api {proxy_pass: api.mydomain.com }

CSDN文章保存為MD文檔(一)

免責聲明 文章僅做經驗分享用途&#xff0c;利用本文章所提供的信息而造成的任何直接或者間接的后果及損失&#xff0c;均由使用者本人負責&#xff0c;作者不為此承擔任何責任&#xff0c;一旦造成后果請自行承擔&#xff01;&#xff01;&#xff01; import os import re i…

Element中el-table組件右側空白隱藏-滾動條

開發情況&#xff1a; 固定table高度時&#xff0c;出現滾動條&#xff0c;我們希望隱藏滾動條&#xff0c;或修改滾動條樣式&#xff0c;出現table右邊出現15px 的固定留白。 代碼示例 <el-table class"controlTable" header-row-class-name"controlHead…

C語言二十一彈 --打印空心正方形

C語言實現打印空心正方形 思路&#xff1a;觀察圖中空心正方形&#xff0c;可知首行列和尾行列被黑色外框包裹&#xff0c;其它均為空。所以按觀察打印即可。 總代碼 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h>int main() {int n 0;while (scanf("%d&q…

關于數據擺渡 你關心的5個問題都在這兒!

數據擺渡&#xff0c;這個詞語的概念源自于網絡隔離和數據交換的場景和需求。不管是物理隔離、協議隔離、應用隔離還是邏輯隔離&#xff0c;最終目的都是為了保護內部核心數據的安全。而隔離之后&#xff0c;又必然會存在文件交換的需求。 傳統的跨網數據擺渡方式經歷了從人工U…