资讯动态

Python自动化工具:从巨潮资讯网抓取年报PDF并转换为可分析文本

发布时间:2026/9/2 11:22:36 来源:尧图企业网站定制
简介这是一套面向金融数据分析初学者与Python实践者的自动化年报处理工具专为解决巨潮资讯网上市公司年报PDF难以批量词频分析的痛点而设计。资源共13个文件含4个核心Python脚本年报链接抓取、PDF下载、PDF转TXT、通用文本分析、4个XML配置文件IDEA项目结构、1个覆盖2004–2023年年报链接的Excel数据源、1个依赖说明txt及README.md等整体压缩包仅2.14MB轻量易部署。已有201人学习下载适合需快速构建年报文本挖掘流水线的用户。读者可直接运行三步脚本完成“网页抓取→PDF下载→文本提取”全流程获得标准化TXT文本用于后续关键词统计、情感分析或LDA主题建模配套xlsx链接库与模块化代码结构便于按行业/年份筛选目标公司并支持自定义清洗规则扩展。1. 项目概述与核心价值最近在做一个金融文本分析的小研究需要批量处理上市公司的年报。源头数据自然想到了巨潮资讯网这是国内最权威的上市公司信息披露平台。但实际操作起来发现几个痛点非常明显手动一个个搜索、点开、下载PDF效率极低下载下来的PDF文件格式混乱直接做文本分析就像在沙子里淘金噪音太多最后还得想办法把PDF里的文字抠出来转成干净的TXT。这一套流程走下来半天时间就没了还容易出错。于是我就动手写了这个Python小工具目标很明确一键搞定从巨潮资讯网抓取指定公司年报、下载PDF、并自动转换为规整TXT文本的全流程为后续的词频分析、情感分析或机器学习建模提供高质量的数据原料。这个小工具的核心用户是像我一样需要处理大量金融文本的研究员、学生、量化分析爱好者或者任何对上市公司信息披露文本感兴趣的人。它解决的问题非常具体将非结构化的、散落在网络上的PDF公告转化为结构化的、纯净的文本数据。你不需要懂复杂的网络协议也不需要去研究各种PDF解析库的坑工具已经把这条流水线搭建好了。你只需要提供目标公司的股票代码和想要的年份它就能帮你把脏活累活都干了让你能专注于更有价值的分析工作本身。2. 整体设计思路与技术选型做这个工具我的设计原则就八个字流程自动化结果可用化。整个工具被设计成一条清晰的流水线每个环节解决一个具体问题并且环环相扣。2.1 核心流程拆解整个工具的工作流可以分解为四个核心阶段信息检索与链接抓取根据用户输入的股票代码和年份在巨潮资讯网上定位到对应的年报PDF公告页面并提取出PDF文件的真实下载地址。文件下载与本地管理将PDF文件可靠地下载到本地指定目录并按照“公司代码/年份”的层级结构进行存储便于后续管理。PDF文本内容提取解析下载的PDF文件尽可能准确、完整地提取出其中的文字内容并处理PDF中常见的格式干扰问题。文本清洗与格式化输出对提取出的原始文本进行深度清洗去除页眉页脚、无关字符、多余空格和换行生成适合进行自然语言处理NLP的纯净TXT文件。2.2 关键技术选型与考量为什么用这些库每个选择背后都有实际踩坑后的考量。网络请求与解析requestslxmlrequests是Python HTTP库的绝对首选其API简洁直观会话保持、超时设置、异常处理都非常完善。相比urllib代码可读性和开发效率高出一大截。为什么选lxml而不是BeautifulSoup在解析像巨潮资讯网这类结构复杂、动态内容可能较多的网页时lxml的解析速度和XPath表达能力更强。巨潮网的页面结构虽然可能变动但其公告列表和链接的DOM路径通常有规律可循用XPath可以更精准、更稳定地定位元素。BeautifulSoup更适合解析不规范的HTML而lxml在速度和精准度上更适合这个生产数据抓取的场景。PDF文本提取pdfplumber这是选型中最重要的决定。我对比过PyPDF2/PyMuPDF(fitz)/pdfminer.six等多个库。PyPDF2对中文支持 historically 不太友好提取复杂版式PDF时容易乱码或丢字。PyMuPDF性能极佳但对某些内嵌字体或特殊编码的PDF提取文本需要额外配置不够“傻瓜化”。pdfminer.six功能强大但API相对复杂需要更多的代码来处理布局分析。pdfplumber正是在pdfminer.six的基础上进行了高层封装它提供了极其友好的API比如.extract_text()并且在表格提取、字符位置识别上表现突出。对于年报这种以连续文字为主、夹杂少量表格的文档pdfplumber能在保证提取精度的前提下极大简化代码是平衡了易用性与能力的绝佳选择。文本清洗与正则表达式re从PDF里提出的文本是“毛坯房”充满了换行符因为PDF排版导致的断行、多余空格、页码标记如“- 1 -”、页眉页脚信息等。re正则表达式是进行批量文本模式匹配和替换的瑞士军刀是深度清洗不可或缺的工具。路径与文件操作os,pathlib用于创建按公司和年份分类的目录结构管理文件路径。使用pathlib可以让路径操作更面向对象、更清晰跨平台兼容性也更好。注意关于动态内容与反爬。巨潮资讯网的部分页面数据可能是通过JavaScript动态加载的。经过实测其核心的公告列表和PDF链接在初始HTML响应中通常就已包含直接使用requests获取页面内容并用lxml解析即可抓到。如果未来网站改版链接变为动态加载则需要考虑使用Selenium或Playwright等浏览器自动化工具来模拟浏览器行为获取完整页面。本工具基于当前可稳定访问的静态结构设计。3. 核心模块详解与实操要点接下来我们深入每个核心模块看看代码具体怎么写以及有哪些必须注意的细节。3.1 链接抓取模块如何精准定位PDF下载地址这是第一步也是最容易因为网站结构变动而失效的一步。我们的目标是输入股票代码如000001平安银行和年份如2023得到对应年报PDF的最终下载链接。import requests from lxml import etree import re def fetch_annual_report_url(stock_code, year): 根据股票代码和年份从巨潮资讯网获取年报PDF的下载链接。 Args: stock_code (str): 6位股票代码例如 000001 year (str or int): 年份例如 2023 Returns: str: 年报PDF文件的直接下载链接如果未找到则返回None。 # 构造搜索请求的URL模板实际URL需根据网站当前结构调整 # 这里是一个示例巨潮网通常通过特定接口或搜索页面进行查询 base_url fhttp://www.cninfo.com.cn/new/disclosure/stock?stockCode{stock_code} # 注意实际URL可能需要包含更多参数如公告类型、年份范围等。 # 更常见的做法是模拟其搜索接口的POST请求或解析搜索结果页。 headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 } try: resp requests.get(base_url, headersheaders, timeout10) resp.raise_for_status() # 检查HTTP请求是否成功 resp.encoding utf-8 # 或根据网页实际编码调整如gbk # 使用lxml解析HTML html etree.HTML(resp.text) # **关键步骤使用XPath定位包含指定年份年报的链接** # 示例XPath需要根据巨潮网实际页面结构进行修改 # 思路寻找所有公告链接然后过滤出文本中包含“年报”和指定年份的链接。 # 例如//a[contains(href, .pdf) and contains(text(), 年报) and contains(text(), 2023)] year_str str(year) # 一个更稳健的XPath可能如下需开发者手动分析页面后确定: # 假设每个公告项在一个class为‘announcement’的div里标题在a标签内 link_xpath f//div[contains(class, announcement)]//a[contains(., 年度报告) and contains(., {year_str})]/href pdf_links html.xpath(link_xpath) if not pdf_links: print(f未找到股票{stock_code}在{year}年的年度报告链接。) return None # 通常第一个链接就是最新的或最相关的年报 target_relative_url pdf_links[0] # 将相对URL补全为绝对URL # 需要观察巨潮网链接是相对路径还是绝对路径 if target_relative_url.startswith(http): pdf_url target_relative_url else: # 这里需要根据网站基础URL进行拼接例如 pdf_url fhttp://www.cninfo.com.cn{target_relative_url} print(f成功找到PDF链接: {pdf_url}) return pdf_url except requests.RequestException as e: print(f网络请求失败: {e}) return None except Exception as e: print(f解析页面时发生未知错误: {e}) return None实操要点与避坑指南XPath是动态的上面代码中的link_xpath只是一个示例。你必须亲自打开巨潮资讯网使用浏览器的开发者工具F12查看目标公告列表的HTML结构然后编写适合当前页面结构的XPath。这是爬虫项目最核心、最需要手动适配的部分。处理反爬机制巨潮网对频繁访问可能会有限制。务必在请求头headers中设置一个真实的User-Agent。更进阶的做法是使用requests.Session()保持会话并在请求间添加随机延时如time.sleep(random.uniform(1, 3))模拟人类操作。链接有效性验证获取到的pdf_url可能是一个中间页面链接而不是直接的PDF地址。有些网站会先跳转到一个预览或确认页面。你可能需要再次访问这个链接从响应内容中提取最终的.pdf链接。可以通过检查URL是否以.pdf结尾或者分析第二次请求返回的HTML/JS代码来判断。错误处理要周全网络超时、页面结构变化、链接失效等情况都要考虑到并用try...except包裹给出明确的错误提示避免程序因单个任务失败而完全崩溃。3.2 文件下载与管理模块稳定下载与有序存储拿到正确的PDF链接后下一步就是把它可靠地下载下来并放到合适的位置。import os from pathlib import Path def download_pdf(pdf_url, stock_code, year, save_dir./reports): 下载PDF文件并保存到本地结构化目录。 Args: pdf_url (str): PDF文件的直接下载链接。 stock_code (str): 股票代码用于创建子目录。 year (str or int): 年份用于创建子目录和命名文件。 save_dir (str): 根存储目录。 Returns: str or None: 成功则返回保存的文件路径失败返回None。 if not pdf_url: return None # 创建按股票代码和年份组织的目录结构 stock_dir Path(save_dir) / stock_code year_dir stock_dir / str(year) year_dir.mkdir(parentsTrue, exist_okTrue) # parentsTrue允许创建多层目录 # 从URL中提取文件名或自己构造 # 方法1使用URL的最后一部分作为文件名可能不友好 # filename pdf_url.split(/)[-1] # 方法2自己构造清晰的文件名推荐 filename f{stock_code}_{year}_年报.pdf file_path year_dir / filename headers { User-Agent: Mozilla/5.0 ..., # 有时需要添加Referer头表明请求来源防止盗链 Referer: http://www.cninfo.com.cn/ } try: print(f正在下载: {pdf_url}) # streamTrue用于流式下载大文件避免内存占用过高 response requests.get(pdf_url, headersheaders, streamTrue, timeout30) response.raise_for_status() # 检查响应内容是否是PDF content_type response.headers.get(content-type, ) if pdf not in content_type.lower(): print(f警告下载的内容类型不是PDF而是 {content_type}。链接可能已失效或需要处理。) # 这里可以尝试处理非PDF响应如跳转页面 # 以二进制写入模式保存文件 with open(file_path, wb) as f: # 分块写入对于大文件更安全 for chunk in response.iter_content(chunk_size8192): if chunk: f.write(chunk) print(f文件已保存至: {file_path}) return str(file_path) except requests.RequestException as e: print(f下载PDF失败: {e}) # 可选删除可能已部分下载的损坏文件 if file_path.exists(): file_path.unlink() return None except IOError as e: print(f文件写入失败: {e}) return None实操要点与避坑指南流式下载streamTrue对于几MB甚至几十MB的年报PDF务必使用流式下载。这允许你分块读取响应内容并写入文件而不是一次性将整个文件加载到内存中对于内存管理和大文件下载至关重要。目录结构设计./reports/000001/2023/000001_2023_年报.pdf这样的结构一目了然后续管理和批量处理都非常方便。使用pathlib的Path对象进行路径操作比用字符串拼接更优雅、更安全自动处理不同操作系统的路径分隔符。设置超时和重试网络环境不稳定下载可能中断。可以为requests.get设置timeout参数。对于重要的批量任务可以考虑实现一个简单的重试机制例如使用tenacity库或在循环中重试几次。验证文件完整性简单的验证可以检查文件大小是否过小可能下载失败或者尝试用pdfplumber打开一下看是否会报“非PDF文件”错误。4. PDF转TXT的核心实现与深度清洗下载好PDF只是拿到了原材料转换成干净文本才是提升数据质量的关键。这一步的挑战在于PDF本质上是面向打印的格式提取文本时会携带大量排版信息。4.1 基础文本提取我们先看看如何用pdfplumber把文字“读”出来。import pdfplumber def pdf_to_raw_text(pdf_path): 使用pdfplumber提取PDF中的所有文本。 Args: pdf_path (str): PDF文件的路径。 Returns: str: 提取出的原始文本。 raw_text try: with pdfplumber.open(pdf_path) as pdf: for page_num, page in enumerate(pdf.pages): # 提取单页文本 page_text page.extract_text() if page_text: # 在每页文本间添加一个换行符作为分隔可选 raw_text page_text \n else: print(f警告第 {page_num1} 页可能为扫描图像或未提取到文本。) return raw_text except Exception as e: print(f打开或解析PDF文件失败: {e}) return 4.2 深度文本清洗从“毛坯”到“精装”raw_text直接可读但充满了问题。下面是一个清洗函数的示例它处理了多种常见噪音import re def clean_extracted_text(raw_text): 对提取的原始文本进行深度清洗。 Args: raw_text (str): 从PDF提取的原始文本。 Returns: str: 清洗后的纯净文本。 if not raw_text: return text raw_text # 1. 移除PDF中常见的页码标记如 “- 1 -”, “1 / 100”, “[1]” # 这类标记通常在行首或行尾且单独成行或与少量字符在一起 text re.sub(r^\s*[-–—]?\s*\d\s*[-–—]?\s*$, , text, flagsre.MULTILINE) # 处理 “- 1 -” text re.sub(r^\s*\d\s*/\s*\d\s*$, , text, flagsre.MULTILINE) # 处理 “1 / 100” text re.sub(r^\s*\[\d\]\s*$, , text, flagsre.MULTILINE) # 处理 “[1]” # 2. 移除常见的页眉页脚关键词需根据年报特点调整 header_footer_keywords [ r巨潮资讯网, rwww\.cninfo\.com\.cn, r公司年度报告, r年度报告摘要, r第\s*\d\s*页\s*共\s*\d\s*页, r股票代码\d, r股票简称.*, r^.*\d{4}年\s*年度报告.*$ # 匹配整行为页眉的情况 ] for pattern in header_footer_keywords: text re.sub(pattern, , text, flagsre.MULTILINE | re.IGNORECASE) # 3. 修复因PDF排版导致的错误换行将行末不是句号、分号、感叹号、问号的中文换行连接起来 # 中文段落内换行通常没有结束符直接连接。英文则需谨慎。 # 这是一个简化策略针对中文文本效果较好。 lines text.split(\n) cleaned_lines [] i 0 while i len(lines): line lines[i].strip() if not line: # 跳过空行 i 1 continue # 如果当前行不以中文句子结束符结尾且下一行非空则合并 if i 1 len(lines): next_line lines[i1].strip() if next_line and not re.search(r[。.””]$, line): line line next_line i 1 # 跳过下一行因为它已被合并 cleaned_lines.append(line) i 1 text \n.join(cleaned_lines) # 4. 合并过多的空白字符空格、制表符等为单个空格 text re.sub(r\s, , text) # 5. 移除首尾空白 text text.strip() # 6. (可选但推荐) 移除或替换特殊字符、不可见字符 # 移除ASCII控制字符除了换行和制表符 text re.sub(r[\x00-\x08\x0b\x0c\x0e-\x1f\x7f], , text) # 将中文全角空格、不间断空格等替换为普通空格 text re.sub(r[\u3000\u00A0], , text) return text4.3 保存清洗后的文本最后将清洗好的文本保存为TXT文件。def save_clean_text(clean_text, pdf_file_path): 将清洗后的文本保存为TXT文件与PDF文件同名同目录。 Args: clean_text (str): 清洗后的文本内容。 pdf_file_path (str): 原始PDF文件的路径。 Returns: str: 保存的TXT文件路径。 if not clean_text: print(清洗后的文本为空跳过保存。) return None pdf_path Path(pdf_file_path) # 生成对应的TXT文件路径例如将 .pdf 替换为 .txt txt_path pdf_path.with_suffix(.txt) try: # 使用UTF-8编码保存确保中文字符正确 with open(txt_path, w, encodingutf-8) as f: f.write(clean_text) print(f清洗文本已保存至: {txt_path}) return str(txt_path) except IOError as e: print(f保存TXT文件失败: {e}) return None实操要点与避坑指南清洗规则是迭代出来的上面的清洗函数是一个通用起点。不同的PDF模板不同公司、不同年份、不同排版软件生成会产生不同的噪音。最好的方法是先处理几份典型的年报观察raw_text的输出找出其中特定的页眉、页脚、页码、无关水印的规律然后补充或修改正则表达式模式。这是一个“观察-分析-添加规则”的循环过程。“修复错误换行”是双刃剑这个步骤对提高中文文本的连贯性至关重要因为它把被PDF硬换行拆散的句子重新拼接起来。但算法如上面的简单合并逻辑可能误判例如将表格中不同单元格的内容错误地合并。如果后续分析对段落结构要求极高可能需要更复杂的启发式规则或者考虑保留原始换行在后续分析中再处理。编码问题务必使用utf-8编码读写TXT文件这是处理中文文本的标准。pdfplumber提取的文本通常是Unicode字符串直接写入即可。处理扫描件PDF如果年报是扫描版图片这在早期年报中常见pdfplumber的.extract_text()将返回空或极少文本。此时需要OCR光学字符识别技术。你可以集成pytesseract库Google Tesseract的Python封装和pdf2image库将PDF页面转为图片来处理。但这会极大增加复杂度和运行时间仅当确定目标PDF为扫描件时才需启用。5. 集成与主流程控制将上述模块串联起来形成一个完整的工具。我们还需要一个主函数来协调整个流程并处理批量任务。import time import random def process_single_report(stock_code, year, base_save_dir./reports): 处理单只股票单一年份的年报抓取-下载-转换-清洗-保存。 Args: stock_code (str): 股票代码。 year (str or int): 年份。 base_save_dir (str): 基础保存目录。 Returns: bool: 是否成功处理。 print(f\n{*50}) print(f开始处理: 股票{stock_code}, {year}年年报) print(f{*50}) # 步骤1: 获取PDF下载链接 pdf_url fetch_annual_report_url(stock_code, year) if not pdf_url: print(获取PDF链接失败终止流程。) return False # 可选添加随机延时避免请求过快 time.sleep(random.uniform(1, 3)) # 步骤2: 下载PDF pdf_path download_pdf(pdf_url, stock_code, year, base_save_dir) if not pdf_path: print(下载PDF失败终止流程。) return False # 步骤3: 提取原始文本 raw_text pdf_to_raw_text(pdf_path) if not raw_text: print(从PDF提取文本失败可能为扫描件或加密文档。) # 这里可以尝试调用OCR备用流程 return False # 步骤4: 清洗文本 clean_text clean_extracted_text(raw_text) # 步骤5: 保存清洗后文本 txt_path save_clean_text(clean_text, pdf_path) success txt_path is not None status 成功 if success else 失败 print(f处理完成状态: {status}) return success def batch_process(stock_list, year_range, base_save_dir./reports): 批量处理多只股票多个年份的年报。 Args: stock_list (list): 股票代码列表如 [000001, 000002]。 year_range (list): 年份列表如 [2022, 2023]。 base_save_dir (str): 基础保存目录。 results [] total len(stock_list) * len(year_range) processed 0 for stock_code in stock_list: for year in year_range: processed 1 print(f\n进度: ({processed}/{total})) try: success process_single_report(stock_code, year, base_save_dir) results.append((stock_code, year, success)) except Exception as e: print(f处理{stock_code}-{year}时发生未捕获的异常: {e}) results.append((stock_code, year, False)) # 批量任务中更长的随机延时以示友好 time.sleep(random.uniform(2, 5)) # 打印汇总报告 print(f\n{*50}) print(批量处理完成汇总报告) success_count sum(1 for _, _, s in results if s) print(f总计任务: {len(results)} 成功: {success_count} 失败: {len(results)-success_count}) if success_count len(results): print(失败详情:) for code, yr, suc in results: if not suc: print(f - {code} ({yr})) # 示例主程序入口 if __name__ __main__: # 单次处理示例 # process_single_report(000001, 2023) # 批量处理示例 my_stocks [000001, 600519] # 平安银行 贵州茅台 my_years [2022, 2023] batch_process(my_stocks, my_years, base_save_dir./annual_reports)6. 常见问题排查与实战技巧在实际运行中你几乎一定会遇到下面这些问题。这里是我踩过坑后总结的排查清单和应对技巧。6.1 网络与请求相关问题问题现象可能原因排查与解决思路requests.get()超时或连接错误网络不稳定目标网站服务器响应慢IP被临时限制。1.增加超时时间timeout(10, 30)连接10秒读取30秒。2.添加重试机制使用requests.adapters.HTTPAdapter设置重试次数。3.使用代理IP如果频繁被封需考虑使用代理池注意合规性。4.检查URL和参数确认构造的搜索URL和参数格式正确可先用浏览器手动测试。返回状态码403禁止访问请求头User-Agent被识别为爬虫缺少必要的请求头如Referer。1.完善请求头模拟真实浏览器添加User-Agent,Accept,Accept-Language,Referer等。2.使用Sessionrequests.Session()可以保持cookies模拟连续访问。3.观察浏览器请求用开发者工具的Network面板复制真实请求的所有Headers。获取的HTML内容为空或与浏览器看到的不符页面数据通过JavaScript动态加载。1.分析初始响应查看resp.text确认所需数据如PDF链接是否在初始HTML中。巨潮网的核心链接通常在初始HTML里。2.寻找隐藏接口用开发者工具寻找页面加载时调用的XHR/Fetch API接口直接请求该接口获取JSON数据更高效。3.终极方案使用Selenium或Playwright控制无头浏览器渲染页面再提取数据。但速度慢、资源占用高。6.2 数据提取与解析问题问题现象可能原因排查与解决思路XPath找不到元素返回空列表网页结构已更新XPath写错了元素在iframe内。1.重新分析页面打开目标页面使用浏览器检查工具CtrlShiftC重新定位元素生成新的XPath。2.使用更宽松的XPath避免使用绝对路径和过于依赖class/id。多用contains()函数进行模糊匹配如//a[contains(text(), 年度报告)]。3.检查iframe如果目标内容在iframe里需要先切换到对应的iframe再进行解析lxml处理iframe较麻烦此时考虑Selenium。提取的PDF链接是中间页非直接下载链接网站设计了防直链点击后跳转到真实地址。1.分析中间页用requests访问这个中间页链接查看其响应内容可能是HTML或JS从中提取真实的.pdf链接。2.模拟点击有时链接是JavaScript函数调用。需要分析JS代码或者直接用Selenium点击该链接获取跳转后的真实URL。pdfplumber打开PDF时报错或提取文本为空PDF文件损坏PDF是扫描图片PDF有加密或特殊权限。1.验证PDF文件用PDF阅读器如Adobe打开下载的文件确认其正常。2.检查是否为扫描件在PDF阅读器中选中文字若无法选中则是图片。需启用OCR流程。3.尝试其他库用PyMuPDF(fitz) 尝试打开看是否有更多错误信息。PyMuPDF有时能处理pdfplumber无法处理的某些加密。6.3 文本清洗与格式问题问题现象可能原因排查与解决思路清洗后文本仍有大量无关数字、乱码或奇怪字符清洗规则不完善PDF本身包含水印、注释、表单域等非正文内容。1.输出原始文本样本将raw_text的前几百行写入一个文件仔细查看找出新的噪音模式。2.针对性添加正则规则例如移除所有单独成行的、由数字和符号组成的短字符串。3.利用pdfplumber高级功能page.extract_words()可以获取每个单词及其坐标通过坐标过滤掉页眉页脚区域如果它们位置固定。这比纯文本正则更精准。段落合并过度导致不同段落或表格内容粘连“修复错误换行”的算法过于激进。1.调整合并策略修改合并逻辑的判断条件。例如只有下一行以非大写字母开头、非特定标题字符开头时才合并。2.分步清洗先进行基础清洗去页码、页眉保留原始换行。在后续的词频分析中许多分析工具如jieba分词对换行不敏感可以暂时不合并。如果需要连贯文本做段落分析再使用更保守的合并算法。中英文混合文本处理不佳清洗规则主要针对中文设计可能误伤英文格式。1.区分处理如果文本是中英文混杂且都需要清洗规则应更保守。重点移除页码、页眉等通用噪音保留原文的换行和空格。2.分词工具选择后续做词频分析时中文用jieba英文用nltk或spacy可能需要先对文本进行语言识别或按段落拆分处理。6.4 效率与稳定性优化技巧使用连接池与会话在批量处理时使用requests.Session()可以复用TCP连接显著提升请求效率。实现增量抓取在本地维护一个记录已成功处理(股票代码, 年份)的日志文件或数据库。每次运行前先检查避免重复下载和转换。加入健壮的日志系统不要只靠print。使用Python的logging模块将运行信息、错误、警告记录到文件便于后期排查问题。设置全局超时与重试除了单个请求的超时可以为整个脚本设置一个运行超时防止因某个任务卡死而无限等待。使用retrying或tenacity库可以优雅地实现重试逻辑。处理编码探测巨潮网页面编码可能是UTF-8或GBK。如果resp.text出现乱码可以尝试resp.content.decode(gbk)或者使用chardet库自动探测编码import chardet; encoding chardet.detect(resp.content)[encoding]。这个工具链搭建起来后你就拥有了一套自动化的金融文本数据生产线。从几十份到上千份年报都可以在设定好任务后让程序自动运行。产出的规整TXT文件可以直接喂给像jieba、snowNLP这样的中文文本分析库或者sklearn、TensorFlow等机器学习框架进行更深度的洞察挖掘。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价