热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Python抓取「知识星球」内容生成电子书

是不是有时星球内容太多刷不过来?是不是想把星球精华内容撸下来做个电子书?本文就带你实现用Python抓取星球内容,并生产PDF电子书。先上效果:内容基于https:github.c

是不是有时星球内容太多刷不过来?是不是想把星球精华内容撸下来做个电子书?

本文就带你实现用 Python 抓取星球内容,并生产 PDF 电子书。

先上效果:

最终效果图


内容基于 https://github.com/96chh/crawl-zsxq 进行的优化,主要优化内容在于,翻页时间的处理、大段空白处理、评论抓取、超链接处理等。



涉及到隐私问题,这里我们以免费星球「万人学习分享群」为爬取对象。



过程分析

模拟登录

爬取的是网页版知识星球,https://wx.zsxq.com/dweb/。

这个网站并不是依靠 COOKIE 来判断你是否登录,而是请求头中的 Authorization 字段。

所以,需要把 Authorization,User-Agent 换成你自己的。(注意 User-Agent 也要换成你自己的)

一般来说,星球使用微信扫码登录后,可以获取到一个 Authorization,这个歌有效期很长反正,真的很长。

headers = {
'Authorization': 'C08AEDBB-A627-F9F1-1223-7E212B1C9D7D',
'x-request-id': "7b898dff-e40f-578e-6cfd-9687a3a32e49",
'accept': "application/json, text/plain, */*",
'host': "api.zsxq.com",
'connection': "keep-alive",
'referer': "https://wx.zsxq.com/dweb/",
'user-agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36",
}

页面内容分析

登录成功后,一般我习惯右键、检查或者查看源代码。

但是这个页面比较特殊,它不把内容放到当前地址栏 URL 下,而是通过异步加载(XHR),只要找对接口就可以了。

精华区的接口:https://api.zsxq.com/v1.10/groups/2421112121/topics?scope=digests&count=20

这个接口是最新 20 条数据的,还有后面数据对应不同接口,这就是后面要说的翻页。


制作 PDF 电子书

需安装模块:



  1. wkhtmltopdf,用作导出 PDF,安装完成后可用命令生成 PDF,例如:wkhtmltopdf http://www.google.com.hk google.pdf

  2. pdfkit,是 python 对 wkhtmltopdf 调用的封装,支持 URL、本地文件、文本内容到 PDF 的转换,实际转换还是最终调用 wkhtmltopdf 命令

本来精华区是没有标题的,我把每个问题的前 6 个字符当做标题,以此区分不同问题。


爬取图片

很明显,在返回的数据中的 images 键就是图片,只需提取 large 的,即高清的 url 即可。

关键在于将图片标签 img 插入到 HTML 文档。我使用 BeautifulSoup 操纵 DOM 的方式。

需要注意的是,有可能图片不止一张,所以需要用 for 循环全部迭代出来。

if content.get('images'):
soup = BeautifulSoup(html_template, 'html.parser')
for img in content.get('images'):
url = img.get('large').get('url')
img_tag = soup.new_tag('img', src=url)
soup.body.append(img_tag)
html_img = str(soup)
html = html_img.format(title=title, text=text)

制作精美 PDF

通过 css 样式来控制字体大小、布局、颜色等,详见 test.css 文件。

再将此文件引入到 options 字段中。

optiOns= {
"user-style-sheet": "test.css",
...
}

难点分析

翻页逻辑

爬取地址是:{url}?scope=digests&count=20&end_time=2018-04-12T15%3A49%3A13.443%2B0800

路径后面的 end_time 表示加载帖子的最后日期,以此达到翻页。

这个 end_time 是经过 url 转义了的,可以通过 urllib.parse.quote 方法进行转义,关键是找出这个 end_time 是从那里来的。

经过我细细观察发现:每次请求返回 20 条帖子,最后一条贴子就与下一条链接的 end_time 有关系。

例如最后一条帖子的 create_time 是 2018-01-10T11:49:39.668+0800,那么下一条链接的 end_time 就是 2018-01-10T11:49:39.667+0800,注意,一个 668,一个 667 , 两者相差,于是我们便得到了获取 end_time 的公式:

end_time = create_time[:20]+str(int(create_time[20:23])-1)+create_time[23:]

不过事情没有那么简单,因为上一个 create_time 有可能是 2018-03-06T22%3A29%3A59.000%2B0800,-1 后出现了负数!

由于时分秒都有出现 0 的可能,看来最好的方法是,若出现 000,则利用时间模块 datetime 获取 create_time 的上一秒,然后在拼接 999

# int -1 后需要进行补 0 处理,test_str.zfill(3)
end_time = create_time[:20]+str(int(create_time[20:23])-1).zfill(3)+create_time[23:]
# 时间出现整点时需要特殊处理,否则会出现 -1
if create_time[20:23] == '000':
temp_time = datetime.datetime.strptime(create_time, "%Y-%m-%dT%H:%M:%S.%f+0800")
temp_time += datetime.timedelta(secOnds=-1)
end_time = temp_time.strftime("%Y-%m-%dT%H:%M:%S") + '.999+0800'
end_time = quote(end_time)
next_url = start_url + '&end_time=' + end_time

