爬虫入门re+bs4

news2025/3/22 12:42:04

目录

前言

1. 导入必要的库

2. 定义获取网页HTML内容的函数 get_html

3. 定义获取数据的函数 get_data

4. 定义获取文章正文内容的函数 content_text

5. 定义获取单条课程数据的函数 get_one_course_data

6. 定义保存数据的函数 `save_data`

7. 定义文件名合法化处理函数 `sanitize_filename`

8. 主程序


前言

在信息爆炸的时代,互联网已成为数据获取的核心渠道。从学术研究到商业分析,从新闻监控到用户行为洞察,数据的价值日益凸显。而网络爬虫(Web Crawler)作为自动化获取网络数据的核心技术,正扮演着越来越重要的角色。本案例将通过一个完整的 Python 爬虫案例,构建高效、可靠的爬虫系统,实现对中文日报网站内容的自动化抓取与结构化存储。

说明

遵守法律法规:确保爬取的内容符合目标网站的 robots 协议,避免侵犯他人知识产权。

合理控制请求频率:通过time.sleep()等机制降低对目标服务器的压力,防止 IP 被封禁。

动态调整策略:网页结构可能变化,需根据实际情况修改解析逻辑(如 CSS 选择器)。

实战导向:以 中国日报(China Daily) 真实网页为目标,演示从页面解析到数据存储的全流程,代码可直接复用于类似网站。

技术覆盖:涵盖 HTTP 请求、HTML 解析、反爬策略、数据清洗、文件存储等核心技术,结合requests、BeautifulSoup、pandas等主流库,提升代码实战能力。

模块化设计:通过函数封装实现功能解耦,降低代码复杂度,便于后续扩展与维护。

反爬与稳定性:包含请求头伪装、异常处理、延时机制等策略,减少被目标网站封禁的风险。

掌握 Python 爬虫的基本架构与工作流程;

学会使用BeautifulSoup解析复杂 HTML 结构;

理解并处理网页反爬机制(如请求头伪装、延时控制);

实现数据的清洗、存储与持久化(CSV 文件);

了解图片下载与文件名合法化处理技巧。

适用场景

案例适合以下读者:

对 Python 爬虫感兴趣的初学者;

需要批量获取公开网络数据的开发者;

希望了解新闻聚合、舆情监控等应用的从业者。

代码亮点

智能编码处理:使用chardet自动检测网页编码,避免乱码问题;

结构化数据存储:通过pandas将数据保存为 CSV 文件,便于后续分析;

图片本地化存储:自动下载文章配图并命名,支持特殊字符过滤;

分页爬取支持:自动识别 “下一页” 链接,实现无限翻页抓取。

后续扩展建议

添加代理池以应对反爬限制;

集成 Scrapy 框架提升爬取效率;

增加数据去重与增量更新功能;

结合 NLP 技术对新闻内容进行情感分析。

构建高效的中文日报内容抓取系统

1. 导入必要的库

import os.path
import requests
import chardet
import time
from bs4 import BeautifulSoup
import pandas as pd
import re

os.path:用于处理文件路径相关操作,例如检查文件是否存在

requests:用于发送HTTP请求,获取网页内容

chardet:用于检测网页内容的字符编码

time:用于添加延时,避免对目标网站造成过大压力

BeautifulSoup:用于解析HTML和XML文档,方便提取所需信息

pandas:用于数据处理和保存,将爬取的数据保存为CSV文件

re:用于正则表达式操作,例如文件名的合法化处理

2. 定义获取网页HTML内容的函数 get_html

def get_html(url):
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Edg/124.0.0.0'
    }
    try:
        # 发送请求
        response = requests.get(url, headers=headers)

        # 检查请求响应状态码
        response.raise_for_status()

        # 设置相应内容字符编码
        response.encoding = chardet.detect(response.content)['encoding']

        return response.text
    except Exception as e:
        print(e)
    finally:
        time.sleep(2)

功能:发送HTTP请求获取指定URL的网页内容,并处理字符编码

