吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 902|回复: 4
收起左侧

[经验求助] Python下载保存html文件时数学公式的显示问题

[复制链接]
bin_chb 发表于 2023-9-21 20:16
30吾爱币
本帖最后由 bin_chb 于 2023-9-21 23:14 编辑

以下代码是下载某专栏的文章,但是知乎中的数学公式无法正常显示,请问如何能正常显示数学公式
参考:https://blog.csdn.net/weixin_44283855/article/details/124123375
[Python] 纯文本查看 复制代码
import time
import re
import os,sys
import requests
from bs4 import BeautifulSoup
from pathlib import Path 
import pdfkit

def get_list():
    url = 'https://www.zhihu.com/api/v4/columns/%s/articles?include=data.topics&limit=10' % author
    article_dict = {}
    while True:
        print('fetching', url)
        try:
            resp = requests.get(url, headers=headers)
            j = resp.json()
            data = j['data']
        except:
            print('get list failed')

        for article in data:
            aid = article['id']
            akeys = article_dict.keys()
            if aid not in akeys:
                article_dict[aid] = article['title']

        if j['paging']['is_end']:
            break
        url = j['paging']['next']
        time.sleep(2)

    with open(filedir.joinpath('zhihu_ids.txt'), 'w') as f:
        items = sorted(article_dict.items())
        for item in items:
            f.write('%s %s\n' % item)
def get_html(aid, title, index,encoding='UTF-8'):
    title = re.sub('[\/:*?"<>|]', '-', title)  # 正则过滤非法文件字符
    print(title)
    file_name = '%03d. %s.html' % (index, title)
    file_name=file_name.replace(" ","").strip()
    # file_name=[strings.replace(i, "") for i in special_characters]
    # 删除字符串中的特殊字符

    print('saving', title)
    try:
        url = 'https://zhuanlan.zhihu.com/p/' + aid
        res= requests.get(url, headers=headers)
        encoding=res.encoding
        html =res.text
        # soup = BeautifulSoup(html, 'lxml')
        soup = BeautifulSoup(html, 'html.parser')
        content = soup.find(class_='Post-RichText').prettify()
        content = content.replace('data-actual', '')
        content = content.replace('h1>', 'h2>')
        content = re.sub(r'<noscript>.*?</noscript>', '', content)
        content = re.sub(r'src="data:image.*?"', '', content)
        # content = f'<!DOCTYPE html><html><head><meta charset={encoding}></head><body><h1>{title}</h1>{content}</body></html>'
        strmath = '<script type="text/javascript" async src="https://cdn.staticfile.org/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML" ></script>' #解析数学公式
        
        content1 = f'<!DOCTYPE html><html><head><meta charset={encoding}></head><body><h1>{title}</h1>{content}{strmath}</body></html>' 
        str1 = """
    <style>
      body {
        margin: 0 50px;
      }
    
      p {
        text-indent: 2em;
      } # 文字首行缩进2em
    
      img {
        width: 100%;
      } # 图片显示中间 不超出
      pre {
        white-space: pre-wrap;
        word-wrap: break-word;
      } # 代码段自动换行
      .ztext-math {
        display: inline-block;
      }
    </style>
    """
        content2 = content1 +  str1
        
        with open(filedir.joinpath(file_name), 'w', encoding='utf-8') as f:
            f.write(content2)
    except:
        print('get %s failed', title)
    time.sleep(2)

def get_details():
    with open(filedir.joinpath('zhihu_ids.txt')) as f:
        i = 1
        for line in f:
            lst = line.strip().split(' ')
            aid = lst[0]
            title = '_'.join(lst[1:])
            get_html(aid, title, i)
            i += 1

def to_pdf():
    '''
    如需导出pdf,除通过pip安装pdfkit外,还需要手动安装 wkhtmltopdf,具体参见:
    [url=https://github.com/JazzCore/python-pdfkit/wiki/Installing-wkhtmltopdf]https://github.com/JazzCore/pyth ... talling-wkhtmltopdf[/url]
    [url=https://wkhtmltopdf.org/downloads.html]https://wkhtmltopdf.org/downloads.html[/url]
    '''
    print('exporting PDF...')
    htmls = []
    htmls += [name.name for name in Path.iterdir(filedir) if name.suffix==".html"]
    path_wk = r"E:\Software\wkhtmltopdf\bin\wkhtmltopdf.exe"
    # htmls.remove('index.html')
    config = pdfkit.configuration(wkhtmltopdf = path_wk)
    path_wk = r"E:\Software\wkhtmltopdf\bin\wkhtmltopdf.exe"
    config = pdfkit.configuration(wkhtmltopdf = path_wk)
    options = {
            'encoding': "utf-8",
            # 'page-size': 'A4',
            'orientation': 'Portrait',#'Landscape',#'Portrait',#横屏竖屏
            # 'margin-top': '2mm',
            # 'margin-right': '2mm',
            # 'margin-bottom': '2mm',
            # 'margin-left': '2mm',
            # 'no-outline': None,
            # 'background': background_color,
            # 'quiet':'' #默认情况下, PDFKit 将会显示所有的wkhtmltopdf输出. 如果你不想看到这些信息,需要传递一个quiet选项
       
       'enable-local-file-access': '--enable-local-file-access',
        'enable-internal-links': '--enable-internal-links',
        'enable-javascript':'--enable-javascript',
        # 'javascript - delay' :'--javascript - delay < 300 >',
        'javascript-delay':'10000',
        'no-stop-slow-scripts':'--no-stop-slow-scripts',
        'debug-javascript':'--debug-javascript',
        'enable-forms':'--enable-forms',
        'disable-smart-shrinking':'--disable-smart-shrinking'
       }
    htmls_dir=[filedir.joinpath(name) for name in sorted(htmls)]
    pdfkit.from_file(htmls_dir, dir_path+"\\"+author + '.pdf',options=options,configuration=config)
    print('Done')
