一、问题描述

1.1、具体需求:

        将CSDN博客文章内容爬取下来,并保存为PDF格式和MD格式。本博客以爬取【论文阅读】2022年最新迁移学习综述笔注(Transferability in Deep Learning: A Survey)为例介绍爬虫整个流程。

二、两种解决方案

2.1、方案一:通过专栏爬取指定文章

①:定位专栏,获取专栏网路请求url地址

②:定位文章,找到专栏中全部文章所在的位置信息

③:定位文章,找到文章的title和content所在的位置

④:python具体实现代码


"""
@Author :江上挽风&sty
@Blog(个人博客地址):https://blog.csdn.net/weixin_56097064
@File :CSDNSpider
@Time :2024/11/26 9:13
@Motto:一直努力,一直奋进,保持平常心

代码思路:
1.确定目标需求:通过专栏将csdn文章内容保存成 html、PDF、md格式
    - 1.1首先保存为html格式:获取列表页中所有的文章ur1地址,请求文章ur1地址获取我们需要的文章内容
    - 1.2 通过 wkhtmitopdf.exe把html文件转换成PDF文件
    - 1.3 通过 wkhtmitopdf.exe把html文件转换成md文件
2.请求ur1获取网页源代码
3.解析数据,提取自己想要内容
4.保存数据
5.转换数据类型把HTML转换成PDF、md文伴
"""

html_str = """
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
{article}
</body>
</html>
"""

import requests
import parsel   # 解析HTML和XML文档
import pdfkit   # 用来将html转为pdf
import re
import os
import urllib.parse
from bs4 import BeautifulSoup
import html2text    # 用来将html转换为md
import random

# user_agent库:每次执行一次访问随机选取一个 user_agent,防止过于频繁访问被禁止
USER_AGENT_LIST = [
    "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1",
    "Mozilla/5.0 (X11; CrOS i686 2268.111.0) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11",
    "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1092.0 Safari/536.6",
    "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1090.0 Safari/536.6",
    "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; 360SE)",
    "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",
    "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",
    "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.0 Safari/536.3",
    "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.24 (KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24",
    "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/535.24 (KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24"
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.82 Safari/537.36"
]

class CSDNSpider():
    def __init__(self):
        self.url = 'https://blog.csdn.net/cy19980216/category_10557406.html'
        self.headers = {
            'user-agent': random.choice(USER_AGENT_LIST)
        }

    def send_request(self, url):
        response = requests.get(url=url, headers=self.headers)
        response.encoding = "utf-8"
        if response.status_code == 200:
            return response

    def parse_content(self, reponse):
        html = reponse.text
        selector = parsel.Selector(html)  # 创建一个新的 Selector 对象,用于后续的HTML或XML数据解析
        href = selector.css('.column_article_list a::attr(href)').getall()  # 提取满足要求的全部href元素,即获取全部链接并保存为一个列表
        name = 00
        for link in href:
            print(link)
            name = name + 1
            # 对文章的url地址发送请求
            response = self.send_request(link)
            if response:
                self.parse_detail(response, name)

    def parse_detail(self, response, name):
        html = response.text
        # print(html)
        selector = parsel.Selector(html)
        title = selector.css('#articleContentId::text').get()
        # content = selector.css('#content_views').get()
        # print(title)
        # 由于这里使用parsel拿到的网页文件,打开会自动跳转到csdn首页,并且不能转为pdf,就想在这里用soup
        soup = BeautifulSoup(html, 'lxml')

        content = soup.find('div',id="content_views",class_=["markdown_views prism-github-gist", "htmledit_views"]) #class_="htmledit_views"
        # print(content)
        # print(title, content)

        html = html_str.format(article=content)  # 将content得到的内容插入到开头定义的模板中,得到一个新的html对象
        self.write_content(html, title)

    def write_content(self, content, name):
        html_path = "HTML/" + str(self.change_title(name)) + ".html"
        pdf_path = "PDF/" + str(self.change_title(name))+ ".pdf"
        md_path = "MD/" + str(self.change_title(name)) + ".md"

        # 将内容保存为html文件
        with open(html_path, 'w', encoding="utf-8") as f:
            f.write(content)
            print("正在保存", name, ".html")

        # 将html文件转换成PDF文件
        config = pdfkit.configuration(wkhtmltopdf=r'D:\ApplicationsSoftware\Wkhtmltopdf\bin\wkhtmltopdf.exe')
        pdfkit.from_file(html_path, pdf_path, configuration=config)
        print("正在保存", name, ".pdf")
        # os.remove(html_path)

        # 将html文件转换成md格式
        html_text = open(html_path, 'r', encoding='utf-8').read()
        markdown = html2text.html2text(html_text)
        with open(md_path, 'w', encoding='utf-8') as file:
            file.write(markdown)
            print("正在保存", name, ".md")

    # 这个新标题字符串中的某些特殊字符被替换为了下划线 _。这些特殊字符包括:反斜杠 \、斜杠 /、冒号 :、问号 ?、星号 *、双引号 "、小于号 <、大于号 >、竖线 | 和感叹号 !
    def change_title(self, title):
        mode = re.compile(r'[\\\/\:\?\*\"\<\>\|\!]')
        new_title = re.sub(mode,'_', title)  # re.sub 是 re 模块中的另一个函数,用于替换字符串中匹配正则表达式模式的子串
        return new_title

    def start(self):
        response = self.send_request(self.url)
        if response:
            self.parse_content(response)


