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

免責聲明

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

import os
import re
import sys
import requests
sys.path.append("")
from os.path import join, exists
from urllib.request import urlretrieve
from bs4 import BeautifulSoup, Tag, NavigableString, Comment

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'?
? ? ? ? ? ? ? ? ? ? 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 == '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 = join(self.fig_dir, img_file)
? ? ? ? ? ? ? ? urlretrieve(src, img_file)
? ? ? ? ? ? ? ? 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)

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('正在保存 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) Safari/537.36",
? ? ? ? "x-requested-with": "XMLHttpRequest"
? ? ? ? }

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

if __name__ == '__main__':
? ? article_url = input(str("輸入需要保存的csdn博客鏈接:")) #csdn博客鏈接
? ? markdown_dir = './' #保存文件夾
? ? download_csdn_single_page(article_url,markdown_dir)


結語

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

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

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

相關文章

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…

手把手教你通過CODESYS V3進行PLC編程(二)

教程背景 在上一期教程中&#xff0c;我們已經完成了控制器設備的連接和配置。接下來的教程將繼續以宏集MC-Prime為例&#xff0c;假設控制器已經配置并連接到開發者的PC上&#xff0c;為您演示如何為控制器安裝合適的CODESYS V3版本并創建第一個程序。 一、安裝CODESYS &…

調用飛漿情感評分模型

# 跑模型并保存 import paddlehub as hub # 加載模型 senta hub.Module(name"senta_lstm")# dataframe格式轉為list格式 text articles[標題內容].drop_duplicates().to_list() # 情感評分 results_data senta.sentiment_classify(data{text:text}) results_df p…

解決 requests 庫下載文件問題的技術解析

每次都以為自己即將戰勝bug&#xff0c;這是一場永無休止的游戲。在編程的世界中&#xff0c;bug就像狡猾的敵人&#xff0c;時隱時現&#xff0c;讓人防不勝防。 今天&#xff0c;我要分享的是如何解決requests庫下載文件問題的技術解析。這是一個讓我頭痛已久的bug&#xff0…

FastAPI通過SSE進行流式輸出

服務端推送 在服務器推送技術中&#xff0c;服務器在消息可用后立即主動向客戶端發送消息。其中&#xff0c;有兩種類型的服務器推送&#xff1a;SSE和 WebSocket。 SSE&#xff08;Server-Send Events&#xff09; SSE 是一種在基于瀏覽器的 Web 應用程序中僅從服務器向客戶…

【高級網絡程序設計】Week2-1 Sockets

一、The Basics 1. Sockets 定義An abstraction of a network interface應用 use the Socket API to create connections to remote computers send data(bytes) receive data(bytes) 2. Java network programming the java network libraryimport java.net.*;similar to…

pgsql常用命令總結

pgsql常用命令及相關總結 命令 命令登錄 psql -U postgres -h 127.0.0.1 -p 5432 -d vism查看所有數據庫&#xff1a;\l 進入某一數據庫&#xff1a;\c 數據庫名字 查看數據庫表&#xff1a;\dt 列出某一張表格的結構&#xff1a;\d 表名 查看某個表的所有數據&#xff1a;s…

學習筆記記錄

目錄 windows php一句話木馬 日志清理 DOS命令 查看用戶的SID 最高權限 常見的cmd命令 反彈shell PHPMYadmin mysql注入語句 wmic linux crontab創建隱藏后門 linux日志文件 knockd服務 ssh登錄 ssh隧道 本地轉發 遠程轉發 動態轉發 /proc: Centos 8 更…

CentOS 7 使用cJSON 庫

什么是JSON JSON是一種輕量級的數據交換格式&#xff0c;可讀性強、編寫簡單。鍵值對組合編寫規則&#xff0c;鍵名使用雙引號包裹&#xff0c;冒號&#xff1a;分隔符后面緊跟著數值&#xff0c;有兩種常用的數據類型是對象和數組。 對象&#xff1a;使用花括號{}包裹起來的…

【Rxjava詳解】(三)更好實踐異步請求

本文為更像demo的總結&#xff0c;在實際開發中&#xff0c;利用rxjava采取異步請求在一些簡單的單純請求數據上面&#xff0c;會顯得沒有必要&#xff0c;但rxjava提供的思路&#xff0c;在后期不論是增加功能&#xff0c;還是說整體代碼的工整度&#xff0c;都能感受到開發的…

補充:自動化測試高級應用之python多線程的使用-新方法

前段時間在網上學習多線程跑用例的時,發現一種更簡潔,優雅的使用多線程的方法,在此分享給大家。 閱讀本文前,請先閱讀前面寫的多線程跑用例的文章:【精選】第七章 第四節 自動化測試高級應用之python多線程的使用_add_test_img-CSDN博客 本文新的方法,對原有的run_al…

接口傳參數list的時候,items里面放個???????list

item里面放個list 先定義一個 list&#xff0c;循環add加入參數

java之switch case的用法

java之switch case的用法 Java中的switch語句是一種多路選擇結構&#xff0c;它允許一個變量在其值的多個可能選項之間進行選擇。這種結構可以替代一系列嵌套的if-else語句&#xff0c;使代碼更清晰和簡潔。 下面是switch語句的基本語法&#xff1a; switch (expression) { …

android keylayout鍵值適配

1、通過getevent打印查看當前keyevent數字對應事件和物理碼 2、dumpsys input 查看輸入事件對應的 KeyLayoutFile: /system/usr/keylayout/Vendor_6080_Product_8060.kl 3、通過物理碼修改鍵值映射&#xff0c;修改/system/usr/keylayout/目錄下的文件

CuratorFramework的blockUntilConnected方法

CuratorFramework是一個ZooKeeper客戶端庫&#xff0c;它提供了一些用于處理ZooKeeper連接和節點操作的高級API。其中&#xff0c;blockUntilConnected方法是一個阻塞方法&#xff0c;它會一直阻塞直到客戶端成功連接到ZooKeeper服務器。 具體來說&#xff0c;blockUntilConne…

(三)、基于 LangChain 實現大模型應用程序開發 | 模型鏈 Chains

&#x1f604; 為什么我們需要Chains &#xff1f; 鏈允許我們將多個組件組合在一起&#xff0c;以創建一個單一的、連貫的應用程序。鏈&#xff08;Chains&#xff09;通常將一個LLM&#xff08;大語言模型&#xff09;與提示結合在一起&#xff0c;使用這個構建塊&#xff0…

永久免費!N個excel表一鍵合并成一個表(excel表格合并技巧)

您是否還在用手工復制粘貼來將多個EXCEL或表的數據合并到一個表里&#xff1f;那就太麻煩&#xff0c;效率太低了&#xff0c;用金鳴表格文字識別的“表格合并”功能&#xff0c;可免費將N個excel文件或N個excel表一鍵合并到一個表里面&#xff0c;而且這個功能永久免費&#x…

【C++】特殊類設計 {不能被拷貝的類;只能在堆上創建的類;只能在棧上創建的類;不能被繼承的類;單例模式:懶漢模式,餓漢模式}

一、不能被拷貝的類 設計思路&#xff1a; 拷貝只會發生在兩個場景中&#xff1a;拷貝構造和賦值重載&#xff0c;因此想要讓一個類禁止拷貝&#xff0c;只需讓該類不能調用拷貝構造以及賦值重載即可。 C98方案&#xff1a; 將拷貝構造與賦值重載只聲明不定義&#xff0c;并…