0

0

Python实现HTML链接的迭代抓取与跟踪

聖光之護

聖光之護

发布时间:2025-11-18 11:53:02

|

888人浏览过

|

来源于php中文网

原创

python实现html链接的迭代抓取与跟踪

本教程详细阐述了如何使用Python的`urllib`和`BeautifulSoup`库,实现对网页HTML内容中特定链接的迭代抓取和跟踪。文章重点解决了在多层链接跟踪过程中,如何正确更新下一轮抓取的URL,避免重复处理初始页面,并提供了清晰的代码示例、错误分析及最佳实践,旨在帮助开发者构建高效稳定的网页爬虫

引言:网页链接迭代抓取的需求

网络爬虫和数据抓取领域,一个常见的任务是不仅抓取单个页面,还需要根据页面内容(尤其是链接)进一步访问其他页面。例如,从一个起始页开始,找到第三个链接,访问该链接指向的页面,然后从新页面中再次找到第三个链接并访问,如此循环往复。这个过程涉及到HTML内容的获取、解析、链接提取以及关键的URL更新机制。

核心工具介绍

我们将使用以下两个Python库来完成任务:

  • urllib.request: Python标准库的一部分,用于打开和读取URLs。
  • BeautifulSoup: 一个强大的库,用于从HTML或XML文件中提取数据。它能够将复杂的HTML文档转换成一个Python对象,方便我们进行导航、搜索和修改。

如果尚未安装BeautifulSoup,可以使用pip进行安装:

立即学习Python免费学习笔记(深入)”;

pip install beautifulsoup4

实现原理与常见陷阱

实现链接迭代抓取的核心在于:

  1. 获取页面内容: 使用urllib打开一个URL并读取其HTML。
  2. 解析HTML: 使用BeautifulSoup将HTML字符串解析为可操作的对象。
  3. 提取链接: 找到页面中所有的标签,并从中获取href属性。
  4. 更新URL: 根据业务逻辑(例如,选择第N个链接),将下一个要访问的URL更新到循环变量中。

一个常见的陷阱是URL更新不当。如果每次循环都从初始URL开始,或者在内部循环中错误地重置了用于外部循环的URL变量,就会导致爬虫行为异常,例如反复抓取同一个页面,或者无法按预期路径深入。

示例代码与问题分析

考虑一个场景:我们需要从一个起始URL开始,连续访问其页面上的第3个链接,重复此过程4次。

以下是一个可能出现问题的初始代码结构(与原问题描述类似):

AI Content Detector
AI Content Detector

Writer推出的AI内容检测工具

下载
import urllib.request, urllib.parse, urllib.error
from urllib.parse import urljoin
from bs4 import BeautifulSoup

# blanc list - 列表在外部定义
l = []

# starting url
url = input('Enter URL: ')
if len(url) < 1:
    url = 'http://py4e-data.dr-chuck.net/known_by_Fikret.html'

# loop for 4 iterations
for _ in range(4):
    html = urllib.request.urlopen(url).read()    # open url
    soup = BeautifulSoup(html, 'html.parser')    # parse through BeautifulSoup
    tags = soup('a')    # extract tags

    for tag in tags:
        # 链接提取和URL更新都在内层循环中
        url = tag.get('href', None)    # extract links from tags
        l.append(url)    # add the links to a list
        url = l[2:3]    # slice the list to extract the 3rd url
        url = ' '.join(str(e) for e in url)    # change the type to string
    print(url)

这段代码的预期输出是每次都访问新的页面,但实际输出却是:

http://py4e-data.dr-chuck.net/known_by_Montgomery.html
http://py4e-data.dr-chuck.net/known_by_Montgomery.html
http://py4e-data.dr-chuck.net/known_by_Montgomery.html
http://py4e-data.dr-chuck.net/known_by_Montgomery.html

这表明爬虫每次都回到了同一个页面。问题在于:

  1. l = [] 列表的定义位置:它在外部循环之外,这意味着l会不断累积所有页面上的链接,而不是只包含当前页面的链接。
  2. url 变量的更新逻辑:url = tag.get('href', None) 和 url = l[2:3] 都发生在内层循环中。当内层循环遍历每个标签时,url变量会被不断覆盖。虽然l.append(url)将链接添加到列表,但url = l[2:3]在每次内层循环迭代时都会尝试从(可能不完整的)l中提取第三个链接,并将其赋值给url。最终,当内层循环结束后,url变量将保存当前页面所有链接中第三个链接的字符串形式。由于l在外部循环外没有重置,或者说,即使重置了,这种赋值方式也容易混淆。

