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

爬虫入门re+bs4

目录

前言

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.kler.cn/a/599087.html

相关文章:

  • 构建高效的LinkedIn图像爬取工具
  • 《Operating System Concepts》阅读笔记:p460-p4470
  • stc8g1k08a+cd4017红绿灯
  • Linux 文件操作-文件IO函数2- write向文件写入数据、read从文件读取数据、lseek重定位文件描述符的偏移量的验证
  • (UI自动化测试web端)第二篇:元素定位的方法_xpath路径定位
  • 记录 macOS 上使用 Homebrew 安装的软件
  • 批量删除或替换多个 PPT 文档中的首页、尾页或其它任意范围的页
  • 【实战指南】用MongoDB存储文档和图片等大文件(Java实现)
  • EasyRTC嵌入式音视频通话SDK:微信生态支持、轻量化架构与跨平台兼容性(Linix/Windows/ARM/Android/iOS/LiteOS)
  • Windows安装Jenkins配置Allure踩坑,必须单独配置当前windows系统为新的node节点,才可在工具位置中指定节点服务器allure的位置
  • and滚动下拉加载
  • 【无标题】vue项目,浏览器打印时,永远只显示一页的问题
  • JSX入门
  • 第31章:Istio安全:mTLS与服务间身份认证
  • Python爬虫获取Shopee店铺的所有商品?
  • git使用经验(一)
  • 算法方法快速回顾
  • leetcode 的T5 最长回文字符串
  • 【Linux之Shell脚本实战】Linux服务器输出美观漂亮的html巡检报告
  • 4.4 前缀和专题:LeetCode 238. 除自身以外数组的乘积