if __name__ == '__main__':
    csdn = CSDNSpider()
    csdn.start()

2.2、方案二:通过URL爬取指定文章


"""
@Author :江上挽风&sty
@Blog(个人博客地址):https://blog.csdn.net/weixin_56097064
@File :CSDNSpider
@Time :2024/11/26 9:13
@Motto:一直努力,一直奋进,保持平常心

代码思路:
1.确定目标需求:通过指定csdn文章内容保存成 html、PDF、md格式
2.请求url获取网页源代码
3.解析数据,提取自己想要内容
4.保存数据
5.转换数据类型把HTML转换成PDF、md文伴
"""

html_str = """
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
{article}
</body>
</html>
"""

import requests
import parsel   # 解析HTML和XML文档
import pdfkit   # 用来将html转为pdf
import re
import os
import urllib.parse
from bs4 import BeautifulSoup
import html2text    # 用来将html转换为md
import random

# user_agent库:每次执行一次访问随机选取一个 user_agent,防止过于频繁访问被禁止
USER_AGENT_LIST = [
    "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1",
    "Mozilla/5.0 (X11; CrOS i686 2268.111.0) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11",
    "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1092.0 Safari/536.6",
    "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1090.0 Safari/536.6",
    "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; 360SE)",
    "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",
    "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",
    "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.0 Safari/536.3",
    "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.24 (KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24",
    "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/535.24 (KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24"
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.82 Safari/537.36"
]

