0. 引言

爬虫常用技术

💡数据抓取技术

HTTP请求库(如Python的requestsaiohttp)用于发送网络请求,支持GET/POST等方法。动态页面抓取依赖无头浏览器(如SeleniumPlaywright)或直接调用页面API接口。

💡解析技术

HTML解析常用BeautifulSouplxml,XPath和CSS选择器用于精准定位元素。JSON数据使用内置库或jsonpath处理,正则表达式(re模块)适合非结构化文本提取。

💡反反爬策略

设置随机User-Agent和IP代理池(免费/付费服务)绕过基础封锁。模拟登录需处理Cookies/Session,验证码识别可借助OCR工具(如Tesseract)或第三方打码平台。动态渲染页面通过控制浏览器行为规避检测。

💡数据存储

结构化数据存入MySQL/PostgreSQL,非结构化数据用MongoDB。分布式存储可选HBase/Cassandra,小规模数据可导出CSV/JSON文件。云存储如AWS S3适合海量资源。

💡任务调度与并发

多线程/多进程(threadingmultiprocessing)提升效率,协程(asyncio)减少IO阻塞。分布式框架(Scrapy-Redis)支持跨节点协作,定时任务依赖APScheduler或系统级Cron。

💡增量爬取

通过数据库记录已抓取URL指纹(如MD5哈希),或对比页面更新时间戳。布隆过滤器高效去重,配合版本控制追踪数据变更。

💡日志与监控

日志模块(logging)记录异常和警告,Prometheus+Grafana监控爬虫健康状态。邮件/短信报警机制及时响应故障,关键指标包括请求成功率、数据增量等。

今天先学习 爬虫解析技术的BeautifulSoup 模块。

1. 概述

BeautifulSoup 是一个用于解析 HTML 和 XML 文档的 Python 库,提供了简单灵活的 API 用于遍历、搜索和修改文档树。本文件通过 10 个主要部分全面展示了其核心功能。

首先引入BeautifulSoup 模块

from bs4 import BeautifulSoup
import requests

2. 核心功能模块及代码示例

2.1 基础解析功能

  • 支持从字符串解析 HTML/XML 内容

  • 提供 prettify() 方法格式化输出文档结构

  • 支持多种解析器,示例中使用 html.parser

    # =============================
    # 1. 基础功能:解析HTML/XML
    # =============================
    print("===== 1. 基础解析功能 =====")
    
    # 从字符串解析 ,假定这是读取到页面内容
    html_doc = """
    <html><head><title>测试页面</title></head>
    <body>
    <p class="title"><b>小说列表</b></p>
    
    <p class="novel">科幻小说:
    <a href="http://example.com/scifi" class="book" id="scifi1">三体</a>,
    <a href="http://example.com/scifi2" class="book" id="scifi2">沙丘</a> 和
    <a href="http://example.com/scifi3" class="book" id="scifi3">星际穿越</a>
    </p>
    
    <p class="novel">奇幻小说:
    <a href="http://example.com/fantasy" class="book" id="fantasy1">魔戒</a>,
    <a href="http://example.com/fantasy2" class="book" id="fantasy2">哈利波特</a>
    </p>
    
    <div class="footer">© 2023 小说网站</div>
    </body></html>
    """
    
    soup = BeautifulSoup(html_doc, 'html.parser')
    print("解析后的HTML结构:")
    print(soup.prettify())  # 格式化输出HTML
    

2.2 标签选择器

  • 通过标签名直接访问文档元素(如 soup.title )

  • 获取标签的文本内容( string 属性)和父标签( parent 属性)

  • 支持获取标签属性(如 soup.p[‘class’] )

    # =============================
    # 2. 标签选择器
    # =============================
    print("\n===== 2. 标签选择器 =====")
    
    # 获取标题标签
    print("标题标签:", soup.title)
    print("标题文本:", soup.title.string)
    print("标题父标签:", soup.title.parent.name)
    
    # 获取第一个p标签
    print("第一个p标签:", soup.p)
    print("p标签的class:", soup.p['class'])
    
    # 获取所有a标签
    print("所有a标签:")
    for a in soup.find_all('a'):
        print(f"  {a.string}: {a['href']}")
    

