当前位置: 首页 > news >正文

Python如何通过URL链接判断文件类型

在爬虫开发中经常遇到一类场景:拿到一批URL,有的是普通HTML网页需要解析文本,有的是PDF、Excel、压缩包等下载文件需要保存二进制。
仅仅依靠URL后缀判断并不靠谱,很多动态下载接口没有真实文件后缀;直接全部请求完整内容又浪费带宽。本文分享一套兼顾性能与准确度的实现方案。

业务场景

爬虫抓取列表页拿到大量链接,我们需要做分流:

  1. 如果是HTML网页:请求页面,提取网页文本内容;
  2. 如果是文件资源(PDF/Word/Excel/ZIP等):直接下载保存二进制;
  3. 识别失败:标记为unknown,做兜底处理。
    同时文件类型字符串可以直接存入数据库,方便后续业务使用。

判断思路总览

一共有两种判断手段,组合使用兼顾性能与准确率:

1. URL后缀本地快速判断(无网络请求)

解析URL路径,提取末尾文件扩展名。
优点:零网络开销,速度极快
缺点:不可靠。动态下载接口/download?id=123没有后缀;也存在伪装后缀,例如xxx.pdf实际返回HTML页面。

适合做前置过滤,能识别就直接返回,减少不必要的HTTP请求。

2. HTTP响应头探测(权威判断)

优先发送HEAD请求,只获取响应头,不下载响应体

  • Content-Type:资源MIME类型,用来区分是text/html网页还是application/pdf等二进制文件;
  • Content‑Disposition:如果头部包含attachment,代表浏览器触发下载,里面还可以拿到服务器下发的真实文件名,这对无后缀动态下载接口最为关键。

部分服务器拒绝HEAD请求,此时降级为GET + stream=True,依然只读取响应头,不会拉取完整文件内容。

优先级顺序:
Content‑Disposition中的真实文件名后缀>MIME类型映射>URL路径后缀兜底

完整可运行代码

importrequestsimportrefromurllib.parseimporturlparse,unquote# 需要识别的下载后缀集合(带点小写)DOWNLOAD_EXT={".pdf",".zip",".rar",".7z",".doc",".docx",".xls",".xlsx",".ppt",".pptx",".txt",".csv",".jpg",".jpeg",".png",".gif",".bmp",".mp4",".mp3",".tar",".gz"}# 网页后缀集合HTML_EXT={".html",".htm",".php",".asp",".aspx",".jsp"}# MIME类型映射为文件后缀MIME_MAP={"application/pdf":"pdf","application/zip":"zip","application/x-zip-compressed":"zip","application/vnd.openxmlformats-officedocument.wordprocessingml.document":"docx","application/msword":"doc","application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":"xlsx","application/vnd.ms-excel":"xls","text/csv":"csv","image/jpeg":"jpg","image/png":"png","text/plain":"txt"}HEADERS={"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0.0.0"}defcheck_resource_type(url:str,timeout=8)->str:""" 判断URL资源类型 :param url: 待检测链接 :param timeout: 请求超时时间 :return: "html" | "pdf"/"docx"/"zip"... | "unknown" """# 第一步:本地解析URL后缀快速判断,不走网络parse_result=urlparse(url)path=parse_result.path.lower()dot_index=path.rfind(".")ifdot_index!=-1:ext_with_dot=path[dot_index:]ext_raw=path[dot_index+1:]ifext_with_dotinHTML_EXT:return"html"ifext_with_dotinDOWNLOAD_EXT:returnext_raw# 本地无法判断,发起HTTP头探测try:resp=requests.head(url,headers=HEADERS,timeout=timeout,allow_redirects=True)exceptException:# HEAD被拒绝,降级GET,stream=True不下载bodytry:resp=requests.get(url,headers=HEADERS,timeout=timeout,allow_redirects=True,stream=True)exceptException:return"unknown"content_type=resp.headers.get("Content-Type","").lower().split(";")[0].strip()disposition=resp.headers.get("Content-Disposition","")# 判断是否HTML网页if"text/html"incontent_type:return"html"# 优先从Content‑Disposition提取服务器返回的文件名后缀(动态下载接口核心)fn_match=re.search(r'filename\*?=(?:["\']?)([^"\';\n]+)',disposition)iffn_match:filename=fn_match.group(1)# 处理RFC5987编码文件名 filename*=utf-8''xxx.pdfiffilename.startswith("utf-8''"):filename=unquote(filename[7:])filename=filename.lower()fd=filename.rfind(".")iffd!=-1:returnfilename[fd+1:]# MIME映射获取后缀ifcontent_typeinMIME_MAP:returnMIME_MAP[content_type]# 兜底再次使用URL后缀ifdot_index!=-1:returnpath[dot_index+1:]return"unknown"if__name__=="__main__":test_urls=["https://example.com/detail.html","https://example.com/report.pdf","https://example.com/api/download?id=100","https://example.com/no_suffix_page"]fortest_urlintest_urls:t=check_resource_type(test_url)print(f"{test_url}-->{t}")

