文章目录
- 写在前面
- 具体思路
- 代码
- 后记
- 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="(.*?)".*?/>')