步骤:

1. 设置请求头 `headers`,模拟浏览器访问,避免被网站识别为爬虫

2. 使用 `requests.get` 方法发送请求

3. 使用 `raise_for_status` 方法检查响应状态码,如果状态码不是200,抛出异常

4. 使用 `chardet` 检测网页内容的字符编码,并设置响应的编码

5. 返回网页的文本内容

6. 无论请求是否成功,最后都使用 `time.sleep(2)` 暂停2秒,避免频繁请求

3. 定义获取数据的函数 get_data

def get_data(html):
    # 解析HTML文本
    bs = BeautifulSoup(html, 'lxml')

    # 查找第一个符合class_="left-liebiao"条件div的标签
    div_tag_one = bs.find('div', class_="left-liebiao")

    # 查找所有符合class_="busBox3"条件的div标签
    div_tags = div_tag_one.find_all('div', class_="busBox3")

    return [get_one_course_data(div_tag) for div_tag in div_tags]

功能:从网页HTML内容中提取所需的数据。

步骤:

1. 使用 `BeautifulSoup` 解析HTML文本

2. 查找第一个 `class` 为 `left-liebiao` 的 `div` 标签

3. 在该 `div` 标签内查找所有 `class` 为 `busBox3` 的 `div` 标签

4. 遍历这些 `div` 标签,调用 `get_one_course_data` 函数提取每条数据

4. 定义获取文章正文内容的函数 content_text

def content_text(content_url):
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Edg/124.0.0.0'
    }
    # 发送请求
    response = requests.get(content_url)

    # 检查请求响应状态码
    response.raise_for_status()

    # 设置相应内容字符编码
    response.encoding = chardet.detect(response.content)['encoding']

    html = response.text

    # 解析HTML文本
    bs = BeautifulSoup(html, 'lxml')

    # 查找所有符合id="Content"条件的div标签
    div = bs.find('div', id="Content")

    p_tags = div.find_all('p')

    # 写入文本
    texts = [texts.text for texts in p_tags]
    texts = ''.join(texts)
    return texts

功能:根据文章链接获取文章的正文内容。

步骤:

1. 设置请求头,发送HTTP请求。

2. 检查响应状态码,设置字符编码。

3. 使用 `BeautifulSoup` 解析HTML文本。

4. 查找 `id` 为 `Content` 的 `div` 标签。

5. 在该 `div` 标签内查找所有 `p` 标签。

6. 提取 `p` 标签的文本内容,并拼接成一个字符串返回。

5. 定义获取单条课程数据的函数 get_one_course_data

def get_one_course_data(div_tag):
    # 找到标题内容
    title_tag = div_tag.select_one('div > div:nth-child(2) > h3 > a')

    title = title_tag.text.strip() if title_tag is not None else None

    # 保存图片
    img_tag = div_tag.select_one('img')
    print(img_tag)
    if img_tag:
        img_url = img_tag.get('src')

        img_url = 'https:' + img_url

        img = requests.get(img_url)

        img.raise_for_status()

        img_name = sanitize_filename(title)
        print(img_name)
        file_name = f'test/{img_name}.jpg'
        with open(file_name, 'wb') as f:
            f.write(img.content)

    # 找到摘要内容
    abstract_tag = div_tag.select_one('div > div:nth-child(2) > p')

    abstract = ''.join([abstracts.strip() for abstracts in abstract_tag if isinstance(abstracts, str)])

    # 找到日期内容
    date_tag = div_tag.select_one('div > div:nth-child(2) > p > b')

    date = date_tag.text.strip() if date_tag is not None else None

    # 爬取正文内容
    content_url = 'https:' + title_tag.get('href')
    content = content_text(content_url)

    return title, abstract, date, content

功能:从单个 `div` 标签中提取标题、图片、摘要、日期和正文内容。

步骤:

1. 使用 `select_one` 方法找到标题标签,并提取标题文本

2. 找到图片标签,获取图片链接,发送请求下载图片,并保存到本地。使用 `sanitize_filename` 函数对文件名进行合法化处理

