使用Python和FastAPI构建网站爬虫:Oncolo医疗文章抓取实战

news2025/5/20 8:06:17

使用Python和FastAPI构建网站爬虫:Oncolo医疗文章抓取实战

    • 前言
    • 项目概述
    • 技术栈
    • 代码分析
      • 1. 导入必要的库
      • 2. 初始化FastAPI应用
      • 3. 定义请求模型
      • 4. 核心爬虫功能
        • 4.1 URL验证和准备
        • 4.2 设置HTTP请求
        • 4.3 发送请求和解析HTML
        • 4.4 提取文章内容
        • 4.5 保存结果和返回数据
      • 5. API端点定义
      • 6. 启动服务器
    • 爬虫技术要点分析
      • 1. 请求头和会话管理
      • 2. 重试机制
      • 3. HTML解析技巧
      • 4. 递归内容提取
      • 5. 错误处理和异常管理
    • 爬虫开发的最佳实践
    • 改进建议
    • 总结
    • 注意事项

前言

在数据分析和信息收集的时代,网络爬虫技术已成为获取互联网数据的重要手段。本文将通过分析一个实际的爬虫项目,帮助大家了解如何使用Python构建一个功能完善的网站爬虫API,特别是针对医疗类网站的内容抓取。

项目概述

这个项目是一个基于FastAPI的Web服务,专门用于抓取日本医疗网站Oncolo的文章内容。该API可以接收文章URL,然后抓取并解析文章的各个部分,包括标题、副标题、发布日期、正文内容、标签和作者信息等,最后将结果保存为文本文件并返回JSON格式的响应。

技术栈

  • Python:编程语言
  • FastAPI:构建API服务
  • BeautifulSoup:HTML解析
  • Requests:HTTP请求处理
  • Pydantic:数据验证

代码分析

1. 导入必要的库

import requests
from bs4 import BeautifulSoup
import os
import time
import re
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from typing import Optional

from bs4.element import NavigableString, Tag
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.util.retry import Retry
from requests.packages.urllib3.exceptions import InsecureRequestWarning

这部分导入了项目所需的所有库,包括HTTP请求、HTML解析、文件操作和API构建等功能模块。

2. 初始化FastAPI应用

# 安全でないリクエストの警告を無効化
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)

app = FastAPI(title="Oncoloの記事スクレイピングAPI", description="Oncoloウェブサイトの記事内容をスクレイピングするAPI")

这里初始化了FastAPI应用,并禁用了不安全请求的警告(因为代码中使用了verify=False选项)。

3. 定义请求模型

class ScrapeRequest(BaseModel):
    url: str

使用Pydantic定义了一个简单的请求模型,只包含一个URL字段。

4. 核心爬虫功能

scrape_oncolo_article函数是整个项目的核心,它完成了以下任务:

4.1 URL验证和准备
def scrape_oncolo_article(url: str):
    # URL验证
    if not url.startswith('https://oncolo.jp/news/'):
        raise ValueError("URLはoncolo.jp/news/形式である必要があります")
    
    # 从URL提取文件名
    file_id = url.split('/news/')[1]
    output_filename = f"{file_id}.txt"

这部分代码验证URL是否符合要求的格式,并从URL中提取文章ID作为保存文件的名称。

4.2 设置HTTP请求
    # HTTP请求头设置
    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',
        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
        'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
        'Connection': 'keep-alive',
        'Upgrade-Insecure-Requests': '1',
    }

    # 创建会话对象
    session = requests.Session()

    # 设置重试策略
    retry_strategy = Retry(
        total=5,
        backoff_factor=1,
        status_forcelist=[429, 500, 502, 503, 504],
    )
    adapter = HTTPAdapter(max_retries=retry_strategy)
    session.mount("https://", adapter)
    session.mount("http://", adapter)

这部分代码设置了HTTP请求头,创建了一个会话对象,并配置了重试策略。这是爬虫开发中的重要步骤,因为:

  1. 自定义User-Agent可以模拟浏览器行为,避免被网站识别为爬虫
  2. 设置重试策略可以处理临时网络问题和服务器错误
  3. 使用会话对象可以在多次请求之间保持Cookie等状态
4.3 发送请求和解析HTML
    try:
        # 禁用SSL验证
        response = session.get(url, headers=headers, verify=False, timeout=30)
        response.raise_for_status()  # 如果请求失败则抛出异常

        # 使用BeautifulSoup解析HTML
        soup = BeautifulSoup(response.text, 'html.parser')