业务调用示例

返回的字符串可以直接存入数据库varchar字段。

url="https://xxx.com/xxx"res_type=check_resource_type(url)ifres_type=="html":# 网页,请求获取文本passelse:# 文件,res_type为后缀,unknown时兜底为binsuffix=res_typeifres_type!="unknown"else"bin"save_filename=f"output.{suffix}"# 执行文件保存逻辑

返回值行为示例

URL示例返回结果业务动作
xxx/detail.htmlhtml解析网页文本
xxx/file.pdfpdf保存pdf文件
xxx/api/download?id=123,响应头携带attachment;filename="data.xlsx"xlsx保存xlsx文件
无后缀链接返回HTML页面html解析网页文本
二进制资源全部识别失败unknown保存为.bin

注意坑点

  1. 必须开启allow_redirects=True:很多下载链接会302重定向到真实资源地址,不跟随重定向拿到的是错误头信息。
  2. HEAD请求会被部分服务器405拒绝,代码已经做降级GET+stream=True,不会下载完整body,只会读取headers。
  3. 反爬:请求一定要带上User‑Agent,否则部分网站直接返回403。
  4. 网络异常:超时、连接失败直接返回unknown,不会抛出异常中断爬虫主流程。
  5. 局限性:极少数网站内容类型错误配置,会造成误判;生产环境建议做好异常捕获与日志记录。

性能优化提示

大量URL循环调用的时候,大部分普通HTML页面会在本地URL后缀阶段直接返回,不会产生网络请求
只有没有后缀的模糊链接,才会发送HTTP探测请求,大幅减少爬虫网络开销。

完整函数对外只有一个入口,返回简单字符串,方便数据库存储与后续分流处理。

http://www.jsqmd.com/news/1336960/

相关文章:

  • Graph Engineering与Codex Multi-agent V2:多模型智能体编排实战
  • 小红书内容保存终极指南:如何用开源工具优雅收藏你的灵感宝藏
  • GameMaker跨平台C++扩展开发:YYRunnerInterface接口与实战指南
  • 郑州空气能选购网点推荐:【芬尼】网点密布 - 18002239949
  • Unity Shader颜色控制:从片元着色器到动态调色实战
  • 2026年广州番禺漏水检测公司哪家好?本地正规靠谱服务商选择 - 盛隆防水
  • 乡镇社区整套空气能集中采暖系统推荐哪个品牌:【芬尼】乡镇适配 - 18002239949
  • 免费Windows风扇控制终极指南:5分钟掌握FanControl核心功能
  • AI助手交互模式对比:执行代理与协作顾问的技术路径与应用场景
  • 彻底解决“bind: address already in use”:从原理到实战的端口占用排查指南
  • Resource Override:浏览器资源拦截与重定向的3层架构工程化解决方案实现原理
  • WebGL与WebGPU核心技术对比与68个案例实践指南
  • MySQL DATE类型详解与高效应用指南
  • Cadence Allegro网络表导出与PCB前处理实战指南
  • 2026年深圳专业的电容式点焊机公司哪家靠谱怎么选 - 品牌优推
  • 用户密码与验证码一致性验证的安全实践
  • 3个简单步骤:用Screencast-Keys让你的Blender操作一目了然 [特殊字符]
  • AI资本开支进入盈利验证期:从技术军备竞赛到商业价值落地
  • C++模板编程实战:从泛型思想到智能指针实现
  • 老旧小区改造集中采暖系统选什么牌子靠谱:【芬尼】旧改优选 - 17728181569
  • 三步搞定洛雪音乐音源配置:免费解锁全网无损音乐
  • 2026年8月福建省泉州市移动宽带我的真实避坑攻略 - 找卡家园
  • feign 调用 如果 服务返回有 n个字段 ,客户端调用 响应 对象中只有n-1 个字段
  • 2026年8月郑州市联通500M单宽带避坑全攻略 - 找卡家园
  • 本地部署AI长内容生成项目:从环境配置到批量集成的完整指南
  • 当AI也开始推荐,你的客户被谁截流?
  • BIOS重置全攻略:从原理到实操,解决电脑启动与硬件故障
  • LangChain / Middleware / Overview
  • 专业PCB逆向分析:用OpenBoardView高效处理.brd文件的完整指南
  • 【JVM原理详解】36-JIT编译器概述-C1与C2与分层编译