3. 找到摘要标签,提取摘要内容

4. 找到日期标签,提取日期内容

5. 构建文章链接,调用 `content_text` 函数获取文章正文内容

6. 返回标题、摘要、日期和正文内容

6. 定义保存数据的函数 `save_data`

def save_data(data, file_name):
    df = pd.DataFrame(data, columns=['标题', '摘要', '日期', '详情(新闻内容)'])
    if not os.path.exists(file_name):
        df.to_csv(file_name,
                  encoding='utf-8-sig',  # 编码为utf-8-sig
                  header=True,  # 添加列名
                  index=False)  # 不添加行索引
    else:
        df.to_csv(file_name,
                  encoding='utf-8-sig',  # 编码为utf-8-sig
                  header=False,  # 不加列名
                  index=False,  # 不添加行索引
                  mode='a')  # 追加数据
    return

功能:将爬取的数据保存为CSV文件。

步骤:

1. 使用 `pandas` 的 `DataFrame` 方法将数据转换为数据框

2. 检查文件是否存在,如果不存在,则创建文件并添加列名;如果存在,则追加数据,不添加列名

7. 定义文件名合法化处理函数 `sanitize_filename`

def sanitize_filename(filename):
    # 定义正则表达式,匹配所有不合法的字符
    pattern = r'[\\*?:"<>|【】]'
    # 将不合法的字符替换为下划线
    return re.sub(pattern, '_', filename)

功能:将文件名中的不合法字符替换为下划线,避免保存文件时出现错误

8. 主程序

if __name__ == '__main__':
    # 爬取地址
    url = f'https://china.chinadaily.com.cn/5bd5639ca3101a87ca8ff636/page_39.html'  # 如果改成其它的url,可能有反爬策略和不同的内容定位策略+翻页规则

    while url:
        # 获取网页文本内容
        html = get_html(url)
        if not html:
            break

        # 获取关键信息
        data = get_data(html)

        # 写入文件
        file_name = '中文日报.csv'
        save_data(data, file_name)

        # 解析HTML文本,查找下一页链接
        bs = BeautifulSoup(html, 'lxml')
        next_page_tag = bs.find('a', text='下一页')
        if next_page_tag:
            url = 'https:' + next_page_tag.get('href')
        else:
            url = None

功能:从指定URL开始爬取数据,直到没有下一页为止。

步骤:

1. 定义初始爬取URL

2. 使用 `while` 循环,只要 `url` 不为空,就继续爬取

3. 调用 `get_html` 函数获取网页HTML内容

4. 调用 `get_data` 函数提取关键信息

5. 调用 `save_data` 函数将数据保存到CSV文件

6. 解析HTML文本,查找下一页链接。如果找到,则更新 `url`;否则,将 `url` 置为 `None`,结束循环

运行效果:

保存的图片如果没有明确指定文件路径则默认到当前工作目录下,保存的图片:

这个爬虫代码的案例主要功能是从指定的网页开始,爬取新闻标题、摘要、日期、正文内容和图片,并将数据保存为CSV文件。代码通过定义多个函数,将不同的功能模块化,提高了代码的可读性和可维护性。通过添加了异常处理和延时机制,避免对目标网站造成过大压力。完整代码:

import os.path
import requests
import chardet
import time
from bs4 import BeautifulSoup
import pandas as pd
import re

def get_html(url):
    headers = {
        'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Edg/124.0.0.0'
    }
    try:
        # 发送请求
        response = requests.get(url,headers=headers)

        # 检查请求响应状态码
        response.raise_for_status()

        # 设置相应内容字符编码
        response.encoding = chardet.detect(response.content)['encoding']

        return response.text
    except Exception as e:
        print(e)
    finally:
        time.sleep(2)