这部分代码发送HTTP请求并使用BeautifulSoup解析返回的HTML内容。注意这里禁用了SSL验证(verify=False),这在开发阶段可能有用,但在生产环境中应该避免。

4.4 提取文章内容

代码使用BeautifulSoup的选择器功能,根据网站的HTML结构提取各种信息:

  • 主标题和副标题
  • 发布日期和更新日期
  • 文章正文内容
  • 标签信息
  • 作者信息和简介

例如,提取标题的代码:

# 提取标题和副标题
h1_element = main_section.find('h1')
main_title = ""
subtitle = ""

if h1_element:
    subtitle_element = h1_element.find('span', class_='subtitle')
    if subtitle_element:
        subtitle = subtitle_element.get_text(strip=True)
        # 创建h1的副本以避免修改原始soup
        title_copy = BeautifulSoup(str(h1_element), 'html.parser').h1
        subtitle_in_copy = title_copy.find('span', class_='subtitle')
        if subtitle_in_copy:
            subtitle_in_copy.decompose()  # 从副本中删除副标题元素
        main_title = title_copy.get_text(strip=True)
    else:
        main_title = h1_element.get_text(strip=True)
4.5 保存结果和返回数据
# 保存为纯文本文件
output_path = os.path.join('scraped_data', output_filename)
with open(output_path, 'w', encoding='utf-8') as f:
    f.write(f"メインタイトル: {main_title}\n")
    f.write(f"サブタイトル: {subtitle}\n")
    # ...其他内容...

# 返回包含所有内容的响应
return {
    "success": True,
    "message": f"記事は {output_path} に保存されました",
    "filename": output_filename,
    "title": main_title,
    # ...其他字段...
}

这部分代码将提取的内容保存到文本文件中,并返回一个包含所有数据的JSON响应。

5. API端点定义

@app.post("/scrape/", summary="Oncolo記事のスクレイピング", description="oncolo.jpの記事URLを提供し、コンテンツをスクレイピングして保存します")
async def scrape_article(request: ScrapeRequest):
    try:
        result = scrape_oncolo_article(request.url)
        return result
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    except HTTPException as e:
        raise e
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"サーバーエラー: {str(e)}")

@app.get("/", summary="APIルートパス", description="APIの基本情報を返します")
async def root():
    return {"message": "Oncolo記事スクレイピングAPIへようこそ", "usage": "/scrape/エンドポイントにPOSTリクエストを送信し、oncolo.jpの記事URLを提供してください"}

这部分代码定义了两个API端点:

  • /scrape/:接收POST请求,包含要抓取的URL
  • /:根路径,返回API的基本信息

6. 启动服务器

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)

这部分代码使用uvicorn启动FastAPI服务器,监听所有网络接口的8000端口。

爬虫技术要点分析

1. 请求头和会话管理

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',
    # ...其他头信息...
}
session = requests.Session()

要点

  • 设置User-Agent模拟真实浏览器,避免被网站拦截
  • 使用Session对象维护会话状态,提高效率并保持登录状态

2. 重试机制

retry_strategy = Retry(
    total=5,
    backoff_factor=1,
    status_forcelist=[429, 500, 502, 503, 504],
)
adapter = HTTPAdapter(max_retries=retry_strategy)
session.mount("https://", adapter)

要点

  • 实现自动重试机制,处理临时网络问题
  • 使用指数退避策略(backoff_factor)避免频繁请求
  • 针对特定HTTP错误码(如429太多请求、500服务器错误等)进行重试

3. HTML解析技巧

soup = BeautifulSoup(response.text, 'html.parser')
main_section = soup.find('section', class_='main')

要点

  • 使用BeautifulSoup进行HTML解析,比正则表达式更可靠
  • 根据HTML结构和CSS选择器定位元素
  • 处理复杂的嵌套结构和不同类型的内容

4. 递归内容提取

for content in content_div.contents:
    if isinstance(content, NavigableString):
        # 处理文本节点
    elif isinstance(content, Tag):
        # 处理标签节点
        # 递归处理子节点

要点

  • 区分处理文本节点和标签节点
  • 递归遍历复杂的DOM结构
  • 保持原始格式和链接信息

5. 错误处理和异常管理

try:
    # 爬虫代码
except requests.exceptions.RequestException as e:
    raise HTTPException(status_code=500, detail=f"リクエストエラー: {str(e)}")
except Exception as e:
    raise HTTPException(status_code=500, detail=f"処理エラー: {str(e)}")

要点

  • 区分不同类型的异常(请求错误、解析错误等)
  • 提供有意义的错误信息
  • 将内部错误转换为适当的HTTP状态码

