python爬虫:将知乎专栏文章转为pdf

欢迎关注本人的知乎主页~

实现思路

  1. 用户输入专栏ID:

    1. 代码首先提示用户输入一个知乎专栏的ID,默认值为 'c_1747690982282477569'
    2. 输入的ID用于构建API请求的URL。
  2. 发送HTTP请求:

    1. 使用 requests.get() 向知乎API发送GET请求,获取指定专栏的文章列表。
    2. 检查响应的状态码,确认请求是否成功。
  3. 如果请求成功,解析返回的JSON数据,并将其保存到本地文件 zhihu.json 中。

  4. 定义处理HTML内容的函数 process_content

    1. 这个函数用于处理文章的HTML内容,具体操作包括:
      1. 移除 data-pid 属性。
      2. 替换特殊的字符 \u003C\u003E<>
      3. 添加段落的缩进和底部边距。
      4. 移除包含 <img><figure> 标签。
      5. 移除 class="ztext-empty-paragraph"<p> 标签。
      6. 去除多余的 <br> 标签。
      7. 确保每个段落都在 <p></p> 之间。
  5. 从之前保存的 zhihu.json 文件中读取JSON数据,并解析为Python字典。

  6. 从解析后的数据中提取文章的具体内容和标题。

  7. 创建一个名为 articles 的目录来保存生成的HTML文件。

  8. 使用 Jinja2 模板引擎初始化模板环境,并加载预定义的HTML模板 template.html

  9. 遍历文章数据并生成HTML文件:

    1. 对每篇文章的内容进行处理,并使用Jinja2模板渲染为完整的HTML页面。
    2. 将渲染后的HTML内容保存到 articles 目录下的 .html 文件中。
  10. 转换HTML文件为PDF文件:

    1. 创建一个名为 pdfs 的目录来保存生成的PDF文件。
    2. 遍历 articles 目录中的所有HTML文件,并使用 pdfkit 将其转换为PDF格式。
    3. 在转换过程中,禁止加载远程资源,并忽略加载错误。
  11. 输出结果信息,告知用户所有文章已保存为HTML文件,并且所有HTML文件已转换为PDF文件。

完整代码

python 复制代码
import json
import os
import re
from jinja2 import Environment, FileSystemLoader
import requests
import pdfkit

# 用户输入专栏名称,默认为c_1747690982282477569
column_id = input("请输入知乎专栏ID(默认为 c_1747690982282477569):") or 'c_1747690982282477569'
url = f'https://www.zhihu.com/api/v4/columns/{column_id}/articles'

# 发送请求获取专栏文章列表
response = requests.get(url)

# 检查请求是否成功
if response.status_code == 200:
    # 解析 JSON 数据
    data = response.json()
    
    # 保存到本地文件
    output_file = 'zhihu.json'
    with open(output_file, 'w', encoding='utf-8') as file:
        json.dump(data, file, ensure_ascii=False, indent=4)
    
    print(f"数据已保存到 {output_file}")
else:
    print(f"请求失败,状态码:{response.status_code}")

def process_content(content):
    """
    处理HTML内容,移除不需要的标签和属性,调整样式等。
    """
    # 移除标识符号
    # 匹配 data-pid 属性,并允许属性值使用普通双引号或转义的双引号,以及可能存在的空白字符
    content = re.sub(r'data-pid\s*=\s*(?:"|\")(.+?)(?:"|\")', '', content)
    
    # 替换特殊字符
    content = content.replace('\u003C', '<').replace('\u003E', '>')
    
    # 处理<p>标签,添加缩进和底部边距
    content = content.replace('<p ', '<p style="text-indent: 2em; margin-bottom: 1em;">')
    
    # 处理</p>标签
    content = content.replace('</p>', '</p>')
    
    # 移除包含 <img> 的 <figure> 标签
    content = re.sub(r'<figure.*?>.*?</figure>', '', content, flags=re.DOTALL)
    
    # 移除 class="ztext-empty-paragraph"
    content = re.sub(r'<p[^>]*class\s*=\s*["\']ztext-empty-paragraph["\'][^>]*>', '</p>', content)
    
    # 去除多余的<br>
    content = re.sub(r'</p><br>', '</p>', content)
    
    # 最后一个段落不应该有额外的换行
    if content.endswith('<p style="text-indent: 2em; margin-bottom: 1em;">'):
        content = content[:-len('<p style="text-indent: 2em; margin-bottom: 1em;">')]
    content += '</p>'
    
    # 确保每段文本都包裹在<p>和</p>之间
    paragraphs = re.split(r'(<p[^>]*>)', content)
    cleaned_paragraphs = []
    for i in range(0, len(paragraphs), 2):
        if i + 1 < len(paragraphs):  # 如果有对应的<p>标签
            cleaned_paragraphs.append(paragraphs[i])
            cleaned_paragraphs.append(paragraphs[i + 1].strip())
        else:
            cleaned_paragraphs.append(paragraphs[i].strip())
    
    content = ''.join(cleaned_paragraphs)
    
    return content

