0
点赞
收藏
分享

微信扫一扫

python爬取知乎页面的LaTeX公式


文章目录

  • ​​写在前面​​
  • ​​具体思路​​
  • ​​代码​​
  • ​​后记​​
  • ​​2021.01.20更新​​
  • ​​2022.4.10更新​​

写在前面

最近看到知乎有个大佬总结了一百多道不定积分的题目(网址请见​​知乎专栏:不定积分王者100题​​),看着有点兴趣,于是决定挑战一下(真的难)。但是一道一道打(LaTeX)公式有点浪费时间,于是想着用以前学过的python爬虫解析网页,并存储为markdown文件(数学公式搭配Typora简直是绝配),下面请看具体操作。

具体思路

首先想的是用​​requests​​​抓整个网页,再用​​re​​​库配合正则表达式解析公式,点审查元素(或​​F12​​​一键解决),就可以发现整个网页的结构其实非常简单,就是仅有两个​​<ol></ol>​​​标签对,里面包含了所有的公式,内部使用了​​<li></li>​​标签,其中一段如下:

<img src="https://www.zhihu.com/equation?tex=%5Cint%7B%5Cfrac%7B1%2Bx%5E2%7D%7B1%2Bx%5E4%7D%7D%5Ctext%7Bd%7Dx+" alt="[公式]" eeimg="1" data-formula="\int{\frac{1+x^2}{1+x^4}}\text{d}x ">

不过,当我真正开始写正则的时候,发现使用​​data-formula="()"​​​查找的时候返回为空!?后来输出整个网页才发现应该使用​​alt="()"​​​,而不是​​data-formula="()"​​,可能是网页后台的解析什么的,小问题。

之后就是一些细节上的实现了,比如使用上下文管理语句​​with​​​进行文件的保存,还有加上序号和​​$$​​符号(数学环境),剩下的请看代码啦~~

P.S. 下面的代码我用的是最近学的Xpath语句,使用起来更加方便(直接复制粘贴无压力),根据王爷的列表改一下序号啥的就能定位网页元素了。

代码

import requests
import re
from lxml import etree


url = "https://zhuanlan.zhihu.com/p/99341070"

def get_html(url):
#设置请求头,否则无法获取网页内容
headers = {"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36 Edg/86.0.622.51"}
r = requests.get(url, headers=headers)
r.encoding = "utf-8"
return r.text

def parse_items(raw_html):
#使用xpath解析网页内容
html = etree.HTML(raw_html)
# 需要注意这里定位到的元素是一个包含字符串的列表,所以下面需要取第一个元素('[0]')
result1 = [html.xpath('//*[@id="root"]/div/main/div/article/div[1]/div/ol[1]/li[%s]/img//@alt'
%(i))[0] for i in range(1,35)]
result2 = [html.xpath('//*[@id="root"]/div/main/div/article/div[1]/div/ol[2]/li[%s]/img//@alt'
%(j))[0] for j in range(1,101)]
# 将两个列表连起来
result = result1+result2
# 使用re库进行解析,具体结果类似Xpath结果
# regex = re.compile(r'<li><img.*?alt="(.*?)".*?</li>')
# result = re.findall(regex,raw_html)
return result

if __name__ == '__main__':
html = get_html(url)
# print(html)
items = parse_items(html)
# print(items)
# 用于计数
num = 0
# 存文件
with open("formula.md", 'w') as f:
for i,item in zip(range(1,135),items):
print(item)
# 使输出符合markdown的语法,便于直接显示公式
f.write("%d. $$\n "%(i)+item+"\n $$\n\n")
num+=1
print("已写入%d条公式"%(num))

后记

有兴趣的小伙伴可以试试,顺便练练手,这个例子还是不难实现的。

不过美中不足的一点是:​​Typora​​​在完美显示前99条公式之后突然不能以公式形式显示后面的式子了,但是在​​VScode​​中可以全部正常显示,感觉这个是Typora的问题,希望朋友们尝试过之后告诉我一下,看看是哪里出了问题,欢迎大家学习交流!

2020.12.4更新,最近学到了一个新函数​​enumerate()​​,用于生成可迭代的索引(值对),所以最后面生成索引的那个循环就可以简单一些了。更新后的部分代码如下(只改动了添加索引部分):

# 用于计数
num = 0
# 存文件
with open("formula.md", 'w') as f:
for i,item in enumerate(items):
print(item)
# 使输出符合markdown的语法,便于直接显示公式
f.write("%d. $$\n "%(i + 1)+item+"\n $$\n\n")
num+=1
print("已写入%d条公式"%(num))

2021.01.20更新

我发现Typora的这个bug了,就是有序列表不能是三位数,否则渲染会出问题,当我把代码倒数第三行的i+1改成1就可以在Typora中正确显示公式啦。

2022.4.10更新

突然发现知乎网页结构有变化, 这里重写一下正则表达式,就可以爬取了:

= re.compile(r'<li.*?>.*?<img.*?alt="(.*?)".*?/>')


举报

相关推荐

0 条评论