起因

上次想下载个文档,试了一圈百度文库下载器,结果都不能用了。

包括各种软件和浏览器插件、油猴插件,全都不行了。

无奈只能临时用复制的方法(选中内容,点击“翻译”)把内容拿到。

事后有空,索性看看能不能解析下载下来。

过程

先网上搜了一下,有开源的内容,也有分析的文章,试了两个也都不能用了,所以没细看。

直接上手,发现直接访问文章链接,网页内容直接就包括所有需要的东西了,包括文字和图片的链接。

其中图片链接不知道怎么解析的,看起来像是服务端把多张图片合并成了一张返回,前端再分割的。

文字内容是json格式返回的,网上搜了一下,有个传说中的bdjson,也就是百度自定义的json格式,也就是xreader(psp上的阅读软件)的格式,简单查了一下,没发现xreader转doc的方法,索性放弃直接转换,决定直接取文字内容算了,之后再把图片全部下载,手动调整格式。

可能很多时候只是想复制一点内容,却发现无法预览全文,测试发现,先清空文库的cookie,再从百度搜索界面跳转文档,就不限制全文预览了。

后来又发现一个接口,直接可以预览全文,可以复制,就是不能打印(只显示6页内容,其他部分空白)

https://wenku.baidu.com/share/文档ID?share_api=1

下载文字和图片的代码

import requests
import re, time, os, json


class Doc(object):
    """
    百度文库下载为TXT
    """
    def __init__(self, url):
        """
        传入地址
        """
        self.doc_id = re.findall('view/(.*).html', url)[0]
        self.s = requests.session()
        self.get_info()
        self.get_token()
        if not os.path.exists('下载'):
            os.mkdir('下载')

    @staticmethod
    def get_timestamp(long: int = 13):
        """
        取时间戳,默认13位
        """
        return str(time.time_ns())[:long]

    def get_info(self):
        """
        取文档名称/页数等基本信息
        """
        url = f'https://wenku.baidu.com/share/{self.doc_id}?share_api=1'
        try:
            html = self.s.get(url).content.decode('GBK')
            self.title = re.search(r"title'   : '([\s\S]*?)',", html).group(1)
            pages = re.search(r"totalPageNum' : '([\s\S]*?)',", html).group(1)
            self.pages = int(pages)
            self.type = re.search(r"docType' : '(.*?)',", html).group(1)
            htmlURLs = re.search(r"htmlUrls: '([\s\S]*?)',", html).group(1).replace('\\\\', '')
            htmlURLs = htmlURLs.encode('latin1').decode('unicode_escape')
            self.urls = json.loads(htmlURLs)
        except:
            print('获取文档基本信息失败,运行结束。')
            os._exit()

    def get_token(self):
        """
        取Token,短期(小时级)有效
        """
        url = 'https://wenku.baidu.com/api/interface/gettoken?host=wenku.baidu.com&secretKey=6f614cb00c6b6821e3cdc85ab1f8f907'
        try:
            res = self.s.get(url).json()
            self.token = res['data']['token']
        except:
            print('获取token失败,运行结束。')
            os._exit()

    def download_pic(self):
        """
        下载所有图片
        """
        pics = self.urls['png']
        for pic in pics:
            content = self.s.get(pic['pageLoadUrl']).content
            with open(f'下载/{self.title}_{pic["pageIndex"]}.png', 'wb') as f:
                f.write(content)

    def download(self):
        """
        下载文字
        """
        self.download_pic()
        print(self.token, self.title, self.pages, self.type)
        result = ''
        url = 'https://wenku.baidu.com/api/interface/getcontent'
        for page in range(1, self.pages + 1):
            params = {
                "doc_id": self.doc_id,
                "pn": page,
                "t": "json",
                "v": "6",
                "host": "wenku.baidu.com",
                "token": self.token,
                "type": "xreader"
            }
            res = self.s.get(url, params=params).json()
            lst = res['data']['1']['body']
            for index in range(len(lst)):
                if lst[index]['t'] == 'word':
                    text = lst[index]['c']
                    if text == ' ' and index < len(lst) - 1:
                        if lst[index]['p']['y'] < lst[index + 1]['p']['y']:
                            text = '\n'
                        else:
                            text = ' '
                    result += text
                elif lst[index]['t'] == 'pic':
                    pass
        with open(f'下载/{self.title}.txt', 'w', encoding='utf-8') as f:
            f.write(result)
        print('完成')

    def download2(self):
        """
        下载文字
        """
        self.download_pic()
        print(self.token, self.title, self.pages, self.type)
        result = ''
        pages = self.urls['json']
        for page in pages:
            res = self.s.get(page['pageLoadUrl']).text
            res = res[8:-1]
            res = json.loads(res)
            lst = res['body']
            for index in range(len(lst)):
                if lst[index]['t'] == 'word':
                    text = lst[index]['c']
                    if text == ' ' and index < len(lst) - 1:
                        if lst[index]['p']['y'] < lst[index + 1]['p']['y']:
                            text = '\n'
                        else:
                            text = ' '
                    result += text
                elif lst[index]['t'] == 'pic':
                    pass
        with open(f'下载/{self.title}.txt', 'w', encoding='utf-8') as f:
            f.write(result)
        print('完成')


if __name__ == "__main__":

    # url = 'https://wenku.baidu.com/view/81bbd69a541810a6f524ccbff121dd36a22dc477.html'
    url = 'https://wenku.baidu.com/view/c145899e6294dd88d1d26b0e.html'
    doc = Doc(url)
    doc.download()
    # doc.download2()
03-05 23:32