百度文库爬虫(二)PPT下载

文章链接:https://blog.csdn.net/qq_43444349/article/details/105308086

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

写在最前

整个系列都已经上传github,可以去github看看呀

GitHub传送门(好用的话不妨给个star)BaiduWenkuSpider

觉得好用的话也可以收藏,点赞,关注博主啊

简介

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

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

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

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

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

系列文章

具体实现

问题分析

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

百度文库ppt文档截图

通过Chrome抓包工具检查元素

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

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

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

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

百度文库ppt文档截图XHR

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

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的获取在上一篇中已经提到,可以参考 百度文库爬虫(一)TXT

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

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

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

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

一些细节

  • 部分准备操作在上一篇中同样有所介绍
  • 在获取ppt图片的url后,需要转换其格式,命名以0.png,…,totalPageNum-1.png
  • 使用PIL库的Image将图片合并为title.pdf

需要下载的第三方库(博主的版本)

库名版本
requests2.19.1
PIL5.2.0
chardet3.0.4
bs44.6.3

⚠️一般来说,使用pip命令安装即可,关于PIL的安装请参考这篇python3 怎么安装 PIL

$ pip install requests
$ pip install Pillow
$ pip install chardet
$ pip install bs4

完整代码

from requests import get
from PIL import Image
from os import removedirs,remove,mkdir,getcwd
from os.path import join, exists
from requests.exceptions import ReadTimeout
from chardet import detect
from bs4 import BeautifulSoup
from re import findall
from json import loads
from time import time


class GetPpt:
    def __init__(self, url, savepath):
        self.url = url
        self.savepath = savepath if savepath != '' else getcwd()
        self.tempdirpath = self.makeDirForImageSave()
        self.pptsavepath = self.makeDirForPptSave()

        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 = 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.encoding =  detect(html.content).get("encoding")   #检测并修改html内容的编码方式


    # 获取文档基本信息:名字,类型,文档ID
    def getWkInfo(self):
        items = ["'title'","'docType'","'docId'","'totalPageNum"]
        for item in items:
            ls = 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 = get(url)
        jsonstr = response.text[response.text.find('(')+1: response.text.rfind(')')]  # 获取json格式数据
        return jsonstr


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


    # 创建临时文件夹保存图片
    def makeDirForImageSave(self):
        if not exists(join(self.savepath,'tempimages')):
            mkdir(join(self.savepath,'tempimages'))
        return join(self.savepath,'tempimages')

    # 创建临时文件夹保存ppt
    def makeDirForPptSave(self):
        if not exists(join(self.savepath,'pptfiles')):
            mkdir(join(self.savepath,'pptfiles'))
        return join(self.savepath,'pptfiles')


    # 从json文件中提取ppt图片的url
    def getImageUrlForPPT(self):
        timestamp = round(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):
        imagename = join(self.tempdirpath, imagename)
        with open(imagename,'wb') as ig:
            ig.write(get(imageurl).content)  #content属性为byte


    # 将获取的图片合成pdf文件
    def mergeImageToPDF(self, pages):
        if pages == 0:
            raise IOError


        namelist = [join(self.tempdirpath, 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 = join(self.pptsavepath, self.wkinfo.get('title')+'.pdf')
        firstimg.save(savepath, "PDF", resolution=100.0,
                      save_all=True, append_images=imglist)

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


    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/a5fc216dc9d376eeaeaad1f34693daef5ff7130b.html?from=search', '存储路径').getPPT()

测试

百度文库ppt文档截图测试

  • 6
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值