def get_data(html):
    # 解析HTML文本
    bs = BeautifulSoup(html,'lxml')

    # 查找第一个符合class_="left-liebiao"条件div的标签
    div_tag_one = bs.find('div',class_="left-liebiao")

    # 查找所有符合class_="busBox3"条件的div标签
    div_tags = div_tag_one.find_all('div',class_="busBox3")

    return [get_one_course_data(div_tag) for div_tag in div_tags]

def content_text(content_url):
    headers = {
        'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Edg/124.0.0.0'
    }
    # 发送请求
    response = requests.get(content_url)

    # 检查请求响应状态码
    response.raise_for_status()

    # 设置相应内容字符编码
    response.encoding = chardet.detect(response.content)['encoding']

    html = response.text

    # 解析HTML文本
    bs = BeautifulSoup(html, 'lxml')

    # 查找所有符合id="Content"条件的div标签
    div = bs.find('div', id="Content")

    p_tags = div.find_all('p')

    # 写入文本
    texts = [texts.text for texts in p_tags]
    texts = ''.join(texts)
    return texts

def get_one_course_data(div_tag):
    # 找到标题内容
    title_tag = div_tag.select_one('div > div:nth-child(2) > h3 > a')

    title = title_tag.text.strip() if title_tag is not None else None

    # 保存图片
    img_tag = div_tag.select_one('img')
    print(img_tag)
    if img_tag:
        img_url = img_tag.get('src')

        img_url = 'https:' + img_url

        img = requests.get(img_url)

        img.raise_for_status()


        img_name = sanitize_filename(title)
        print(img_name)
        file_name = f'test/{img_name}.jpg'
        with open(file_name, 'wb') as f:
            f.write(img.content)

    # 找到摘要内容
    abstract_tag = div_tag.select_one('div > div:nth-child(2) > p')

    abstract = ''.join([abstracts.strip() for abstracts in abstract_tag if isinstance(abstracts, str)])

    # 找到日期内容
    date_tag = div_tag.select_one('div > div:nth-child(2) > p > b')

    date = date_tag.text.strip() if date_tag is not None else None

    # 爬取正文内容
    content_url = 'https:' + title_tag.get('href')
    content = content_text(content_url)

    return title,abstract,date,content

def save_data(data,file_name):
    df = pd.DataFrame(data,columns=['标题','摘要','日期','详情(新闻内容)'])
    if not os.path.exists(file_name):
        df.to_csv(file_name,
                  encoding='utf-8-sig',  # 编码为utf-8-sig
                  header=True,  # 添加列名
                  index=False)  # 不添加行索引
    else:
        df.to_csv(file_name,
                  encoding='utf-8-sig',  # 编码为utf-8-sig
                  header=False,  # 不加列名
                  index=False,  # 不添加行索引
                  mode='a')  # 追加数据
    return

def sanitize_filename(filename):
    # 定义正则表达式,匹配所有不合法的字符
    pattern = r'[\\*?:"<>|【】]'
    # 将不合法的字符替换为下划线
    return re.sub(pattern, '_', filename)

if __name__=='__main__':
    # 爬取地址
    url = f'https://china.chinadaily.com.cn/5bd5639ca3101a87ca8ff636/page_39.html' # 如果改成其它的url,可能有反爬策略和不同的内容定位策略+翻页规则

    while url:
        # 获取网页文本内容
        html = get_html(url)
        if not html:
            break

        # 获取关键信息
        data = get_data(html)

        # 写入文件
        file_name = '中文日报.csv'
        save_data(data, file_name)

        # 解析HTML文本,查找下一页链接
        bs = BeautifulSoup(html,'lxml')
        next_page_tag = bs.find('a',text='下一页')
        if next_page_tag:
            url = 'https:' + next_page_tag.get('href')
        else:
            url = None

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

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

相关文章

MySQL身份验证的auth_socket插件

在Ubuntu 20.04 LTS上&#xff0c;MySQL 8.0默认使用auth_socket插件进行身份验证&#xff0c;可能存在意想不到的情况。 一、auth_socket插件 在使用sudo mysql或通过sudo切换用户后执行任何MySQL命令时&#xff0c;不需要输入密码或错误密码都可以正常登入mysql数据库&…