正确的迭代抓取实现

为了解决上述问题,我们需要确保:

  1. 每次处理新页面时,用于收集链接的列表是空的,只包含当前页面的链接。
  2. url变量在外部循环的每次迭代结束时,被正确地更新为下一个要访问的URL,而不是在内层循环中被随意覆盖。

以下是修正后的代码示例,它将正确实现迭代抓取:

import urllib.request, urllib.parse, urllib.error
from urllib.parse import urljoin # 导入urljoin,用于处理相对URL
from bs4 import BeautifulSoup

# starting url
url = input('Enter URL: ')
if len(url) < 1:
    url = 'http://py4e-data.dr-chuck.net/known_by_Fikret.html'

# loop for 4 iterations
for i in range(4): # 使用i来表示当前是第几次迭代
    # 每次外层循环开始时,清空链接列表,确保只收集当前页面的链接
    l = [] 

    print(f"--- 访问第 {i+1} 次,当前URL: {url} ---")
    try:
        html = urllib.request.urlopen(url).read()    # open url
        soup = BeautifulSoup(html, 'html.parser')    # parse through BeautifulSoup
        tags = soup('a')    # extract tags

        # 遍历所有链接,将它们添加到当前页面的链接列表中
        for tag in tags:
            href = tag.get('href', None)
            if href: # 确保链接存在
                # 使用urljoin处理相对URL,生成绝对URL
                absolute_url = urljoin(url, href) 
                l.append(absolute_url)

        # 确保有足够的链接来选择第三个链接
        if len(l) > 2:
            # 更新url变量为下一个要访问的链接(列表的第3个元素,索引为2)
            # 这会在内层循环结束后执行,确保url被正确赋值给下一个迭代
            url = l[2] 
            print(f"找到第3个链接: {url}")
        else:
            print("当前页面链接不足3个,无法继续跟踪。")
            break # 退出循环

    except Exception as e:
        print(f"访问URL {url} 时发生错误: {e}")
        break # 发生错误时退出循环

print("\n--- 迭代抓取完成 ---")

