用python爬取指定时间范围的人民日报

前言

本文演示了如何使用Python爬取人民日报官网的电子版日报,并将各个页面的报纸整合在一起,主要的内容在于解释程序的设计思路和程序的流程,还有当前程序存在的不足情况



设计背景

由于最近准备考公,在看人民日报的电子版报纸,获取方式一种是手机APP直接查看人民日报,但是只能查看一页,点击之后直接查看有只能看当日某版页中的谋篇文章,不能同时看其他文章;或者只能从官网看电子版,不过官网还得一页一页点击,页面跳转之间很影响体验。
官网有提供下载报纸PDF的链接,但是只能一页一页地下载,还不如在线看电子的。但查看了下载链接之后发现下载链接有很强的规范性,感觉可以试试写个爬虫自动获取,于是开始尝试写程序。

设计思路

要求

  1. 在控制台输入开始和截止时间,能够自动获取时间范围内的人民日报
  2. 由于下载时是一页一页下的,所以最终还需要一个合并功能,使当天的日报各版面合并为一篇完整的
  3. 由于下载链接是规范的,类似于http://paper.people.com.cn/rmrb/images/2023-08/25/20/rmrb2023082520.pdf,所以变动的部分在于2023-08/25/20/rmrb2023082520.pdf,不难发现符合日期 + 版页号 + rmrb + 日期 + 版页号 + “.pdf”,使用代码自动生成
  4. 由于周末两天(8页)和工作日(20页)的版面数不一样,所以添加了一个判断当日是周几的函数,get_weekday(now_time)

程序流程

  1. 接收输入的开始和结束日期
  2. 生成一个日期列表,内部元素为字符串类型,格式为%Y-%m/%d
  3. 根据得到的日期列表开始下载每天的日报PDF,并生成文件夹保存到当前程序所在目录下
  4. 按顺序合并当日的日报,得到一个完整版的当日日报
  5. 保存到指定路径total_file_path

完整程序

# @Version: python3.10
# @Time: 2023/8/25 16:57
# @Author: PlutoCtx
# @Email: 15905898514@163.com
# @File: fetch_fun.py
# @Software: PyCharm
# @User: chent

import datetime
import os
import re

import requests
from PyPDF2 import PdfMerger, PdfReader
from PyPDF2.errors import PdfReadError

# PDF链接
url = 'http://paper.people.com.cn/rmrb/images/2023-08/25/20/rmrb2023082520.pdf'


def init_date(start_date, end_date):
    """
    to get a list of formatted date, like '%Y-%m/%d', it is directly used in the url concat,
    and it is user to generate the files folder
    :param start_date:  start date
    :param end_date:    end date
    :return: list of date
    """
    start_year, start_month, start_day = map(int, start_date.split('-'))
    end_year, end_month, end_day = map(int, end_date.split('-'))

    date_list = []

    current_date = datetime.date(start_year, start_month, start_day)

    while current_date <= datetime.date(end_year, end_month, end_day):
        formatted_date = current_date.strftime('%Y-%m/%d')
        date_list.append(formatted_date)
        current_date += datetime.timedelta(days=1)

    return date_list


def fetch_rmrb_paper(res_list):
    """
    to get People's Daily's everyday newspaper,
    first, get a day's every single paper, save it as named 'rmrb2022040101' and saved in folder '\files\yyyy-MM\dd'
    second, generate the single paper into a complete one day's paper
    :param res_list:list of date that are in defined duration
    :return: files saved
    """
    characters_to_remove = [",", "-", "/"]  # 要去除的字符列表

    # 遍历指定日期范围内的每一天,获取报纸
    for i in res_list:
        # http://... +  2023-08/25/
        temp = 'http://paper.people.com.cn/rmrb/images/' + i + '/'
        flag = update_paper_number(i)

        global folder_path
        folder_path = ""

        # 生成链接,下载当日某一版面的pdf文件
        for j in range(1, flag + 1):
            # http://... +  2023-08/25/ + /XX
            tem = temp + str(j).zfill(2)
            # /rmrb2023082520.pdf'
            string = str(j).zfill(2) \
                     + '/rmrb' \
                     + "".join([c for c in i if c not in characters_to_remove]) \
                     + str(j).zfill(2) + ".pdf"

            print(temp + string)
            # 发送GET请求下载PDF文件
            response = requests.get(temp + string, stream=True)

            # 设置文件夹路径和文件名
            folder_path = "files/" + i + '/'
            file_name = 'rmrb' + "".join([c for c in i if c not in characters_to_remove]) + str(j).zfill(2) + ".pdf"

            # 创建文件夹(如果不存在)
            if not os.path.exists(folder_path):
                os.makedirs(folder_path)

            # 生成文件的完整路径
            file_path = os.path.join(folder_path, file_name)

            with open(file_path, 'wb') as file:
                file.write(response.content)

        # 获取文件夹中的所有 PDF 文件
        pdf_files = [f for f in os.listdir(folder_path) if f.endswith(".pdf")]

        # 根据日期和数字标号排序
        pdf_files = sorted(pdf_files, key=sort_by_date_and_number)

        # 创建 PdfFileMerger 对象...
        pdf_merger = PdfMerger()

        # 逐个合并 PDF 文件
        for pdf_file in pdf_files:
            pdf_path = os.path.join(folder_path, pdf_file)

            try:
                # 通过尝试打开并检查 PDF 文件来捕获异常
                with open(pdf_path, "rb") as f:
                    pdf = PdfReader(f)

                    # 如果文件正常打开,则将其添加到合并器中
                    pdf_merger.append(pdf)

            except (PdfReadError, OSError) as e:
                # 当遇到 PdfReadError 或 OSError 时跳过该文件并打印错误消息
                print(f"跳过文件 '{pdf_file}',发生错误: {str(e)}")

            # pdf_merger.append(pdf_path)

        # 合并后的文件保存路径
        output_path = "total_files/"

        # 创建文件夹(如果不存在)
        if not os.path.exists(output_path):
            os.makedirs(output_path)
        # 生成文件的完整路径
        total_file_path = os.path.join(output_path,
                                       i.replace("/", "-") + ".pdf")

        # 将合并后的 PDF 保存到指定路径
        pdf_merger.write(total_file_path)
        pdf_merger.close()


