【爬虫实战】2.多线程批量下载+多线程PDF转TXT(另附2010-2021A股TXT年报下载)

1.项目分析

数据来源:excel表格文件

项目需求:从excel表格中批量下载pdf版本的年报,将其命名为"股票代码_公司简称_ 年份"的格式,并全部转为txt文件。

使用语言:python

第三方库:pandas,requests, re , pdfplumber,time等。

实现思路:

  • 由于企业年报文件众多,需要加入多线程来改善程序运行速度;
  • 企业年报下载后体积较大,在转换为txt文件后清理原有pdf文件(可选);
  • 出于效率考虑,将下载与转换操作合并,读者亦可自行调整代码分离处理。

2. 具体步骤

1.准备工作

由于数据保存在excel文件中,所以第一步从读取数据入手,本文采用pandas库处理excel表格,其他第三库亦可。

import requests
import pandas as pd
import os
import multiprocessing
import pdfplumber
import logging
import re

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')


# 读取Excel文件
try:
    df = pd.read_excel('年报_2015.xlsx')
except Exception as e:
    logging.error(f"读取失败!! {e}")
    return

下图为原始excel文件数据,我们可以用标题名称来作为查找名,并设置对应的变量。

# 读取文件内容并存储为字典
content_dict = ((row['公司代码'], row['公司简称'], row['年份'], row['年报链接']) for _, row in df.iterrows())
# 我们分别用code, name, year, pdf_url四个变量来接受这些值

在设置好变量后,还需要设置文件目录,用来存放下载的pdf文件和我们需要的txt文件,因此我们创建两个文件夹。

# 创建存储文件的文件夹
pdf_dir = 'pdf年报'
txt_dir = 'txt年报'
try:
    os.makedirs(pdf_dir, exist_ok=True)
    os.makedirs(txt_dir, exist_ok=True)
except Exception as e:
    logging.error(f"创建文件夹失败!请检查权限! {e}")
    return

2.多线程操作

前面提到,由于表格中的文件比较庞大,直接运行速度过于缓慢,需要加入多线程来提高效率,而且笔者将下载与转换都一次性处理,在分配一个线程进行,逻辑如下图所示。
【爬虫实战】2.多线程批量下载+多线程PDF转TXT(另附2010-2021A股TXT年报下载)_第1张图片

多线程具体代码如下,我们开启一个线程池(网络上有很多人讲,这里不赘述),并加入了检查文件是否存在的功能,以防止程序意外中断后,会重复进行下载操作。

如果检测到文件不存在,则调用convert()函数进行下载和转换操作。

#开启多线程
with multiprocessing.Pool() as pool:
    for code, name, year, pdf_url in content_dict:
        txt_file_name = f"{code}_{name}_{year}.txt"
        txt_file_path = os.path.join(txt_dir, txt_file_name)
        #检测文件是否已经存在
        if os.path.exists(txt_file_path):
            logging.info(f"{txt_file_name} 已存在,跳过.")
        else:
            pool.apply_async(convert, args=(code, name, year, pdf_url, pdf_dir, txt_dir))

    pool.close()
    pool.join()

3.下载和转换

接下来的任务写好convert函数即可,这里这直接给出完整代码。

def convert(code, name, year, pdf_url, pdf_dir, txt_dir):
    pdf_file_path = os.path.join(pdf_dir, f"{code}_{name}_{year}.pdf")
    txt_file_path = os.path.join(txt_dir, re.sub(r'[\\/:*?"<>|]', '', f"{code}_{name}_{year}.txt"))

    try:
        # 下载PDF文件
        if not os.path.exists(pdf_file_path):
            with requests.get(pdf_url, stream=True) as r:
                r.raise_for_status()
                with open(pdf_file_path, 'wb') as f:
                    for chunk in r.iter_content(chunk_size=8192):
                        f.write(chunk)
        # 转换PDF文件为TXT文件
        with pdfplumber.open(pdf_file_path) as pdf:
            with open(txt_file_path, 'w', encoding='utf-8') as f:
                for page in pdf.pages:
                    text = page.extract_text()
                    f.write(text)

        logging.info(f"{txt_file_path} 已保存.")

    except Exception as e:
        logging.error(f"出错了- {code}_{name}_{year}. {e}")

    else:
        # 删除已转换的PDF文件,以节省空间
        os.remove(pdf_file_path)
        logging.info(f"{pdf_file_path} 已被删除。")



具体来说,第一步是根据输入参数构造出 pdf文件的完整路径和 txt文件的完整路径。这里使用了 Python 的 os.path.join 函数来拼接文件路径,以及 re.sub 函数来去除文件名中的非法字符。

接下来就是用 requests 库从 pdf_url 下载文件,并将其保存在 pdf_file_path 中。下载的过程中,函数会以 8192 字节为一块,依次将文件块写入本地文件。

如果 pdf文件下载成功,我们使用 pdfplumber 库将 其转换为txt文件。

最后,函数会删除已经转换成功的 pdf文件,这样就大功告成了~


3.成果展示

经过整理,得到了如下txt文本,可以看到txt文本内容与原内容一致,便于我们之后进行词频分析。
【爬虫实战】2.多线程批量下载+多线程PDF转TXT(另附2010-2021A股TXT年报下载)_第2张图片

文本挖掘是财经类学术研究的常用方式,特别是借助上市公司年报进行词频分析的应用十分广泛。
若要获取完整代码文件,或者2010-2021的txt年报下载链接,可以关注同名公众号“凌小添”回复‘年报’获取哦~

你可能感兴趣的:(爬虫,pdf,python)