使用Gitee Go流水线部署个人项目到服务器指南

使用Gitee Go流水线部署个人项目到服务器指南 前言&#xff01;&#xff01;&#xff01; 本文解决的问题&#xff1a; 你有一台ECS服务器&#xff0c;你在上面部署了一个Java服务也就是一个jar&#xff0c;你觉着你每次手动本地打包&#xff0c;上传&#xff0c;在通过命令去…

BlockChain.java

BlockChain 区块链&#xff0c;举个栗子 注意啦&#xff0c;列子里面的hashcode相等&#xff0c;但是字符串是不一样的哦&#xff0c;之前有记录这个问题 String.hashCode()-CSDN博客

【技术简析】触觉智能RK3506 Linux星闪网关开发板:重新定义工业物联新标杆

在工业智能化与物联网深度融合的今天&#xff0c;深圳触觉智能推出首款搭载瑞芯微RK3506芯片的Linux星闪网关开发板&#xff0c;为大家技术解析。 RK3506-国产芯的硬核实力 作为瑞芯微2024年第四季度推出的入门级工业芯片平台&#xff0c;RK3506以三核Cortex-A7&#xff08;1.…

YOLO-UniOW: 高效通用开放世界目标检测模型【附论文与源码】

《------往期经典推荐------》 一、AI应用软件开发实战专栏【链接】 项目名称项目名称1.【人脸识别与管理系统开发】2.【车牌识别与自动收费管理系统开发】3.【手势识别系统开发】4.【人脸面部活体检测系统开发】5.【图片风格快速迁移软件开发】6.【人脸表表情识别系统】7.【…

面向对象(进阶)(‘封装‘,‘多态‘,‘对象属性‘,‘类属性‘,‘类方法‘,‘对象方法‘及其应用场景)

‘封装’,多态’及其应用场景 一, 封装及其应用场景 封装的定义 属于面向对象的三大特征之一, 就是隐藏对象的属性和现实细节, 仅对外提供公共的访问方式.(我们学的 函数, 类, 都是封装的体现). 封装的格式 __属性名 __属性名()封装的好处和弊端 好处 提高代码的安全性.…

算法模型从入门到起飞系列——广度优先遍历(BFS)

文章目录 前言一、广度优先遍历&#xff08;BFS&#xff09;简介1.1 广度优先遍历&#xff08;BFS&#xff09;的特点1.2 广度优先遍历&#xff08;BFS&#xff09;的要素 二、广度优先遍历&#xff08;BFS&#xff09;& 深度优先遍历&#xff08;DFS&#xff09;2.1 广度优…

<项目> 主从Reactor模型的高并发服务器

目录 Reactor 概念 分类 单Reactor单线程 单Reactor多线程 多Reactor多线程 项目介绍 项目规划 模块关系 实现 TimerWheel -- 时间轮定时器 定时器系统调用 时间轮设计 通用类型Any Buffer Socket Channel Poller EventLoop&#xff08;核心&#xff09; eventfd 设计思路 …

注意力机制,本质上是在做什么?

本文以自注意机制为例&#xff0c;输入一个4*4的矩阵 如下&#xff1a; input_datatorch.tensor([[1,2,3,4], [5,6,7,8], [9,10,11,12], [13,14,15,16] ],dtypetorch.float) 得到Q和K的转置如下。 此时&#xff0c;计算QK^T ,得到如下结果 第一行第一个位置就是第一条样本和第…

使用Python在Word中创建、读取和删除列表 - 详解

目录 工具与设置 Python在Word中创建列表 使用默认样式创建有序&#xff08;编号&#xff09;列表 使用默认样式创建无序&#xff08;项目符号&#xff09;列表 创建多级列表 使用自定义样式创建列表 Python读取Word中的列表 Python从Word中删除列表 在Word中&#xff…

右键添加:新建HTML模板文件

使用注册表给Windows右键添加:新建HTML文档模板的功能_注册表右键新建-CSDN博客 新建文件有了&#xff0c;但是没有引用模板文件&#xff0c;是空文件。 默认改成 htmlfile 模板成功