# 定义排序函数
def sort_by_date_and_number(file_name):
	"""
	define the rule of order, depending on file name's date and number
	"""
    match = re.search(r'\d+', file_name)  # 匹配文件名中的连续数字部分
    if match:
        number = int(match.group())  # 提取连续数字部分并转换为整数
        return file_name[4: 12], number
    return file_name, 0  # 如果没有数字部分,则按原始文件名排序


def get_weekday(now_time):
    """
    to judge when is it today
    :param now_time: like 2023-08/25
    :return: 0 for Mon, 1 for Thu ...
    """
    # 使用多个分隔符拆分字符串
    y, m, d = re.split(r"[-/]",
                       now_time)

    date = datetime.datetime(int(y),
                             int(m),
                             int(d))
    weekday = date.weekday()

    print(int(y),
          int(m),
          int(d),
          weekday)

    return weekday


def update_paper_number(now_time):
    """
    判断当日的报纸有多少份
    正常周末两天只有8份,工作日有20份
    但在下载的过程中某些特别的日子里版页数可能会是8,一般是工作日的20变成8份,而且没有规律
    :param now_time:  like 2023-08/25
    :return: 当日报纸数
    """
    weekday = get_weekday(now_time)
    if weekday == 5 or weekday == 6:
        return 8
    else:
        return 20


if __name__ == '__main__':
    start_date = input("input start date like 'yyyy-MM-dd':")
    end_date = input("input end date like 'yyyy-MM-dd':")
    res_list = init_date(start_date, end_date)
    fetch_rmrb_paper(res_list)

    print("文件保存成功!")

总结和不足

本代码的下载其实是在网页链接规范而且链接名本身就指向了资源的基础上编写的,局限性比较大,普适性不高。

本程序的完整代码如上所示,也传到了本人的github账号里,GitHub,后续的一些代码也会上传到此处,欢迎大家点颗星。
此外,本人之前创建了一个公众号“程序缝补匠”,内容不定期发布,初步打算分享一些代码或者框架,亦或者是和计算机相关的内容,不过除部分内容外都会比较粗浅,但也欢迎志同道合的朋友一起管理这个公众号。新手入行,欢迎大家关注。

如果您下载了本程序,但是该程序存在问题无法运行,那么您可以选择退款或者寻求我们的帮助(如果找我们帮助的话,是需要追加额外费用的)。另外,您不会使用资源的话(这种情况不支持退款),也可以找我们帮助(需要追加额外费用) 爬虫(Web Crawler)是一种自动化程序,用于从互联网上收集信息。其主要功能是访问网页、提数据并存储,以便后续分析或展示。爬虫通常由搜索引擎、数据挖掘工具、监测系统等应用于网络数据抓的场景。 爬虫的工作流程包括以下几个关键步骤: URL收集: 爬虫从一个或多个初始URL开始,递归或迭代地发现新的URL,构建一个URL队列。这些URL可以通过链接分析、站点地图、搜索引擎等方式获。 请求网页: 爬虫使用HTTP或其他协议向目标URL发起请求,获网页的HTML内容。这通常通过HTTP请求库实现,如Python中的Requests库。 解析内容: 爬虫对获的HTML进行解析,提有用的信息。常用的解析工具有正则表达式、XPath、Beautiful Soup等。这些工具帮助爬虫定位和提目标数据,如文本、图片、链接等。 数据存储: 爬虫将提的数据存储到数据库、文件或其他存储介质中,以备后续分析或展示。常用的存储形式包括关系型数据库、NoSQL数据库、JSON文件等。 遵守规则: 为避免对网站造成过大负担或触发反爬虫机制,爬虫需要遵守网站的robots.txt协议,限制访问频率和深度,并模拟人类访问行为,如设置User-Agent。 反爬虫应对: 由于爬虫的存在,一些网站采了反爬虫措施,如验证码、IP封锁等。爬虫工程师需要设计相应的策略来应对这些挑战。 爬虫在各个领域都有广泛的应用,包括搜索引擎索引、数据挖掘、价格监测、新闻聚合等。然而,使用爬虫需要遵守法律和伦理规范,尊重网站的使用政策,并确保对被访问网站的服务器负责。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

听弦者陈 · PlutoCtx

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值