0%

Baidu文库爬取/百度文库爬虫(二)PPT

由于ppt文档的下载是系列下载中相对简单的部分,故放在整个系列的第二篇

其他文章:百度文库爬虫(一)TXTTXT/)

简介

本项目是基于python实现对百度文库可预览文档的下载,实现了对以下文档格式的下载:

  • doc/docx
  • ppt/pptx
  • xls/xlsx
  • pdf
  • txt

⚠️本项目下载的文档均为pdf格式(除txt外)

⚠️项目是本人原创,转载请注明出处

⚠️项目是本人课程设计的作品,请勿用于商业用途

具体实现

问题分析

在百度文库随意搜索一篇ppt文档,如下图:

百度文库ppt文档截图

通过Chrome抓包工具检查元素

百度文库ppt文档截图检查元素

很容易发现百度文库对于ppt文档的展示都是图片形式的,并且图片的url格式与图中框出部分相似

因此进入Network栏分析XHR,寻找这个url

经过一番寻找后锁定了目标:

百度文库ppt文档截图XHR

打开网页后发现内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
jQuery1101019156975490160288_1585929110855({
"list": [{
"zoom": "https:\/\/wkretype.bdimg.com\/retype\/zoom\/4c637aa602d276a200292e72?pn=1&o=jpg_6&md5sum=61929db3a5e7a524aafe6ef092c86a90&sign=f6a4c4f0fd&png=0-242&jpg=0-24297",
"page": 1},
...
{
"zoom": "https:\/\/wkretype.bdimg.com\/retype\/zoom\/4c637aa602d276a200292e72?pn=193&o=jpg_6&md5sum=61929db3a5e7a524aafe6ef092c86a90&sign=f6a4c4f0fd&png=4225171-&jpg=31725863-",
"page": 193
}],
"count": "193",
"free": "193"
})

很明显,该网页存储的json数据就包含我们需要的ppt图片的url

构造网页url并抓取相应内容

主要问题就变成了构造上述url并获取其中信息

分析上述网页的url可以发现,url主要分为两部分

  • https://wenku.baidu.com/browse/getbcsurl?

  • doc_id=395f376fb42acfc789eb172ded630b1c58ee9b59&pn=1&rn=99999&type=ppt&callback=jQuery1101019156975490160288_1585929110855&_=1585929110856

分析一下url的构成

  • 关于doc_id的获取在上一篇中已经提到,可以参考 百度文库爬虫(一)TXTTXT/)

  • 对其他ppt文档进行相同的分析后发现,pnrn可以维持不变

  • type显然对应文档分类,也不需要改变

  • 至于callback=jQuery1101019156975490160288这一部分并没有分析出实际作用,但是,测试之后发现对于不同ppt文档,使用与相同的jQuery...即可,故随意找到一个ppt文档获取其值即可

  • 15859291108551585929110856在上一篇中也提到,是毫秒级时间戳,需要注意,两者之间有一定间隔,构造时对时间戳+1即可

一些细节

  • 部分准备操作在上一篇中同样有所介绍

  • 在获取ppt图片的url后,需要转换其格式,命名以0.png,…,totalPageNum-1.png

  • 使用PIL库的Image将图片合并为title.pdf

完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
import requests
from PIL import Image
import os
from requests.exceptions import ReadTimeout
import chardet
from bs4 import BeautifulSoup
import re
import json
import time


class GetPpt:
def __init__(self, url, savepath):
self.url = url
self.savepath = savepath if savepath != '' else os.getcwd()
self.html = ''
self.wkinfo ={} # 存储文档基本信息:title、docType、docID
self.ppturls = [] # 顺序存储包含ppt图片的url

self.getHtml()
self.getWkInfo()

# 获取网站源代码
def getHtml(self):
try:
header = {'User-Agent': 'Mozilla/5.0 '
'(Macintosh; Intel Mac OS X 10_14_6) '
'AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/78.0.3904.108 Safari/537.36'}
response = requests.get(self.url, headers = header)
self.transfromEncoding(response)
self.html = BeautifulSoup(response.text, 'html.parser') #格式化
except ReadTimeout as e:
print(e)
return None

# 转换网页源代码为对应编码格式
def transfromEncoding(self,html):
#检测并修改html内容的编码方式
html.encoding = chardet.detect(html.content).get("encoding")

# 获取文档基本信息:名字,类型,文档ID
def getWkInfo(self):
items = ["'title'","'docType'","'docId'","'totalPageNum"]
for item in items:
ls = re.findall(item+".*'", str(self.html))
if len(ls) != 0:
message = ls[0].split(':')
self.wkinfo[eval(message[0])] = eval(message[1])

# 获取json字符串
def getJson(self, url):
"""
:param url: json文件所在页面的url
:return: json格式字符串
"""
response = requests.get(url)
jsonstr=response.text[response.text.find('(')+1: response.text.rfind(')')]
return jsonstr

# 获取json字符串对应的字典
def convertJsonToDict(self, jsonstr):
"""
:param jsonstr: json格式字符串
:return: json字符串所对应的python字典
"""
textdict = json.loads(jsonstr) # 将json字符串转换为python的字典对象
return textdict

# 从json文件中提取ppt图片的url
def getImageUrlForPPT(self):
timestamp = round(time.time()*1000) # 获取时间戳
desturl = "https://wenku.baidu.com/browse/getbcsurl?doc_id="+\
self.wkinfo.get("docId")+\
"&pn=1&rn=99999&type=ppt&callback=jQuery1101000870141751143283_"+\
str(timestamp) + "&_=" + str(timestamp+1)

textdict = self.convertJsonToDict(self.getJson(desturl))
self.ppturls = [x.get('zoom') for x in textdict.get('list')]

# 通过给定的图像url及名称保存图像
def getImage(self, imagename, imageurl):
# print(imageurl)
with open(imagename,'wb') as ig:
ig.write(requests.get(imageurl).content) #content属性为byte

# 将获取的图片合成pdf文件
def mergeImageToPDF(self, pages):
# TODO:需要自定义异常类型,处理合并时图片不存在的情况
if pages == 0:
raise IOError

namelist = [str(x)+'.png' for x in range(pages)]
firstimg = Image.open(namelist[0])
imglist = []
for imgname in namelist[1:]:
img = Image.open(imgname)
img.load()

if img.mode == 'RGBA': # png图片的转为RGB mode,否则保存时会引发异常
img.mode = 'RGB'
imglist.append(img)

savepath = self.savepath+'/'+self.wkinfo.get('title')+'.pdf'
firstimg.save(savepath, "PDF", resolution=100.0,
save_all=True, append_images=imglist)

# 清除下载的图片
def removeImage(self, pages):
namelist = [str(x) + '.png' for x in range(pages)]
for name in namelist:
if os.path.exists(name):
os.remove(name)

def getPPT(self):
self.getImageUrlForPPT()
for page, url in enumerate(self.ppturls):
self.getImage(str(page)+'.png', url)
self.mergeImageToPDF(len(self.ppturls))
self.removeImage(len(self.ppturls))


if __name__ == '__main__':
GetPpt('https://wenku.baidu.com/view/6e6b9f397cd184254b3535b6.html?from=search', '存储路径').getPPT()

测试

百度文库ppt文档截图测试

以上,完成了对百度文库PPT文档的下载