2.3 CSS 选择器

  • 支持通过类名选择元素( soup.select(‘p.novel’) )

  • 支持通过 ID 选择元素( soup.select_one(‘#scifi1’) )

  • 支持层级选择( soup.select(‘body p’) )

  • 支持组合选择器和属性选择器(如 a.book[id^=“scifi”] )

    # =============================
    # 3. CSS选择器
    # =============================
    print("\n===== 3. CSS选择器 =====")
    
    # 通过class选择
    print("class为novel的p标签:")
    for p in soup.select('p.novel'):
        print(f"  {p.text.strip()}")
    
    # 通过id选择
    print("id为scifi1的a标签:", soup.select_one('#scifi1'))
    
    # 层级选择
    print("body下的p标签:")
    for p in soup.select('body p'):
        print(f"  {p.text.strip()}")
    
    # 组合选择
    print("class为book的a标签且id以scifi开头:")
    for a in soup.select('a.book[id^="scifi"]'):
        print(f"  {a.string}: {a['href']}")
    
    

2.4 标签属性操作

  • 获取标签的所有属性( attrs 属性)

  • 通过 get() 方法安全获取属性值

  • 支持修改、添加和删除标签属性

    # =============================
    # 4. 标签属性操作
    # =============================
    print("\n===== 4. 标签属性操作 =====")
    
    a_tag = soup.find('a')
    print("a标签的所有属性:", a_tag.attrs)
    print("a标签的href属性:", a_tag.get('href'))
    
    # 修改属性
    print("修改前的href:", a_tag['href'])
    a_tag['href'] = "http://example.com/new"
    print("修改后的href:", a_tag['href'])
    
    # 添加新属性
    print("添加新属性前:", a_tag.attrs)
    a_tag['new_attr'] = 'new_value'
    print("添加新属性后:", a_tag.attrs)
    
    # 删除属性
    del a_tag['new_attr']
    print("删除属性后:", a_tag.attrs)
    

2.5 文本处理

  • 获取标签的纯文本内容( text 属性)

  • 获取特定标签的字符串内容( string 属性)

  • 获取文档所有文本( get_text() 方法)

  • 遍历文档中所有非空白字符串( stripped_strings 生成器)

    # =============================
    # 5. 文本处理
    # =============================
    print("\n===== 5. 文本处理 =====")
    
    # 获取标签文本
    print("p标签的文本:", soup.p.text)
    print("p标签的字符串:", soup.p.string)
    
    # 获取多个文本
    print("所有文本内容:", soup.get_text())
    
    # 遍历所有字符串
    print("遍历所有字符串:")
    for string in soup.stripped_strings:
        print(f"  {string}")
    

2.6 导航树

  • 支持访问子节点( children 属性)和后代节点

  • 支持访问父节点( parent 属性)和祖先节点

  • 支持访问兄弟节点( next_sibling 、 previous_sibling )

  • 提供查找下一个/上一个特定标签的方法( find_next_sibling() 等)

    # =============================
    # 6. 导航树
    # =============================
    print("\n===== 6. 导航树 =====")
    
    # 子节点
    print("body的子节点数量:", len(list(soup.body.children)))
    print("body的直接子标签:")
    for child in soup.body.children:
        if child.name:
            print(f"  {child.name}")
    
    # 后代节点
    print("body下的所有a标签数量:", len(soup.body.find_all('a')))
    
    # 父节点
    print("a标签的父节点名称:", soup.a.parent.name)
    print("a标签的祖父节点名称:", soup.a.parent.parent.name)
    
    # 兄弟节点
    print("第一个p标签的下一个兄弟节点:", soup.p.next_sibling)
    print("第一个p标签的上一个兄弟节点:", soup.p.previous_sibling)
    
    # 找下一个标签节点
    print("第一个p标签的下一个标签节点:", soup.p.find_next_sibling('p'))
    

2.7 搜索功能

  • 通过标签名搜索( find_all(‘a’) )

  • 通过属性搜索(如 find_all(‘a’, class_=‘book’) )

  • 通过文本内容搜索,支持字符串和正则表达式

  • 支持列表搜索和搜索数量限制

    # =============================
    # 7. 搜索功能
    # =============================
    print("\n===== 7. 搜索功能 =====")
    
    # 通过标签名搜索
    print("所有a标签:", len(soup.find_all('a')))
    
    # 通过属性搜索
    print("class为book的a标签:", len(soup.find_all('a', class_='book')))
    print("id为scifi1的标签:", soup.find_all(id='scifi1'))
    
    # 通过文本搜索
    print("包含'三体'的标签:", soup.find_all(string='三体'))
    print("包含'小说'的标签:", soup.find_all(string=lambda text: '小说' in text))
    
    # 正则表达式搜索
    import re
    print("id以'scifi'开头的a标签:", soup.find_all('a', id=re.compile('^scifi')))
    print("href包含'scifi'的a标签:", soup.find_all('a', href=re.compile('scifi')))
    
    # 列表搜索
    print("p标签和a标签:", len(soup.find_all(['p', 'a'])))
    
    # 限制搜索数量
    print("前2个a标签:", len(soup.find_all('a', limit=2)))
    

2.8 修改文档树

  • 创建新标签( new_tag() 方法)

  • 添加标签到文档( append() 方法)

  • 在指定位置插入标签( insert_before() 方法)

  • 替换标签( replace_with() 方法)

  • 删除标签( decompose() 方法)

    # =============================
    # 8. 修改文档树
    # =============================
    print("\n===== 8. 修改文档树 =====")
    
    # 添加标签
    new_tag = soup.new_tag('a', href="http://example.com/newbook")
    new_tag.string = "新书"
    print("新创建的标签:", new_tag)
    
    soup.p.append(new_tag)
    print("添加标签后的p标签:", soup.p)
    
    # 插入标签
    before_tag = soup.find('a', id='scifi2')
    insert_tag = soup.new_tag('a', href="http://example.com/insert")
    insert_tag.string = "插入的书"
    before_tag.insert_before(insert_tag)
    print("插入标签后相关区域:", before_tag.parent.text)
    
    # 替换标签
    tag_to_replace = soup.find('a', id='fantasy1')
    new_tag = soup.new_tag('a', href="http://example.com/newfantasy")
    new_tag.string = "新奇幻"
    tag_to_replace.replace_with(new_tag)
    print("替换标签后相关区域:", new_tag.parent.text)
    
    # 删除标签
    tag_to_delete = soup.find('a', id='fantasy2')
    tag_to_delete.decompose()
    print("删除标签后相关区域:", tag_to_delete.parent.text if tag_to_delete.parent else "已删除")
    

2.9 XML 处理

  • 支持使用 XML 解析器解析 XML 文档

  • 提供与 HTML 解析相似的 API 用于处理 XML 元素

    # =============================
    # 9. 高级功能:处理XML
    # =============================
    print("\n===== 9. 处理XML =====")
    
    xml_doc = """
    <root>
      <book category="fiction">
        <title lang="en">Harry Potter</title>
        <author>J.K. Rowling</author>
        <year>2005</year>
        <price>29.99</price>
      </book>
      <book category="non-fiction">
        <title lang="en">Learning Python</title>
        <author>Mark Lutz</author>
        <year>2013</year>
        <price>39.95</price>
      </book>
    </root>
    """
    
    xml_soup = BeautifulSoup(xml_doc, 'xml')
    print("XML标题标签:", xml_soup.find('title').string)
    print("所有书籍作者:")
    for author in xml_soup.find_all('author'):
        print(f"  {author.string}")
    
    

2.10 网页爬取实战

  • 结合 requests 库获取网页内容

  • 使用 BeautifulSoup 解析网页并提取信息

  • 异常处理确保程序稳定性

    # =============================
    # 10. 实战示例:爬取网页
    # =============================
    print("\n===== 10. 爬取网页示例 =====")
    
    try:
        # 注意:这个URL只是示例
        url = 'http://www.baidu.com'
        response = requests.get(url)
        response.raise_for_status()  # 检查请求是否成功
    
        web_soup = BeautifulSoup(response.text, 'html.parser')
        print(f"从{url}获取的标题: {web_soup.title.string}")
        print("页面中的链接:")
        for link in web_soup.find_all('a', href=True):
            print(f"  {link.text.strip() or '无文本'}: {link['href']}")
    except Exception as e:
        print(f"爬取网页时出错: {e}")
        print("注:由于网络限制,此示例可能无法正常运行。")
    

3. 技术特点

  • 简单易用 :提供直观的 API,降低解析 HTML/XML 的复杂度
  • 灵活强大 :支持多种选择器和搜索方式,适应不同场景需求
  • 良好的兼容性 :支持多种解析器,可处理不规范的 HTML
  • 可扩展性 :易于与其他库(如 requests、re)结合使用

4. 应用场景

  • 网页内容提取与分析
  • 数据挖掘和爬虫开发
  • HTML/XML 文档处理和转换
  • 自动化测试和网页内容验证

5. 注意事项

  • 在处理网络资源时需添加异常处理
  • 选择合适的解析器以获得最佳性能
  • 处理大型文档时需注意内存使用
  • 遵守网站的 robots.txt 规则和相关法律法规
Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