class OneCSDNSpider():
    def __init__(self):
        self.url = 'https://caoyang.blog.csdn.net/article/details/125580146'
        self.headers = {
            'user-agent': random.choice(USER_AGENT_LIST)
        }

    def send_request(self, url):
        response = requests.get(url=url, headers=self.headers)
        response.encoding = "utf-8"
        if response.status_code == 200:
            return response

    def parse_content(self, reponse):
        html = reponse.text
        selector = parsel.Selector(html)  # 创建一个新的 Selector 对象,用于后续的HTML或XML数据解析

        name = selector.css('#articleContentId::text').get()
        soup = BeautifulSoup(html, 'lxml')
        content = soup.find('div', id="content_views",
                            class_=["markdown_views prism-github-gist", "htmledit_views"])  # class_="htmledit_views"
        html = html_str.format(article=content)  # 将content得到的内容插入到开头定义的模板中,得到一个新的html对象
        self.write_content(html, name)

    def write_content(self, content, name):
        html_path = "HTML/" + str(self.change_title(name)) + ".html"
        pdf_path = "PDF/" + str(self.change_title(name)) + ".pdf"
        md_path = "MD/" + str(self.change_title(name)) + ".md"

        # 将内容保存为html文件
        with open(html_path, 'w', encoding="utf-8") as f:
            f.write(content)
            print("正在保存", name, ".html")

        # 将html文件转换成PDF文件
        config = pdfkit.configuration(wkhtmltopdf=r'D:\ApplicationsSoftware\Wkhtmltopdf\bin\wkhtmltopdf.exe')
        pdfkit.from_file(html_path, pdf_path, configuration=config)
        print("正在保存", name, ".pdf")
        # os.remove(html_path)

        # 将html文件转换成md格式
        html_text = open(html_path, 'r', encoding='utf-8').read()
        markdown = html2text.html2text(html_text)
        with open(md_path, 'w', encoding='utf-8') as file:
            file.write(markdown)
            print("正在保存", name, ".md")

    # 这个新标题字符串中的某些特殊字符被替换为了下划线 _。这些特殊字符包括:反斜杠 \、斜杠 /、冒号 :、问号 ?、星号 *、双引号 "、小于号 <、大于号 >、竖线 | 和感叹号 !
    def change_title(self, title):
        mode = re.compile(r'[\\\/\:\?\*\"\<\>\|\!]')
        new_title = re.sub(mode,'_', title)  # re.sub 是 re 模块中的另一个函数,用于替换字符串中匹配正则表达式模式的子串
        return new_title

    def start(self):
        response = self.send_request(self.url)
        if response:
            self.parse_content(response)


if __name__ == '__main__':
    csdn = OneCSDNSpider()
    csdn.start()

前提是已经创建了HTML、PDF、MD三个文件夹,否则程序报文件夹不存在错误,也可通过程序来自动创建三个文件夹,防止程序报错,完成的代码如下所示:


"""
@Author :江上挽风&sty
@Blog(个人博客地址):https://blog.csdn.net/weixin_56097064
@File :CSDNSpider
@Time :2024/11/26 9:13
@Motto:一直努力,一直奋进,保持平常心

代码思路:
1.确定目标需求:通过指定csdn文章内容保存成 html、PDF、md格式
2.请求url获取网页源代码
3.解析数据,提取自己想要内容
4.保存数据
5.转换数据类型把HTML转换成PDF、md文伴
"""

html_str = """
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
{article}
</body>
</html>
"""

import requests
import parsel   # 解析HTML和XML文档
import pdfkit   # 用来将html转为pdf
import re
import os
import urllib.parse
from bs4 import BeautifulSoup
import html2text    # 用来将html转换为md
import random

# user_agent库:每次执行一次访问随机选取一个 user_agent,防止过于频繁访问被禁止
USER_AGENT_LIST = [
    "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1",
    "Mozilla/5.0 (X11; CrOS i686 2268.111.0) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11",
    "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1092.0 Safari/536.6",
    "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1090.0 Safari/536.6",
    "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; 360SE)",
    "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",
    "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",
    "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.0 Safari/536.3",
    "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.24 (KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24",
    "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/535.24 (KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24"
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.82 Safari/537.36"
]