爬虫开发的最佳实践

  1. 尊重robots.txt:虽然本例中没有显示,但在实际开发中应该检查目标网站的robots.txt文件,遵守其访问规则。

  2. 控制请求频率:使用time.sleep()或更复杂的限速机制,避免对目标服务器造成过大负担。

  3. 异常处理:全面的异常处理确保爬虫能够稳定运行,即使遇到意外情况。

  4. 模块化设计:将爬虫功能拆分为多个模块,如请求发送、内容解析、数据存储等,便于维护和扩展。

  5. 数据验证:使用Pydantic等工具验证输入和输出数据,确保数据的完整性和一致性。

改进建议

  1. 添加请求延迟:在代码中添加time.sleep(),控制请求频率,避免被目标网站封禁。

  2. 启用SSL验证:在生产环境中应启用SSL验证(删除verify=False),提高安全性。

  3. 使用代理池:对于大规模爬虫,可以实现代理IP轮换机制,避免IP被封。

  4. 添加日志系统:记录爬虫运行状态和错误信息,便于调试和监控。

  5. 实现增量爬取:检查已爬取的内容,只抓取新内容,提高效率。

总结

这个项目展示了如何使用Python构建一个功能完善的网站爬虫API,涵盖了HTTP请求、HTML解析、内容提取、数据存储和API服务等多个方面。通过分析这个实例,我们可以学习到网络爬虫开发的核心技术和最佳实践。

爬虫开发是一个需要不断学习和适应的过程,因为网站结构经常变化,反爬虫技术也在不断升级。希望这篇文章能够帮助你理解爬虫开发的基本原理和技术要点,为你的爬虫项目提供参考。

注意事项

在使用爬虫技术时,请务必遵守以下原则:

  1. 遵守网站的robots.txt规则和使用条款
  2. 控制爬取频率,不对目标网站造成过大负担
  3. 尊重版权,不将抓取的内容用于商业用途(除非得到授权)
  4. 保护个人隐私数据,不抓取和存储敏感信息

只有合法、合理地使用爬虫技术,才能发挥其真正的价值,并避免不必要的法律风险。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2379822.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

写一段图片平移的脚本

问题描述: 写一段图片平移的脚本。 平移就是将对象换一个位置。如果你要沿方向移动,移动的距离是,你可以以下面的方式构建移动矩阵:。 你可以使用Numpy 数组构建这个矩阵(数据类型是np.float32)&#xf…

【C++】哈希的概念与实现

1.哈希概念 通过某种函数使元素的存储位置与它的关键码之间能够建立一一映射的关系,可以不经过任何比较,一次直接从表中得到要搜索的元素。 当向该结构中: 插入元素: 根据待插入元素的关键码,以此函数计算出该元素的…

Yocto和Buildroot功能和区别

一.介绍 Yocto 和 Buildroot 都是用于嵌入式 Linux 系统开发的工具集,它们的目的是帮助开发者轻松构建定制的 Linux 系统镜像,以便在嵌入式设备上运行。 二.对比 1.Yocto Yocto 是一个开源的嵌入式 Linux 构建系统,它允许开发者创建自定义…

详解RabbitMQ工作模式之发布订阅模式

目录 发布订阅模式 概念 概念介绍 特点和优势 应用场景 注意事项 代码案例 引入依赖 常量类 编写生产者代码 编写消费者1代码 运行代码 发布订阅模式 概念 RabbitMQ的发布订阅模式(Publish/Subscribe)是一种消息传递模式,它允许消…

微信学习之导航功能

