Python | 纸媒不死!

如果程序员喜欢读报纸,那将会是……

·前言

我是一个不太像是这个时代和这个年纪的年轻人,喜欢盘串儿,不刷抖音,还偏偏喜欢看报纸。我原本也是喜欢在微博上看新闻的,但经历过一些大反转的事件之后,我愈发觉得新媒体不太靠谱了。后来我便寻找更靠谱的新媒体,但即使是澎湃新闻这样的媒体也偶尔会出现问题,人民日报的官博也闹过几次乌龙。所以我还是决定,回归纸媒,诚如标题所言,纸媒不死,他们才是新闻界的最后底线。

·人民日报

这份报纸之于中国的意义不言自明了吧,不过我这篇文章大小也算是个技术帖,主要还是讲怎么获取PDF版的报纸。

人民日报的官网还是很贴心的,提供PDF下载的按钮,只不过每次都只能下载一版,那我们就直接写个函数,批量下载再合成一下就好。

整体思路不难,按照关键字检索一下今天一共多少版,然后根据官方链接进行一下日期格式化,然后遍历下载,最后进行一下合并即可。

别着急,这才是刚刚开始,也不是每家媒体都像人民日报一样这么善良。

·北京青年报

坦白讲,本来是想搞中青报的,毕竟之前关注了好久曹林老师在中青报的时评,很是喜欢。只可惜研究了好久,发现中青报根本没有下载PDF的可能,只能退而求其次,搞一搞北青报,毕竟我还是个青年。

北青报也很贴心的给了每个版面的下载链接,只不过相比人民日报,北青报多了A/B/C/D叠,这无疑增加了一点障碍,只能采取更暴力的关键字检索了。

代码逻辑整体上基本与人民日报相似,但一定要注意一点,北青报会偶发某个版面丢失的情况,没有人民日报那么稳定,所以一定要考虑到这个问题。

看到这你是不是已经开始不懈了,心想着我一个白嫖党,还搞一些这么简单的报纸。我也是这么看不起自己,所以我决心搞个大的,身为球迷,足球报陪伴了我整个成长的历程,那就决定是他了。

·足球报

足球报就不太能白嫖了,好在价格也没有死贵,70一年订阅,果断下手了。

这时候才发现,足球报的电子版是一张张高清IPG,根本不是PDF!

好在图片清晰度还真可以,我便有了将图片转pdf的思路,继续搞下去。

这时候技术难点就出现了,讲道理,这时候应该是找到所有图片的下载链接才对,但找了一圈没找到,我确定,他一定是把链接的明文给加密了。

最后我锁定到了这串「乱码」上,能够肯定下载链接就是来自这。那下一步就是寻找解密方法,通过发起程序的调用链,我找到了LoadingJS.js这个文件,定位到了bingo_decode(data, inkey)这个函数上。

但神奇的是,我找不到这个函数体???最后真的没辙了,只能通过设断点的方式寻求帮助了。通过断点,我发现这个函数体是写在了config.js的文件中

解密函数不难,比较基础的语法,改写成python也就十行。可这时候出现了另一个问题,解密是需要密钥的,密钥哪来的啊?

通过断点,能看到密钥在这个时候已经请求到了,于是乎我就不断递归,但一直没能递归到源头,搞得我头都大了。之后我又翻了好几遍请求连接,里边都没有出现这个inkey。

但就在某一瞬间,灵感突至,果不其然,inkey就在这。

嗯,直接写在html中,没用接口,没用cookie,没用变量,我******

其他的点就都很简单了,很常规的做法,模拟请求而已。

最后再根据网上的教程,将JPG转为PDF,再进行下合并,大功告成。

再说一句,请求的时候是要cookie的,不要想白嫖了,支持下纸媒吧。

·体坛周刊

足球报难吗?没事,更难的来了,体坛周刊带你上到更高的难度。

我对体坛周刊倒是无感,毕竟足球版面也没有很多,但考虑到明年的冬奥会,也算是个体育大年,还是很有必要的。

另外说一句,体坛周刊也不要指望白嫖,但可以投机取巧。官网100/年的订阅价格贵了,可以去到官方淘宝店,然后买一本欧战指南,88元赠送一年订阅,这价格也可以接受了吧,毕竟体坛周报也算是有头有脸的媒体之一呢。

买完会员,就可以开始搞事情了。一开始我以为,体坛周刊是最良心的那个(后来脸被打的生疼),每一期都是一个PDF,多完美的结局啊,付费就完了。