class OneCSDNSpider():
    def __init__(self):
        self.url = 'https://caoyang.blog.csdn.net/article/details/125580146'
        self.headers = {
            'user-agent': random.choice(USER_AGENT_LIST)
        }

    def send_request(self, url):
        response = requests.get(url=url, headers=self.headers)
        response.encoding = "utf-8"
        if response.status_code == 200:
            return response

    def parse_content(self, reponse):
        html = reponse.text
        selector = parsel.Selector(html)  # 创建一个新的 Selector 对象,用于后续的HTML或XML数据解析

        name = selector.css('#articleContentId::text').get()
        soup = BeautifulSoup(html, 'lxml')
        content = soup.find('div', id="content_views",
                            class_=["markdown_views prism-github-gist", "htmledit_views"])  # class_="htmledit_views"
        html = html_str.format(article=content)  # 将content得到的内容插入到开头定义的模板中,得到一个新的html对象
        self.write_content(html, name)

    def write_content(self, content, name):
        # 定义文件夹路径
        html_folder = "HTML"
        pdf_folder = "PDF"
        md_folder = "MD"

        # 创建文件夹如果它们不存在
        if not os.path.exists(html_folder):
            os.makedirs(html_folder)
        if not os.path.exists(pdf_folder):
            os.makedirs(pdf_folder)
        if not os.path.exists(md_folder):
            os.makedirs(md_folder)

        # 定义文件路径
        html_path = os.path.join(html_folder, self.change_title(name) + ".html")
        pdf_path = os.path.join(pdf_folder, self.change_title(name) + ".pdf")
        md_path = os.path.join(md_folder, self.change_title(name) + ".md")

        # 将内容保存为html文件
        with open(html_path, 'w', encoding="utf-8") as f:
            f.write(content)
            print("正在保存", name, ".html")

        # 将html文件转换成PDF文件
        config = pdfkit.configuration(wkhtmltopdf=r'D:\ApplicationsSoftware\Wkhtmltopdf\bin\wkhtmltopdf.exe')
        pdfkit.from_file(html_path, pdf_path, configuration=config)
        print("正在保存", name, ".pdf")
        # os.remove(html_path)

        # 将html文件转换成md格式
        html_text = open(html_path, 'r', encoding='utf-8').read()
        markdown = html2text.html2text(html_text)
        with open(md_path, 'w', encoding='utf-8') as file:
            file.write(markdown)
            print("正在保存", name, ".md")

    # 这个新标题字符串中的某些特殊字符被替换为了下划线 _。这些特殊字符包括:反斜杠 \、斜杠 /、冒号 :、问号 ?、星号 *、双引号 "、小于号 <、大于号 >、竖线 | 和感叹号 !
    def change_title(self, title):
        mode = re.compile(r'[\\\/\:\?\*\"\<\>\|\!]')
        new_title = re.sub(mode,'_', title)  # re.sub 是 re 模块中的另一个函数,用于替换字符串中匹配正则表达式模式的子串
        return new_title

    def start(self):
        response = self.send_request(self.url)
        if response:
            self.parse_content(response)


if __name__ == '__main__':
    csdn = OneCSDNSpider()
    csdn.start()

三、其他配置

3.1、下载wkhtmltopdf软件(环境变量配置)

wkhtmltopdf是一个开源的命令行工具,它使用Qt WebKit渲染引擎将HTML页面转换成PDF文件或图像(如jpg、png等)。以下是wkhtmltopdf的一些主要特点和功能:

1. **开源和跨平台**:wkhtmltopdf是一个开源工具,可以在Windows、Linux和Mac OS X等多个操作系统上运行。

2. **WebKit渲染引擎**:它使用WebKit渲染引擎来保持HTML页面在转换为PDF时的布局和样式,确保转换后的PDF文件质量。

3. **页眉和页脚**:wkhtmltopdf允许用户添加自定义的页眉和页脚,增强PDF文件的可读性。

4. **目录生成(TOC)**:工具支持自动根据HTML页面中的`H`标签生成树形目录结构,方便文档的导航。

5. **批量模式转换**:wkhtmltopdf提供批量模式转换,可以一次性转换多个网页。

6. **支持PHP或Python绑定**:通过绑定libwkhtmltox,wkhtmltopdf支持在PHP或Python脚本中使用。

7. **命令行工具**:wkhtmltopdf是一个命令行工具,可以通过命令行直接使用,也可以在脚本中调用。

8. **高级特性**:除了基本的转换功能,wkhtmltopdf还支持多种选项和参数,如页面设置、页边距设置、页面缩放、禁用目录结构、JavaScript执行延迟等,以满足不同的需求。

总的来说,wkhtmltopdf是一个功能强大且灵活的工具,适用于将网页内容转换为PDF格式,广泛应用于报告生成、文档保存等多种场景。

3.2、Pycharm中添加个人信息

四、参考文章

1、爬取CSDN专栏文章到本地,并保存为html、pdf、md格式_csdn会员文章提取-CSDN博客

2、wkhtmltopdf 工具安装与使用_wkhtmltopdf.exe-CSDN博客

Logo

加入社区!打开量化的大门,首批课程上线啦!

更多推荐