先看这个功能的效果: 然后开始学习吧。 一、我们这里用的是vant的Grid控件,首先我们导入: { "usingComponents": {"van-search": "vant/weapp/search/index","my-swiper":"../../components…

城市内涝监测预警系统守护城市安全

一、系统背景 城市内涝是指由于强降水或连续性降水超过城市排水能力,导致城市内产生积水灾害的现象。随着气候变化和城市化进程的加快,城市内涝现象愈发频繁和严重。传统的城市排水系统已难以满足当前的城市排水需求,特别是在暴雨等极端天气条…

用 CodeBuddy 搭建「MiniGoal 小目标打卡器」:一次流畅的 UniApp 开发体验

我正在参加CodeBuddy「首席试玩官」内容创作大赛,本文所使用的 CodeBuddy 免费下载链接:腾讯云代码助手 CodeBuddy - AI 时代的智能编程伙伴 在日常生活中,我们总是希望能够坚持一些小习惯,比如每天锻炼十分钟、读一页书、早睡十分…

Web技术与Nginx网站环境部署

目录 一.web基础 1.域名和DNS (1).域名的概念 (2).hosts文件 (3).DNS (4).域名注册 2.网页与HTML (1).网页简介 (2).HTML &a…

AI移动监测:仓储环境安全的“全天候守护者”

AI移动监测在仓储方面的应用:技术赋能与场景突破 一、背景:仓储环境的“隐形威胁”与AI破局 仓储行业长期面临设备损坏、货物损失、卫生隐患等风险。传统监控依赖人工巡检或固定摄像头,难以实时捕捉动态风险。例如: 动物入侵&a…

2025年5月华为H12-821新增题库带解析

IS-IS核心知识 四台路由器运行IS-IS且已经建立邻接关系,区域号和路由器的等级如图中标记,下列说法中正确的有? R2和R3都会产生ATT置位的Level-1的LSPR1没有R4产生的LSP,因此R1只通过缺省路由和R4通信R2和R3都会产生ATT置位的Leve1-2的LSPR2和…

用 python 编写的一个图片自动分类小程序(三)

图片自动分类识别小程序记录 2025/5/18 0:38修改程序界面,增加一些功能 用 python 编写的一个图片自动识别分类小程序。 操作系统平台:Microsoft Windows 11 编程语言和 IDE:python 3.10 Visual studio code 一:图片自动分…

初识 java

目录 前言 一、jdk,JRE和JVM之间的关系 二、JVM的内存划分 前言 初步了解 jdk,JRE,JVM 之间的关系,JVM 的内存划分。 一、jdk,JRE和JVM之间的关系 jdk 是 java 开发工具集,包含JRE; JRE 是…

frida 配置

1.环境 1.1 下载 frida-server firda-server github下载地址 这边推荐使用最新版的上一个版本 根据虚拟机自行选择版本 我使用这个版本 frida-server-16.7.17-android-x86_64 1.2 启动 frida-server-16.7.17-android-x86_64 将文件解压至虚拟机目录 使用adb命令执行 chmo…

16-看门狗和RTC

一、独立看门狗 1、独立看门狗概述 在由单片机构成的微型计算机系统中,由于单片机的工作常常会受到来自外界电磁场的干扰,造成程序的跑飞(不按照正常程序进行运行,如程序重启,但是如果我们填加看门狗的技术&#xff0…

【AI论文】用于评估和改进大型语言模型中指令跟踪的多维约束框架

摘要:接下来的指令评估了大型语言模型(LLMs)生成符合用户定义约束的输出的能力。 然而,现有的基准测试通常依赖于模板化的约束提示,缺乏现实使用的多样性,并限制了细粒度的性能评估。 为了填补这一空白&…

Chromium 浏览器核心生命周期剖析:从 BrowserProcess 全局管理到 Browser 窗口实例

在 Chromium 浏览器架构中,BrowserProcess 和 Browser 是两个核心类,分别管理 浏览器进程的全局状态 和 单个浏览器窗口的实例。它们的生命周期设计直接影响浏览器的稳定性和资源管理。以下是它们的详细生命周期分析: 1. BrowserProcess 的生…

易境通海外仓系统:一件代发全场景数字化解决方案

随着全球经济一体化和消费升级,一件代发业务的跨境电商市场规模持续增长。然而,一件代发的跨境运营也面临挑战,传统海外仓管理模式更因效率低下、协同困难成为业务扩张的瓶颈。 一、一件代发跨境运营痛点 1、多平台协同:卖家往往…

【Python训练营打卡】day30 @浙大疏锦行

DAY 30 模块和库的导入 知识点回顾: 1. 导入官方库的三种手段 2. 导入自定义库/模块的方式 3. 导入库/模块的核心逻辑:找到根目录(python解释器的目录和终端的目录不一致) 作业:自己新建几个不同路径文件尝试下如何…

仿腾讯会议——添加音频

1、实现开启或关闭音频 2、 定义信号 3、实现开始暂停音频 4、实现信号槽连接 5、回收资源 6、初始化音频视频 7、 完成为每个人创建播放音频的对象 8、发送音频 使用的是对象ba,这样跨线程不会立刻回收,如果使用引用,跨线程会被直接回收掉&a…

虚幻引擎5-Unreal Engine笔记之`GameMode`、`关卡(Level)` 和 `关卡蓝图(Level Blueprint)`的关系

虚幻引擎5-Unreal Engine笔记之GameMode、关卡(Level) 和 关卡蓝图(Level Blueprint)的关系 code review! 参考笔记: 1.虚幻引擎5-Unreal Engine笔记之GameMode、关卡(Level) 和 关卡蓝图&…