if __name__ == '__main__':
    dir_path=r'E:\Brandon\Desktop\zhihu'
    author = 'c_1322265113534304256'

            
    filedir=Path(dir_path).joinpath(author)
    filedir.mkdir(parents=True,exist_ok=True) # 创建文件夹

    headers = {
        'origin': 'https://zhuanlan.zhihu.com',
        'referer': 'https://zhuanlan.zhihu.com/%s' % author,
        'User-Agent': ('Mozilla/5.0'),
    }
    get_list()
    get_details()
#to_pdf()

最佳答案

查看完整内容

[md]在那些 `re.sub` 方法后面再插入以下代码。 ```python # 在这里开始替换,其类似如下格式,关键在于 T 部分 # T content = re.sub(r'data-tex="(.*?)">\s+\1\s+

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

LoveCode 发表于 2023-9-21 20:16

在那些 re.sub 方法后面再插入以下代码。

# 在这里开始替换,其类似如下格式,关键在于 T 部分
# <span class="ztext-math" data-eeimg="1" data-tex="T">T</span>
content = re.sub(r'data-tex="(.*?)">\s+\1\s+<', r">\(\1\)<",  content)

我测试了,下载的 HTML 可以正常渲染数学表达式,那么生成 PDF 应该也没问题(这个没有测试)。

现在不能上传图片,网站显示错误: “不支持的类型”,如果明天可以的话我再详细说明一下。

如果你感到疑惑,可以去看一下 MathJax 的官网如,里面提到了插入 LaTex 表达式时应该使用 $$ 或者 \(\)

LoveCode 发表于 2023-9-22 00:20

额,我发现无法上传图片是因为只能上传 .txt 文件。
那我还是详细用文字说明思考过程吧。

猜测

我先阅读了你所给出的 csdn 博客,其中关于数学表达式的显示,原作者是在下载的 HTML 中插入了外部的渲染数学表达式的 js

既然你提到了数学表达式的渲染问题,我猜测是这个 js 文件导入失败了。另外,只要下载的 HTML 显示正常,那么生成的 PDF 大概也是正常的。

试探

我运行了你的代码,成功下载了几个 HTML 文件(此时还没有生成 PDF),数学表达式没有渲染出来。

(此处省略展示数学表达式渲染失败的图片。)

现在我有几个猜测:

  1. 使用的 mathjax.js 不对
  2. 那个数学表达式不对。不过我只知道 Tex 这个名字,其它都不懂。

为了验证第 1 个猜想,我从 MathJax 官网扒下来一个例子,然后用 python 源码中的 mathjax.js 测试,显示正确,说明这个 js 没有问题。

(此处省略图片。)

为了验证第二个猜想,我把爬取下来的网页中的数学表达式放到一个 Tex 测试网站上测试,结果是正确的!

现在 mathjax.js 文件正确,数学表达式正确,但就是没有渲染出来。最后猜测是 mathjax.js 的问题,因为它够复杂,所以仔细阅读了官方文档,才确定问题所在。

The default math delimiters are

$$...$$
and [...] for displayed mathematics, and (...) for in-line mathematics. Note in particular that the $...$ in-line delimiters are not used by default.

所以在下载来的 HTML 源码中应该找到所有的数学表达式,然后给它们添加对应的前缀和后缀即可。
只要爬取下来的 HTML 可以正常显示,生成的 PDF 也就正常了。


修改 Python 源码

现在的问题就是给所有的 Tex 表达式添加前后缀了,经过分析,发现它们的规律:

  1. 它们都在 class 为特定值的 span 中。
  2. data-tex 属性的值和 span 标签的文本一样,都是要显示的 Tex 表达式。

所以可以使用正则来替换(具体见最回复提到的代码)。

<span class="ztext-math" data-eeimg="1" 
            data-tex="\sum_{i=1}^{n}X_{i}\sim N(n\mu,n\sigma^{2}) \\">
            \sum_{i=1}^{n}X_{i}\simN(n\mu,n\sigma^{2}) \\
</span>

最终我决定添加 \(..\) 促成行内形式,而不是 $$ 独占一行,因为我也无法区分哪些表达式应该是行内还是独占一行显示。

免费评分

参与人数 1吾爱币 +2 热心值 +1 收起 理由
bin_chb + 2 + 1 谢谢@Thanks!

查看全部评分

LoveCode 发表于 2023-9-22 00:26
额,从  MathJax 官网复制的文本被当作 markdown 处理了,具体还是看这里的文档:https://docs.mathjax.org/en/latest/basic/mathematics.html。

免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
bin_chb + 1 + 1 谢谢@Thanks!

查看全部评分

 楼主| bin_chb 发表于 2023-9-22 09:09
LoveCode 发表于 2023-9-21 20:16
[md]在那些 `re.sub` 方法后面再插入以下代码。

```python

感谢回复了这么多
返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2026-6-15 11:30

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表