处理过程有点啰嗦,原谅我时间后面的 000 我没找到直接处理的办法,只能这样曲线救国了。


判断最后一页

翻页到最后返回的数据是:

{"succeeded":true,"resp_data":{"topics":[]}}

故以 next_page = rsp.json().get('resp_data').get('topics') 来判断是否有下一页。


评论爬取

发现评论里也有很多有用的内容,评论的格式如下:

{
"comment_id": 15118288421852,
"create_time": "2018-08-16T16:19:39.216+0800",
"owner": {
"user_id": 1484141222,
"name": "xxx",
"alias": "xxx",
"avatar_url": "https://images.xxx"
},
"text": "他这个资源不做投资才傻",
"likes_count": 0,
"rewards_count": 0,
"repliee": {
"user_id": 484552118,
"name": "Kiwi",
"avatar_url": "https://images.zsxqxxxTRQKsci9Q="
}
}

我们主要解析其中的 owner.nametext,其他信息我们暂时不关心,比如是对谁谁谁的回复,我们暂时只把评论列举出来。

# 评论解析
comments = topic.get('show_comments')
comments_str = ''
if comments:
for comment in comments:
comments_str += comment.get('owner').get('name') + " : " + handle_link(comment.get('text'))
comments_str += '
'

最终评论展示效果:

评论展示效果


优化

中文问题

生成 PDF 后,打开发现中文全部显示为方框,如下图:

中文显示问题

这表示服务器未安装中文字体,安装字体即可,安装下面说明;



  1. 查看目前安装字体:fc-list

  2. 下载所需字体,例如 fangsong_GB2312.ttf

  3. mkdir /usr/share/fonts/zh_CN

  4. cp fangsong_GB2312.ttf /usr/share/fonts/zh_CN

  5. 执行fc-cache -fv

  6. 查看是否安装成功:fc-list,查看是已安装

查看字体列表

重新生成后,一切 OK:

显示正常的中文


页面空白优化

生成成功,但是返现每篇文章默认都是新的一页,出现大块空白,阅读时非常别扭,于是我想着是否可以进行优化。

之所以是一篇星球推文显示成单独的一页,是因为原作者处理时,是将推文分别保存成 HTML 文件进行处理,然后再转换成 PDF。

那么我的思路就是,将每篇推文放在单独的 里,最后合并成一个 HTML,这样最终显示的就是连续的页面了。

修改前:

大段空白

修改后:

连续的页面


超链接优化

在原作者的代码中,没有对超链接进行处理,而星球中有大部分都是进行超链接的分享。

其实这是分享的超链接

没有处理的原因是,抓取到的代码中,超链接是这种形式的:

发现是用 标签包围的,这不是 HTML 原生标签,所以导致无法解析,进而页面也无法展示,我们要做的就是从中解析出超链接内容,并拼接成 HTML 中的超链接。

另外,发现超链接的 URL 是转码后的内容,我们也需要对其进行处理。

这部分的处理代码如下:

# 对文本进行 URL 解码,要不后面解析处理也无法点击
def handle_link(text):
# 星球中用 表示超链接
# 这里我们进行转换
soup = BeautifulSoup(text,"html.parser")
links = soup.find_all('e', attrs={'type':'web'})
if len(links):
for link in links:
title = link.attrs['title']
href = link.attrs['href']
s = '{} '.format(href,title)
text += s

# 清理原文中的 标签
# 这里不清理也没问题,HTML 解析不了,页面也不会显示
# 但是,强迫症。
text = re.sub(r']*>', '', text).strip()
return text

处理后:

超链接处理效果

当然,最好的方式是把超链接的内容也爬取出来,一并放在 PDF 里,这里我就不搞了,有兴趣的尝试下吧。


换行处理

换行在星球上显示是这样的:

星球显示

但是到 PDF 后,换行全部没了,大段文字看起来很费劲:

换行失败

这个处理起来就比较简单了,只要将返回数据中的 \n 替换为 HTML 中的换行标签
即可:

例如获取精华正文时:

text = handle_link(unquote(content.get('text', '').replace("\n", "
")))

需要注意的是,需要在解码之前进行替换。

效果:

换行处理效果

至此,基本需求已完成。

完整代码关注公众号后回复【星球】即可获取。



如果觉得有用,欢迎关注我的微信,一起学习,共同进步,不定期推出赠书活动~

你的关注是对我最大的鼓励!


最近搜集到传智播客 2018 最新 Python 和 Java 教程!关注本公众号,后台回复「2018」即可获取下载地址。




推荐阅读
  • 使用正则表达式爬取36Kr网站首页新闻的操作步骤和代码示例
    本文介绍了使用正则表达式来爬取36Kr网站首页所有新闻的操作步骤和代码示例。通过访问网站、查找关键词、编写代码等步骤,可以获取到网站首页的新闻数据。代码示例使用Python编写,并使用正则表达式来提取所需的数据。详细的操作步骤和代码示例可以参考本文内容。 ... [详细]
  • 这是原文链接:sendingformdata许多情况下,我们使用表单发送数据到服务器。服务器处理数据并返回响应给用户。这看起来很简单,但是 ... [详细]
  • 本文介绍了响应式页面的概念和实现方式,包括针对不同终端制作特定页面和制作一个页面适应不同终端的显示。分析了两种实现方式的优缺点,提出了选择方案的建议。同时,对于响应式页面的需求和背景进行了讨论,解释了为什么需要响应式页面。 ... [详细]
  • 本文介绍了NetCore WebAPI开发的探索过程,包括新建项目、运行接口获取数据、跨平台部署等。同时还提供了客户端访问代码示例,包括Post函数、服务器post地址、api参数等。详细讲解了部署模式选择、框架依赖和独立部署的区别,以及在Windows和Linux平台上的部署方法。 ... [详细]
  • 使用在线工具jsonschema2pojo根据json生成java对象
    本文介绍了使用在线工具jsonschema2pojo根据json生成java对象的方法。通过该工具,用户只需将json字符串复制到输入框中,即可自动将其转换成java对象。该工具还能解析列表式的json数据,并将嵌套在内层的对象也解析出来。本文以请求github的api为例,展示了使用该工具的步骤和效果。 ... [详细]
  • 【MEGA DEAL】Ruby on Rails编码训练营(97%折扣)限时特惠!
    本文介绍了JCG Deals商店提供的Ruby on Rails编码训练营的超值优惠活动,现在只需29美元即可获得,原价为$1,296。Ruby on Rails是一种用于Web开发的编程语言,即使没有编程或网页设计经验,也能在几分钟内构建专业的网站。该训练营共有6门课程,包括使用Ruby on Rails进行BDD的课程,使用RSpec 3和Capybara等。限时特惠,机会难得,赶快行动吧! ... [详细]
  • Java验证码——kaptcha的使用配置及样式
    本文介绍了如何使用kaptcha库来实现Java验证码的配置和样式设置,包括pom.xml的依赖配置和web.xml中servlet的配置。 ... [详细]
  • Python瓦片图下载、合并、绘图、标记的代码示例
    本文提供了Python瓦片图下载、合并、绘图、标记的代码示例,包括下载代码、多线程下载、图像处理等功能。通过参考geoserver,使用PIL、cv2、numpy、gdal、osr等库实现了瓦片图的下载、合并、绘图和标记功能。代码示例详细介绍了各个功能的实现方法,供读者参考使用。 ... [详细]
  • ASP.NET2.0数据教程之十四:使用FormView的模板
    本文介绍了在ASP.NET 2.0中使用FormView控件来实现自定义的显示外观,与GridView和DetailsView不同,FormView使用模板来呈现,可以实现不规则的外观呈现。同时还介绍了TemplateField的用法和FormView与DetailsView的区别。 ... [详细]
  • 本文介绍了前端人员必须知道的三个问题,即前端都做哪些事、前端都需要哪些技术,以及前端的发展阶段。初级阶段包括HTML、CSS、JavaScript和jQuery的基础知识。进阶阶段涵盖了面向对象编程、响应式设计、Ajax、HTML5等新兴技术。高级阶段包括架构基础、模块化开发、预编译和前沿规范等内容。此外,还介绍了一些后端服务,如Node.js。 ... [详细]
  • Spring常用注解(绝对经典),全靠这份Java知识点PDF大全
    本文介绍了Spring常用注解和注入bean的注解,包括@Bean、@Autowired、@Inject等,同时提供了一个Java知识点PDF大全的资源链接。其中详细介绍了ColorFactoryBean的使用,以及@Autowired和@Inject的区别和用法。此外,还提到了@Required属性的配置和使用。 ... [详细]
  • uniapp开发H5解决跨域问题的两种代理方法
    本文介绍了uniapp开发H5解决跨域问题的两种代理方法,分别是在manifest.json文件和vue.config.js文件中设置代理。通过设置代理根域名和配置路径别名,可以实现H5页面的跨域访问。同时还介绍了如何开启内网穿透,让外网的人可以访问到本地调试的H5页面。 ... [详细]
  • .NetCoreWebApi生成Swagger接口文档的使用方法
    本文介绍了使用.NetCoreWebApi生成Swagger接口文档的方法,并详细说明了Swagger的定义和功能。通过使用Swagger,可以实现接口和服务的可视化,方便测试人员进行接口测试。同时,还提供了Github链接和具体的步骤,包括创建WebApi工程、引入swagger的包、配置XML文档文件和跨域处理。通过本文,读者可以了解到如何使用Swagger生成接口文档,并加深对Swagger的理解。 ... [详细]
  • asp中如何嵌入python的简单介绍
    本文目录一览:1、如何在IIS中执行Python脚本 ... [详细]
  • html结构 ... [详细]
author-avatar
徐天凝_669
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有