现实告诉我是我唐突了,这PDF是加密的。其实加密也没啥嘛,找到密钥不就结了吗?这次我学精了,有了足球报的经验,我先开始读html的源码。果不其然,这俩货一个套路,也是直接写在了html中。webViewerLoad(‘https://resource.ttplus.cn/publish/app/newspaper/2021/12/10/403636/6dae8b93-92a4-428d-bb95-f741c2873bd1.pdf’, ‘3YLLX/0Pt3YHYVeLb9dFiKBbiU8stTI8zw6Bo0H+fYOAelOLKqBHBA==’);

这函数,也是太明显了,PDF链接加PDF密码,我真就乐出了声。不过很快理智就告诉我,这密码明显是加密过的,最后的==结尾就不正常。废话不多说,先拿base64试一把,嗯,失败了……然后就老老实实的按照函数一层一层的找,发现了这个。

很明显,就是通过decryptByDESModeEBC这个函数,利用unCompileCode(‘rayux~ddl|m~’)函数的结果解密加密过的密码,说起来都很绕嘴。

然而事实上代码却没多少,俩函数加一块的JS也就这么几行。说出来你可能不信,由于输入的字符串是个定值,经过unCompileCode函数解析出来的解密密钥,是qazwsxedcrfv,低头看看键盘你就明白了。

别着急,之后还有更无语的呢。另一个函数也不难,就是将加密文本先行base64解密,然后利用DES.ECB算法,配合密钥(qazwsxedcrfv)对密文进行解密。但经过我查阅资料,发现这个算法只需要八位字符,也就是说,真正有效的解密密钥,只是qazwsxed,通过验证事实就是如此。

我还能说什么呢,那句话怎么说来着,脱裤子放屁吧。先是整个简单到不行的算法把12位连续的字符串加密成奇奇怪怪的字符串,然后也只是用其中的8位……

这下其实就是基本完成了,有了解密的算法,就能成功的拿到密钥,拿到密钥之后便可以成功的在本地打开PDF了。

为什么说基本呢?你不觉得这样很麻烦吗,每次阅读都要输入密码,我们还是一步到位,把PDF的密码移除了吧。但WPS却告诉我,我拿到的密码权限不足……

体坛加,真有你的,跟这等着我呢。于是乎一通查找,最后找到了python的pikepdf这个库,利用可以打开PDF的密码,就可以移除密码。不得不说,WPS你这个小垃圾。

结束了吗?讲道理是该结束了。但会员不能白开,会员权益之一是可以阅读2016年至今的过刊,爬虫之心冉冉升起。

但其实这个真就是很简单的啊,先获取到每份报纸的ID,然后遍历调用下载解密程序就好了,但是体坛加再一次给了我惊喜。

也是真没想到,我就想获取个列表你都要SIGN,没必要吧大哥。既然如此,只能奉陪到底了,再一次开始网页调试。cryptoUtil.sign_simple({typeId:type,year:year,pageSize:30,pagenum:pagenum}),这句话暴露了一切,就是简单地将请求参数利用sign_simple求个散列值之类的东西。

然而我再一次低估了体坛加无事生非的程度,cryptoUtil.js都妥妥的摆在那里,然而sign_simple却是在eval函数里……你就是为了让我不方便看的吗?

整理出来大概就是这样,一百行左右,多吗?对于我而言,一点都不多!因为仔细读读就能看出来,放到python里,这玩意就是把请求参数的json转换成了dict再转换成k=v&格式,其中还有各种校验而已。而Sign就是把k=v&格式的字符串做了一个MD5,仅此而已。

仅此而已?我试了试,失败了……我查了好久,但这个请求真的是太简单,cookie都不用,我怎么会请求失败呢?这时候真就是百思不得其解啊。我又读了半天JS代码,发现了这句不起眼的话,return x.toLowerCase() > y.toLowerCase() ? 1 : -1,这是在转换k=v&格式前进行了排序啊,按照小写字母序进行排序,然后再格式转换。

然后,我就成功了。是这样的,体坛加是强制要求请求参数的顺序的,我也真是万万没想到我会险些折在这,啥也不说了,respect!

到这真就是结束了,通过按年请求获得报刊的ID,然后再下载解密,最后就可以获得2016至今所有的体坛周刊PDF版。

·后记

我还会去尝试看看别的报纸能不能获取PDF电子版,比如南方都市报等,我觉得这是在现代化的今天拥抱传统媒体的一种最好的方法了。每天去买报纸或许真的很难实现,单位楼下也并没有报亭,即便买了纸质媒体也不那么便于阅读。我希望能用这种付费的方式支持纸媒,在我看来,新媒体讲究的是时效性,爆炸性新闻即刻送达,纸媒却是深度报道的最佳载体,挖掘事件背后的真相,深度点评事件影响。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注