Windows10配置OpenJDK11

下载 # 华为OpenJDK镜像源 https://mirrors.huaweicloud.com/openjdk/11.0.2/解压 # 解压后至于C:\Dev\Env\Java\jdk-11.0.2目录下 https://mirrors.huaweicloud.com/openjdk/11.0.2/openjdk-11.0.2_windows-x64_bin.zip编译安装 # 以管理员身份运行 CMD命令提示符 并进入JD…

统一开放世界与开放词汇检测:YOLO-UniOW无需增量学习的高效通用开放世界目标检测框架

目录 一、摘要 二、引言 三、相关工作 开放词汇对象检测 开放世界目标检测 参数高效学习 四、高效通用的开放世界目标检测 问题定义 高效的自适应决策学习 开放世界通配符学习 五、Coovally AI模型训练与应用平台 六、实验 数据集 评价指标 实施细节 定量结果 …

如何给商品一键换色?图生生AI,告别繁琐修图

在电商竞争日益激烈的今天&#xff0c;商品图片的视觉效果直接影响着消费者的购买决策。而商品颜色的展示&#xff0c;更是重中之重&#xff01;传统的图片换色方式&#xff0c;往往需要耗费设计师大量的时间和精力&#xff0c;从抠图到调色&#xff0c;再到细节调整&#xff0…

练习-班级活动(map存储键值对)

问题描述 小明的老师准备组织一次班级活动。班上一共有 n 名 (n 为偶数) 同学&#xff0c;老师想把所有的同学进行分组&#xff0c;每两名同学一组。为了公平&#xff0c;老师给每名同学随机分配了一个 n 以内的正整数作为 id&#xff0c;第 i 名同学的 id 为 ai​。 老师希望…

OpenHarmony 开源鸿蒙北向开发——hdc工具安装

hdc&#xff08;OpenHarmony Device Connector&#xff09;是为开发人员提供的用于设备连接调试的命令行工具&#xff0c;该工具需支持部署在 Windows/Linux/Mac 等系统上与 OpenHarmony 设备&#xff08;或模拟器&#xff09;进行连接调试通信。简单来讲&#xff0c;hdc 是 Op…

buu-bjdctf_2020_babystack2-好久不见51

整数溢出漏洞 将nbytes设置为-1就会回绕&#xff0c;变成超大整数 从而实现栈溢出漏洞 环境有问题 from pwn import *# 连接到远程服务器 p remote("node5.buuoj.cn", 28526)# 定义后门地址 backdoor 0x400726# 发送初始输入 p.sendlineafter(b"your name…

【Java SE】抽象类/方法、模板设计模式

目录 1.抽象类/方法 1.1 基本介绍 1.2 语法格式 1.3 使用细节 2. 模板设计模式&#xff08;抽象类使用场景&#xff09; 2.1 基本介绍 2.2 具体例子 1.抽象类/方法 1.1 基本介绍 ① 当父类的某些方法&#xff0c;需要声明&#xff0c;但是又不确定如何实现时&#xff…

Unix 域套接字(本地套接字)

Unix 域套接字&#xff08;Unix Domain Sockets&#xff09;&#xff0c;也称为本地套接字&#xff08;Local Sockets&#xff09;&#xff0c;是一种用于同一主机上进程间通信&#xff08;IPC&#xff09;的机制。Unix 域套接字提供了一种高效的进程间通信方式&#xff0c;它利…

Nordic nRF 蓝牙的 Direct Test Mode (DTM) 测试介绍

目录 概述 1. 核心物理层参数 1.1 射频频率 (RF Channel Frequency) 1.2 发射功率 (TX Power) 1.3 调制方式 (Modulation) 1.4 数据包类型 (Packet Type) 1.5 测试模式 (Test Mode) 2. 参数配置方法 2.1 通过 HCI 命令配置 2.2 示例&#xff08;nRF52 系列&#xff0…