抓取网页生成电子书(是不是有时星球内容太多刷不过来?想把星球精华内容撸下来)

优采云 发布时间: 2022-01-14 07:01

  抓取网页生成电子书(是不是有时星球内容太多刷不过来?想把星球精华内容撸下来)

  是不是有时候地球上的内容太多无法刷新?你想制作一本收录地球本质的电子书吗?

  本文将带你实现使用Python爬取星球内容,制作PDF电子书。

  第一个效果:

  

  内容以优化为主,主要优化内容在于翻页时间的处理、大空白的处理、评论的抓取、超链接的处理。

  说到隐私问题,这里我们以自由星球“万人学习分享群”为爬取对象。

  过程分析模拟登录

  爬行是知识星球的网络版本。

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

  因此,您需要将 Authorization 和 User-Agent 替换为您自己的。(注意User-Agent也应该换成你自己的)

  一般来说,星球使用微信扫码登录后,可以获得一个Authorization。这首歌长期有效。无论如何,它真的很长。

  1

2

3

4

5

6

7

8

9

  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),只要你找到合适的界面。

  精华区界面:

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

  创建 PDF 电子书

  需要安装的模块:

  wkhtmltopdf 用于导出 PDF。安装后可以使用命令生成PDF,例如:wkhtmltopdf google.pdfpdfkit,它是python对wkhtmltopdf调用的封装,支持URL、本地文件、文本内容到PDF的转换,实际转换还是最终调用wkhtmltopdf命令

  本来,精华区是没有称号的。我用每个问题的前 6 个字符作为标题来区分不同的问题。

  抓取图片

  很明显,返回数据中的images key就是图片,只需要提取大的、高清的url即可。

  关键是将图像标签 img 插入到 HTML 文档中。我使用 BeautifulSoup 操作 DOM 的方式。

  需要注意的是,图片可能不止一张,所以需要使用for循环来遍历所有的图片。

  1

2

3

4

5

6

7

8

  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文件。

  然后将此文件导入选项字段。

  1

2

3

4

  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个post,最后一个post与下一个链接的end_time有关。

  比如上一个帖子的create_time是2018-01-10T11:49:39.668+0800,那么下一个链接的end_time是2018-01-10T11:49:39. 667+0800,注意一个668和一个667是不一样的,所以我们得到end_time的公式:

  1

  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可能出现在时分秒中,看来最好的方法是使用时间模块datetime获取create_time的最后一秒,如果出现000则拼接999。

  1

2

3

4

5

6

7

8

9

10

  # 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。我没有找到直接的方法来处理它。我只能通过这条曲线拯救国家。

  判断最后一页

  翻页返回的数据为:

  1

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

  因此,使用 next_page = rsp.json().get('resp_data').get('topics') 来判断是否有下一页。

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线