# 定义输入文件名
input_file = 'zhihu.json'

# 从文件中读取JSON数据
with open(input_file, 'r', encoding='utf-8') as file:
    json_data = file.read()

# 解析JSON数据
data = json.loads(json_data)

# 提取"data"数组中的内容
articles_data = data['data']

# 创建一个目录来保存HTML和PDF文件
output_dir = 'articles'
os.makedirs(output_dir, exist_ok=True)

# 初始化Jinja2环境
env = Environment(loader=FileSystemLoader('.'))
template = env.get_template('template.html')

# 遍历每一篇文章的数据
for article in articles_data:
    # 获取文章内容和标题
    article_id = str(article['id'])
    content = article['content']
    processed_content = process_content(content)
    title = article['title']
    
    # 渲染HTML模板
    html_content = template.render(title=title, content=processed_content)
    
    # 移除连续的 '>>',只保留一个 '>'
    html_content = re.sub(r'(>)>', r'\1', html_content)
    
    # 将内容写入HTML文件
    html_file_path = os.path.join(output_dir, f'{article_id}.html')
    with open(html_file_path, 'w', encoding='utf-8') as file:
        file.write(html_content)

print("所有文章已保存为HTML文件")

# 指定输入文件夹
input_dir = 'articles'

# 创建一个目录来保存 PDF 文件
output_dir = 'pdfs'
os.makedirs(output_dir, exist_ok=True)

# 遍历文件夹中的所有 HTML 文件
for filename in os.listdir(input_dir):
    if filename.endswith('.html'):
        # 获取 HTML 文件的完整路径
        html_file_path = os.path.join(input_dir, filename)
        
        # 构造 PDF 文件的名称
        pdf_filename = os.path.splitext(filename)[0] + '.pdf'
        pdf_file_path = os.path.join(output_dir, pdf_filename)
        
        # 读取 HTML 文件内容
        with open(html_file_path, 'r', encoding='utf-8') as file:
            html_content = file.read()
        
        # 将 HTML 文件转换为 PDF 文件
        try:
            # 使用 options 禁止加载远程资源
            options = {
                'disable-local-file-access': None,
                'load-error-handling': 'ignore',
            }
            # 注意html文件名不能含有中文
            pdfkit.from_string(html_content, pdf_file_path, options=options)
            print(f"{filename} 已转换为 {pdf_filename}")
        except Exception as e:
            print(f"转换 {filename} 时发生错误:{e}")

print("所有 HTML 文件已转换为 PDF 文件。")

运行结果

待完善的功能

  1. 本项目没有保存知乎文章中的图片,因为图片大小较难以控制;
  2. 知乎文章中的引用和脚注没能很好地处理。

以上问题有待解决。另外,这篇文章介绍了直接保存知乎网页文章的方法,值得参考。

相关推荐
好看资源平台1 小时前
网络爬虫——综合实战项目:多平台房源信息采集与分析系统
爬虫·python
进击的六角龙1 小时前
深入浅出:使用Python调用API实现智能天气预报
开发语言·python
檀越剑指大厂1 小时前
【Python系列】浅析 Python 中的字典更新与应用场景
开发语言·python
join81 小时前
解决vue-pdf的签章不显示问题
javascript·vue.js·pdf
湫ccc1 小时前
Python简介以及解释器安装(保姆级教学)
开发语言·python
小行星1252 小时前
前端把dom页面转为pdf文件下载和弹窗预览
前端·javascript·vue.js·pdf
孤独且没人爱的纸鹤2 小时前
【深度学习】:从人工神经网络的基础原理到循环神经网络的先进技术,跨越智能算法的关键发展阶段及其未来趋势,探索技术进步与应用挑战
人工智能·python·深度学习·机器学习·ai
羊小猪~~2 小时前
tensorflow案例7--数据增强与测试集, 训练集, 验证集的构建
人工智能·python·深度学习·机器学习·cnn·tensorflow·neo4j
lzhlizihang2 小时前
python如何使用spark操作hive
hive·python·spark
q0_0p2 小时前
牛客小白月赛105 (Python题解) A~E
python·牛客