当前位置: 首页 > news >正文

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)


结语

没有人规定,一朵花一定要成长为向日葵或者玫瑰。

相关文章:

CSDN文章保存为MD文档(一)

免责声明 文章仅做经验分享用途&#xff0c;利用本文章所提供的信息而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;作者不为此承担任何责任&#xff0c;一旦造成后果请自行承担&#xff01;&#xff01;&#xff01; import os import re i…...

【tomcat】java.lang.Exception: Socket bind failed: [730048

项目中一些旧工程运行情况处理 问题 1、启动端口占用 2、打印编码乱码 ʮһ&#xfffd;&#xfffd; 13, 2023 9:33:26 &#xfffd;&#xfffd;&#xfffd;&#xfffd; org.apache.coyote.AbstractProtocol init &#xfffd;&#xfffd;&#xfffd;&#xfffd;: Fa…...

什么是高防IP?有什么优势?怎么选择高防IP?

在当今的互联网环境中&#xff0c;分布式拒绝服务&#xff08;DDoS&#xff09;攻击已经成为一种常见的安全威胁。这种攻击通过向目标服务器发送大量的无效流量&#xff0c;使其无法处理正常的请求&#xff0c;从而达到迫使服务中断的目的。作为一个用户&#xff0c;你是否曾遇…...

不存在类型变量 A, T 的实例,使 Collector<T, A, List<T>> 符合 Supplier<R>

报错信息 原因: 不存在类型变量 A, T 的实例&#xff0c;使 Collector<T, A, List<\T>> 符合 Supplier<\R> 来源 测试Stream流的map方法&#xff0c;做算法习惯基本类型定义数组。 map方法:Stream API的一部分。允许以一种声明式的方式处理数据&#xff0c…...

千兆光模块和万兆光模块的供应链管理

随着网络通信技术的不断发展&#xff0c;千兆光模块和万兆光模块已逐渐成为现代网络建设中不可缺少的组成部分。它们在云计算、数据中心、大规模机房以及企业内部网络等领域广泛应用&#xff0c;已经成为大家熟知的产品。 千兆光模块和万兆光模块的工作原理基本相同&#xff…...

pytorch训练出现的bug

训练过后发现.csv文件左侧出现了几列unname和一列0&#xff0c;1&#xff0c;2。这个时候在训练就会从unname那一列开始训练。我们需要把这几列删除&#xff0c;之后再重新训练 问题应该是执行完了这个语句过后就会出现了。 执行完后&#xff0c;记得删。...

【AGC】集成AGC服务上架应用市场审核问题

【关键字】 AGC、应用市场、审核 【问题描述】 集成了AGC服务&#xff0c;上架到应用市场不通过&#xff0c;检查发现是com.huawei.secure.android.common.ssl.util.c.doInBackground 存在获取安装列表行为。 已经按照sdk 设置了&#xff0c;但是检测还是有授权前去获取安装列…...

element emitter broadcast向下广播 dispatch向上分派

emitter 项目使用element的emitter.js&#xff0c;做个使用记录 function broadcast(componentName, eventName, params) {this.$children.forEach(child > {const name child.$options.name;if (name componentName) {child.$emit.apply(child, [eventName].concat(para…...

基于 Modbus 的工业数据采集、控制(part 2)

基本处理流程 服务器 parse_and_process(char * input)//input :post请求发送的正文 {...// 请求 modbus 数据else if(strstr(input, "modbus_get")){return handle_get(sock, input);}// 控制 modbus 设备else if(strstr(input, "modbus_set")){return …...

vue前端项目如何配置后端项目的请求地址

在 Vue 前端项目中配置后端项目的访问地址可以通过修改项目的配置文件来实现。Vue 常用的配置文件是 vue.config.js&#xff0c;你可以按照以下步骤进行配置&#xff1a; 在 Vue 项目的根目录下&#xff0c;创建或编辑 vue.config.js 文件。 在 vue.config.js 中&#xff0c;可…...

Lora学习资料汇总

目录 LoRa联盟 Semtech lora网关供应商: LoRaMAC API文档 论坛 开发板 主流技术对比分析 LoRa网络距离模拟测试方法 LoRa应用 LoRa联盟 LoRa联盟&#xff1a;LoRaWAN规范的制定组织 https://www.lora-alliance.org/ LoRa技术白皮书&#xff1a;https://www.lora-alli…...

Oracle的控制文件多路复用,控制文件备份,控制文件手工恢复

一.配置控制文件多路复用 1.查询Oracle的控制文件所在位置 SQL> select name from v$controlfile;NAME -------------------------------------------------------------------------------- /u01/app/oracle/oradata/orcl/control01.ctl /u01/app/oracle/fast_recovery_a…...

在线视频课程教育系统源码/网课网校/知识付费/在线教育系统/在线课程培训系统源码

源码简介&#xff1a; 在线视频课程教育系统源码&#xff0c;作为网课/网校/知识付费/在线教育系统&#xff0c;它有文章付费阅读在线点播自动发货付费阅读VIP会员系统等功能。它是实用的在线课程培训系统源码。 发货100-在线视频课程教育系统&#xff0c;它是一款功能实用的…...

程序员护城河:保障系统安全与网络稳定的不可或缺力量

引言&#xff1a; 在当今数字化时代&#xff0c;计算机和互联网的广泛应用使得程序员的角色变得越来越重要。作为保障系统安全与网络稳定的关键力量&#xff0c;程序员需要具备一系列的基本能力&#xff0c;同时还需掌握一些专业技术和策略&#xff0c;以确保系统运行的安全性…...

html属性值可以不用引号吗,实例验证

html属性值可以不用引号 HTML元素的属性值可以不适用引号来包裹&#xff0c;浏览器一样可以将其进行渲染。不过&#xff0c;如果这样写HTML的代码的话&#xff0c;属性与属性值之间需要用空格来进行隔开&#xff0c;避免后面的属性变成前面属性的属性值。 提示&#xff1a;虽…...

angular 实现模块共享

angular 实现共享模块 新建共享模块: ng g m material material.module.ts import {NgModule } from @angular/core; import {OverlayModule } from @angular/cdk/overlay; import {CdkTreeModule } f...

带记忆的超级GPT智能体,能做饭、煮咖啡、整理家务!

随着AI技术的快速迭代&#xff0c;Alexa、Siri、小度、天猫精灵等语音助手得到了广泛应用。但在自然语言理解和完成复杂任务方面仍然有限。 相比文本的标准格式&#xff0c;语音充满复杂性和多样性&#xff08;例如&#xff0c;地方话&#xff09;,传统方法很难适应不同用户的…...

易点易动设备管理系统提升设备能耗管理和设备状态监控效率

如今&#xff0c;能源效率和设备状态监控对于企业来说变得越发重要。传统的设备管理方式往往存在能耗浪费和难以实时监控设备状态的问题。为了解决这些问题&#xff0c;易点易动设备管理系统应运而生。本文将介绍易点易动设备管理系统的功能和优势&#xff0c;以及如何通过它提…...

【idea】解决idea 执行maven build总下载 Downloading maven-metadata.xml文件

可以看到如下日志中打印了执行的命令行&#xff0c;其中包含 --update-snapshots&#xff0c;是强制更新的意思。 日志内容如下&#xff1a; D:\env\jdk1.8.0_261\bin\java.exe --update-snapshots -s D:\env\apache-maven-3.8.6\conf\settings.xml -Dmaven.repo.localD:\env\…...

HttpClient发送MultipartFile多文件及多参数请求

1、环境准备&#xff1a; <dependency><groupId>commons-httpclient</groupId><artifactId>commons-httpclient</artifactId><version>3.1</version></dependency><dependency><groupId>org.apache.httpcomponent…...

并发编程AQS之ReentrantLock/Semaphore/CountDownLatch/CyclicBarrier

一、管程——Java线程同步的设计思想管程&#xff1a;指的是管理共享变量以及对共享变量的操作过程&#xff0c;让他们支持并发。互斥&#xff1a;同一时刻只允许一个线程访问共享资源&#xff1b;同步&#xff1a;线程之间如何通信、协作。MESA模型在管程的发展史上&#xff0…...

NI-DAQmx性能调优秘籍:避开‘隐式转换’和‘循环内启停’这些坑,让你的采集速度翻倍

NI-DAQmx性能调优实战&#xff1a;从隐式转换陷阱到高效事件驱动的全链路优化 在LabVIEW数据采集领域&#xff0c;NI-DAQmx驱动堪称工业级应用的黄金标准。但许多中高级开发者常陷入这样的困境&#xff1a;硬件配置堪称豪华&#xff0c;采样率设置也足够保守&#xff0c;可程序…...

从p值到公平性决策:R语言中FDR校正、多组间Kolmogorov–Smirnov联合检验与LLM群体公平性阈值设定黄金公式

更多请点击&#xff1a; https://intelliparadigm.com 第一章&#xff1a;R语言在大语言模型偏见检测中的统计方法高级开发技巧 在大语言模型&#xff08;LLM&#xff09;部署前的伦理评估中&#xff0c;R语言凭借其强大的统计建模能力与可复现性&#xff0c;正成为偏见量化分…...

5步掌握MuseTalk:AI唇形同步技术实战指南与高级技巧

5步掌握MuseTalk&#xff1a;AI唇形同步技术实战指南与高级技巧 【免费下载链接】MuseTalk MuseTalk: Real-Time High Quality Lip Synchorization with Latent Space Inpainting 项目地址: https://gitcode.com/gh_mirrors/mu/MuseTalk MuseTalk是一款基于潜在空间修复…...

Kettle调度避坑实录:从.bat脚本编写到Windows任务计划,我踩过的那些雷

Kettle调度避坑实录&#xff1a;从.bat脚本编写到Windows任务计划&#xff0c;我踩过的那些雷 第一次尝试用Windows任务计划调度Kettle作业时&#xff0c;我以为按照教程一步步操作就能轻松搞定。直到凌晨三点还在排查为什么任务计划显示"成功执行"&#xff0c;但数据…...

5分钟掌握:终极免费图像转字节数组工具让OLED开发如此简单

5分钟掌握&#xff1a;终极免费图像转字节数组工具让OLED开发如此简单 【免费下载链接】image2cpp 项目地址: https://gitcode.com/gh_mirrors/im/image2cpp image2cpp图像转换工具是一个专为嵌入式开发者设计的强大在线工具&#xff0c;能够将普通图像快速转换为适用于…...

别再为接线发愁!STM32F407ZGT6连接ST-LINK与USB转TTL的保姆级图文指南(附舵机驱动)

STM32F407ZGT6开发板接线全攻略&#xff1a;从ST-LINK调试到舵机控制 第一次拿到STM32开发板时&#xff0c;面对密密麻麻的引脚和一堆调试工具&#xff0c;大多数新手都会感到无从下手。本文将彻底解决这个痛点&#xff0c;不仅告诉你如何正确连接ST-LINK调试器和USB转TTL模块…...

Stable Diffusion文生图实战:从CLIP编码到VAE解码,一步步拆解txt2img的完整流程

Stable Diffusion文生图核心技术解析&#xff1a;从文本编码到图像生成的完整实现路径 在当今AI生成内容&#xff08;AIGC&#xff09;领域&#xff0c;Stable Diffusion已成为最受开发者关注的文本到图像生成模型之一。本文将深入剖析其核心架构与实现细节&#xff0c;通过代码…...

FFXIV ACT动画跳过插件终极指南:3分钟快速安装,副本效率提升50%

FFXIV ACT动画跳过插件终极指南&#xff1a;3分钟快速安装&#xff0c;副本效率提升50% 【免费下载链接】FFXIV_ACT_CutsceneSkip 项目地址: https://gitcode.com/gh_mirrors/ff/FFXIV_ACT_CutsceneSkip 还在为FFXIV中冗长的副本过场动画烦恼吗&#xff1f;FFXIV_ACT_C…...

C语言完美演绎9-8

/* 范例&#xff1a;9-8 */ #include <stdio.h> /* 声明 定义 (并给初值) */ enum /* 省略类型名称 */ { one1,two,three }enum_a, enum_btwo; /* 声明自定义列举类型Weather */ enum Weather /* 包含自定义类型名称 */ { Spring1,Summer,Autumn,Winter /* 定…...