代码解释:

  1. l = [] 的位置:现在它被放置在外部for循环的内部。这意味着在每次新的迭代(即每次访问新页面)开始时,l都会被重置为空列表,确保我们只收集当前页面的链接。
  2. 链接收集与更新
    • 内层for tag in tags:循环负责将当前页面上的所有链接提取出来,并使用urljoin(url, href)将其转换为绝对URL,然后添加到l列表中。
    • 在内层循环结束之后,我们检查l列表是否包含至少3个链接(索引2)。
    • 如果满足条件,url = l[2]这行代码将url变量更新为当前页面上的第三个链接。这个更新发生在外部循环的当前迭代结束前,确保了下一次外部循环迭代会使用这个新的url。
    • 添加了错误处理(try-except)和链接数量检查,提高了代码的健壮性。
    • urljoin的使用是关键,它能将页面上的相对路径链接(如/path/to/page.html)转换为完整的绝对URL(如http://example.com/path/to/page.html),避免了访问无效链接。

运行结果(与期望输出一致):

--- 访问第 1 次,当前URL: http://py4e-data.dr-chuck.net/known_by_Fikret.html ---
找到第3个链接: http://py4e-data.dr-chuck.net/known_by_Montgomery.html
--- 访问第 2 次,当前URL: http://py4e-data.dr-chuck.net/known_by_Montgomery.html ---
找到第3个链接: http://py4e-data.dr-chuck.net/known_by_Mhairade.html
--- 访问第 3 次,当前URL: http://py4e-data.dr-chuck.net/known_by_Mhairade.html ---
找到第3个链接: http://py4e-data.dr-chuck.net/known_by_Butchi.html
--- 访问第 4 次,当前URL: http://py4e-data.dr-chuck.net/known_by_Butchi.html ---
找到第3个链接: http://py4e-data.dr-chuck.net/known_by_Anayah.html

--- 迭代抓取完成 ---

最佳实践与注意事项

  1. 错误处理: 在实际的爬虫中,网络请求可能会失败(例如,404错误、连接超时)。务必使用try-except块来捕获urllib.request.URLError或urllib.request.HTTPError等异常,以提高程序的健壮性。
  2. 相对URL与绝对URL: 网页中的链接可以是相对路径(如/about)或绝对路径(如http://example.com/about)。使用urllib.parse.urljoin(base_url, relative_url)可以可靠地将相对URL转换为绝对URL,确保后续访问的正确性。
  3. 链接选择策略: 本教程选择的是第3个链接。在实际应用中,你可能需要更复杂的选择逻辑,例如根据链接文本、CSS类名、ID或正则表达式来匹配目标链接。
  4. 循环终止条件: 除了固定次数的循环,还可以设置其他终止条件,例如:
    • 达到某个最大深度。
    • 找到特定内容的页面。
    • 遇到已经访问过的URL(避免无限循环和重复抓取,需要维护一个已访问URL的集合)。
    • 页面上没有足够的链接可供选择。
  5. 爬虫礼仪 (Robots.txt与延迟):
    • 在抓取网站之前,检查其robots.txt文件,了解哪些页面允许抓取。
    • 在每次请求之间添加适当的延迟(例如,使用time.sleep()),以避免对服务器造成过大压力,防止IP被封禁。
  6. 用户代理 (User-Agent): 某些网站会检查请求的User-Agent头。模拟一个常见的浏览器User-Agent可以帮助避免被识别为爬虫而拒绝访问。

总结

通过本教程,我们学习了如何使用

相关专题

更多
python开发工具
python开发工具

php中文网为大家提供各种python开发工具,好的开发工具,可帮助开发者攻克编程学习中的基础障碍,理解每一行源代码在程序执行时在计算机中的过程。php中文网还为大家带来python相关课程以及相关文章等内容,供大家免费下载使用。

753

2023.06.15

python打包成可执行文件
python打包成可执行文件

本专题为大家带来python打包成可执行文件相关的文章,大家可以免费的下载体验。

636

2023.07.20

python能做什么
python能做什么

python能做的有:可用于开发基于控制台的应用程序、多媒体部分开发、用于开发基于Web的应用程序、使用python处理数据、系统编程等等。本专题为大家提供python相关的各种文章、以及下载和课程。

758

2023.07.25

format在python中的用法
format在python中的用法

Python中的format是一种字符串格式化方法,用于将变量或值插入到字符串中的占位符位置。通过format方法,我们可以动态地构建字符串,使其包含不同值。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

618

2023.07.31

python教程
python教程

Python已成为一门网红语言,即使是在非编程开发者当中,也掀起了一股学习的热潮。本专题为大家带来python教程的相关文章,大家可以免费体验学习。

1262

2023.08.03

python环境变量的配置
python环境变量的配置

Python是一种流行的编程语言,被广泛用于软件开发、数据分析和科学计算等领域。在安装Python之后,我们需要配置环境变量,以便在任何位置都能够访问Python的可执行文件。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

547

2023.08.04

python eval
python eval

eval函数是Python中一个非常强大的函数,它可以将字符串作为Python代码进行执行,实现动态编程的效果。然而,由于其潜在的安全风险和性能问题,需要谨慎使用。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

577

2023.08.04

scratch和python区别
scratch和python区别

scratch和python的区别:1、scratch是一种专为初学者设计的图形化编程语言,python是一种文本编程语言;2、scratch使用的是基于积木的编程语法,python采用更加传统的文本编程语法等等。本专题为大家提供scratch和python相关的文章、下载、课程内容,供大家免费下载体验。

707

2023.08.11

Java 桌面应用开发(JavaFX 实战)
Java 桌面应用开发(JavaFX 实战)

本专题系统讲解 Java 在桌面应用开发领域的实战应用,重点围绕 JavaFX 框架,涵盖界面布局、控件使用、事件处理、FXML、样式美化(CSS)、多线程与UI响应优化,以及桌面应用的打包与发布。通过完整示例项目,帮助学习者掌握 使用 Java 构建现代化、跨平台桌面应用程序的核心能力。

36

2026.01.14

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Sass 教程
Sass 教程

共14课时 | 0.8万人学习

Bootstrap 5教程
Bootstrap 5教程

共46课时 | 2.9万人学习

CSS教程
CSS教程

共754课时 | 19万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号