由于txt文档的下载是系列下载中最简单的部分,故放在整个系列的第一篇
简介 本项目是基于python实现对百度文库可预览文档的下载,实现了对以下文档格式的下载:
doc/docx
ppt/pptx
xls/xlsx
pdf
txt
⚠️本项目下载的文档均为pdf格式(除txt外)
⚠️项目是本人原创,转载请注明出处
⚠️项目是本人课程设计的作品,请勿用于商业用途
具体实现 问题分析 在百度文库随意搜索一篇txt文档,如下图:
发现下载该文档需要使用下载卷,事实上,大多数百度文库的文档均是以支付下载卷的形式下载
当然,不排除开通VIP的用户(土豪)直接下载
抓取网页信息 通过使用Chrome浏览器自带的网页抓包工具对网页进行分析(在网站上,按下F12)
关于Chrome抓包分析,可以参考这篇文章:
Google Chrome抓包分析详解
在Network页面勾选Preserve log选项以记录网站记录,而后刷新网页
在JS界面可以找到如下网址
打开该网址后可以发现其中内容如下:
1 cb([{"parags":[{"c":"\u673a\u5668\u6570\uff1a\u4e00\u4e2a\u6570\u503c\u5728\u8ba1\u7b97\u673a\u4e2d\u4e8c\u8fdb\u5236\u8868\u793a\u5f62\u5f0f\u3002\r\n\r\n\u5fae\u7a0b\u5e8f:\u7531\u5fae\u6307\u4ee4\u5e8f\u5217\u7ec4\u6210\u7684\u7a0b\u5e8f\u3002\r\n\r\n\u52a8\u6001\u5fae\u7a0b\u5e8f\u8bbe\u8ba1\uff1a\u901a\u8fc7\u6539\u53d8\u5fae\u6307\u4ee4\u548c...
显然这是unicode字符,找一在线网站将其转换一下可得到如下内容:
1 机器数:一个数值在计算机中二进制表示形式。\r\n\r\n微程序:由微指令序列组成的程序。\r\n\r\n动态微程序设计:通过改变微指令和
经过比较可以发现这正是txt文件的内容,事实上,该网址中的数据即为文档内容的json数据
构造网页url并抓取相应内容 分析上述网页的url可以发现
主要分为两部分
显然,需要找到url中的信息
首先在网页源代码中进行搜索df3abfc36137ee06eff9183f
发现
1 'docId': 'df3abfc36137ee06eff9183f' // 文档格式
而对于md5sum等信息的搜索无结果,显然,这种信息一般由网页动态生成的,因此继续进行抓包分析
在XHR中发现了如下信息:
打开网页后果然找到了需要的信息的json格式,使用sublime
格式化json数据得:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 cb({ "doc_id": "df3abfc36137ee06eff9183f", "smallFlowProfessionalDoc": 1, "smallFlowContent": { "isBaiduWiseGuideSmallFlow": 0, "isBaiduWiseGuideValid": 0, "isBaiduWiseGuideVipSmallFlow": 0, "isBaiduWiseGuideVipValid": 0 }, ... "md5sum": "&md5sum=4b7be23adc08726ded99bc39f6a6d76b&sign=c180630292", "bcsParam": false, "rsign": "p_5-r_0-s_b2eb2", "downloadToken": "ba13d4912584b799e78b8bbbff158de5", "matchStatus": 1, "seoTitle": "\u8ba1\u7b97\u673a\u7ec4\u6210\u540d\u8bcd\u89e3\u91ca" })
因此,转而构造https://wenku.baidu.com/api/doc/getdocinfo?callback=cb& doc_id=df3abfc36137ee06eff9183f&t=1585882305929&_=1585882305806
获取相应信息
很明显,只需要doc_id
以及t
与_
即可
doc_id
上面已经提到可在网页源代码中直接获取,故使用爬虫直接爬取源代码并提取即可
t
与_
不难看出是与时间相关的属性,简单测试即可发现这是时间戳,而在python中提供了获取时间戳的 time.time()
函数,值得注意的是该时间戳为秒级时间戳,需要转换成毫秒级
一些细节
对于requests
的应用为常规的get
操作
在进行后续操作前需要对网页源代码进行爬取,以获取文档信息,如:
title、docType、docID、totalPageNum
在获取网页的json
数据后,获取(
和 )
之前的内容,将json字符串转换为python的字典类型,便于管理
将数据中的文本内容,即键值为"c"
的内容,以追加写方式写入title.txt中
完整代码 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 from requests import getfrom requests.exceptions import ReadTimeoutfrom chardet import detectfrom bs4 import BeautifulSoupfrom os import getcwdfrom re import findallfrom json import loadsfrom time import timeclass GetTxt : def __init__ (self, url, savepath) : self.url = url self.savepath = savepath if savepath != '' else getcwd() self.html = '' self.wkinfo = {} self.txturls = [] 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" ) 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 ]) def getJson (self, url) : """ :param url: json文件所在页面的url :return: json格式字符串 """ response = get(url) jsonstr=response.text[response.text.find('(' ) + 1 :response.text.rfind(')' )] return jsonstr def convertJsonToDict (self, jsonstr) : """ :param: jsonstr: json格式字符串 :return: json字符串所对应的python字典 """ textdict = loads(jsonstr) return textdict def getTxtUrlForTXT (self) : timestamp = round(time() * 1000 ) messageurlprefix = "https://wenku.baidu.com/api/doc/getdocinfo?" \ "callback=cb&doc_id=" messageurlsuffix = self.wkinfo.get("docId" ) + "&t=" + \ str(timestamp) + "&_=" + str(timestamp + 1 ) textdict = self.convertJsonToDict( self.getJson(messageurlprefix + messageurlsuffix)) self.txturls.append("https://wkretype.bdimg.com/retype/text/" + self.wkinfo.get('docId' ) + textdict.get('md5sum' ) + "&callback=cb&pn=1&rn=" + textdict.get("docInfo" ).get("totalPageNum" ) + "&rsign=" + textdict.get("rsign" ) + "&_=" + str(timestamp)) def saveToTxt (self, content) : savepath = self.savepath + '/' + self.wkinfo.get('title' ) + '.txt' with open(savepath, "a" ) as f: f.write(content) def getTXT (self) : self.getTxtUrlForTXT() for url in self.txturls: textls = self.convertJsonToDict(self.getJson(url)) for text in textls: content = text.get("parags" )[0 ].get("c" ) self.saveToTxt(content) if __name__ == '__main__' : GetTxt('https://wenku.baidu.com/view/df3abfc36137ee06eff9183f.html?from=search' , '存储' ).getTXT()
测试 对上述网站运行程序后得到正确txt文件
通过以上分析,就完成了对百度文库txt文档的爬取