【Python爬虫(3)】解锁Python爬虫技能树:深入理解模块与包

ops/2025/2/22 20:36:43/

【Python爬虫】专栏简介:本专栏是 Python 爬虫领域的集大成之作,共 100 章节。从 Python 基础语法、爬虫入门知识讲起,深入探讨反爬虫、多线程、分布式等进阶技术。以大量实例为支撑,覆盖网页、图片、音频等各类数据爬取,还涉及数据处理与分析。无论是新手小白还是进阶开发者,都能从中汲取知识,助力掌握爬虫核心技能,开拓技术视野。

目录

  • 引言
  • 一、模块的导入与使用
    • 1.1 模块的基本概念
    • 1.2 导入模块的多种方式
      • 1.2.1 import 语句
      • 1.2.2 from...import 语句
      • 1.2.3 from...import * 语句
      • 1.2.4 as 别名
    • 1.3 模块搜索路径
    • 1.4 绝对导入与相对导入
      • 1.4.1 绝对导入
      • 1.4.2 相对导入
    • 1.5 循环导入问题及解决方法
    • 1.6 判断文件类型
  • 二、自定义模块的创建与分发
    • 2.1 创建自定义模块
    • 2.2 在其他脚本中使用自定义模块
    • 2.3 使用 from...import 语句导入特定函数
    • 2.4 分发自定义模块
      • 2.4.1 使用 setuptools 打
      • 2.4.2 通过 PyPI 发布
      • 2.4.3 安装自定义模块
  • 三、的结构与管理
    • 3.1 的概念与作用
    • 3.2 的结构
    • 3.3 创建
    • 3.4 导入中的模块
      • 3.4.1 import 语句导入
      • 3.4.2 from...import 语句导入
    • 3.5 的导入机制
      • 3.5.1 绝对导入
      • 3.5.2 相对导入
    • 3.6 使用__all__控制导入


引言

在Python爬虫开发中,模块的作用至关重要。通过模块,开发者可以高效地复用代码,提升开发效率,同时保持代码的整洁性和可维护性。

一、模块的导入与使用

1.1 模块的基本概念

在 Python 中,模块是代码组织的基本单元,它是一个含 Python 定义和语句的文件。模块的文件名就是模块名加上.py 扩展名。例如,我们有一个名为example.py的文件,那example就是这个模块的名称。模块的主要作用是将相关的功能代码封装在一起,提高代码的可读性、可维护性和重用性。通过使用模块,我们可以避免在不同的项目中重复编写相同的代码,同时也能使项目的结构更加清晰,易于管理。

1.2 导入模块的多种方式

1.2.1 import 语句

import语句是最常用的导入模块的方式,它用于导入整个模块。语法如下:

python">import module_name

例如,我们要导入 Python 的内置模块math,可以这样写:

python">import math

导入后,就可以使用math模块中的函数和变量了。比如计算一个数的平方根:

python">result = math.sqrt(16)
print(result)  # 输出:4.0

在这种方式下,调用模块内的函数或变量时,需要使用模块名.函数名(或模块名.变量名)的方式,这样可以明确地表明该函数或变量来自哪个模块,避免命名冲突。

1.2.2 from…import 语句

from…import语句用于从模块中导入特定的函数、类或变量。语法如下:

python">from module_name import function_name, variable_name

例如,我们只需要导入math模块中的sqrt函数,可以这样写:

python">from math import sqrt
result = sqrt(16)
print(result)  # 输出:4.0

使用这种方式导入后,在调用函数时直接使用函数名即可,不需要再加上模块名前缀,代码会更加简洁。但需要注意的是,如果多个模块中有同名的函数,使用这种方式导入可能会导致命名冲突。

1.2.3 from…import * 语句

from…import *语句用于导入模块中的所有内容(函数、类、变量等)。语法如下:

python">from module_name import *

例如:

python">from math import *
result = sqrt(16)
print(result)  # 输出:4.0

这种方式虽然方便,但不推荐在实际项目中频繁使用。因为它会将模块中的所有名称都导入到当前命名空间,可能会导致命名冲突,并且难以确定某个名称具体来自哪个模块,降低了代码的可读性和可维护性。

1.2.4 as 别名

使用as关键字可以为模块模块内的成员起一个别名。为模块起别名的语法如下:

python">import module_name as alias_name

例如,numpy是一个常用的数值计算模块,通常我们会给它起一个别名np:

python">import numpy as np
arr = np.array([1, 2, 3])
print(arr)

模块内成员起别名的语法如下:

python">from module_name import member_name as alias_name

比如,我们从math模块中导入sqrt函数,并给它起一个别名square_root:

python">from math import sqrt as square_root
result = square_root(16)
print(result)  # 输出:4.0

使用别名可以使代码更加简洁,同时在遇到模块名或成员名较长,或者需要避免命名冲突时非常有用。

1.3 模块搜索路径

当 Python 导入一个模块时,会按照一定的顺序搜索模块的位置。搜索路径存储在sys.path中,它是一个列表,含了以下几个部分:

  1. 内存中已经加载的模块(如果模块已经被导入过,会直接从内存中获取)。
  2. 内置模块空间,Python 内置的模块会首先被搜索。
  3. PYTHONPATH环境变量中指定的目录(这是一个用户自定义的环境变量,用于指定模块搜索路径)。
  4. Python 的标准库目录,例如 Python 安装目录下的lib文件夹。
  5. 第三方库安装目录,通常是site-packages目录。

我们可以通过以下代码查看当前的模块搜索路径:

python">import sys
print(sys.path)

如果我们想添加自定义的模块搜索路径,可以通过修改sys.path来实现。例如:

python">import sys
sys.path.append('/path/to/your/module')

但需要注意的是,这种方式修改的搜索路径只在当前 Python 会话中有效,程序结束后就会失效。如果需要永久添加模块搜索路径,可以通过设置PYTHONPATH环境变量来实现。

1.4 绝对导入与相对导入

1.4.1 绝对导入

绝对导入是指以执行文件所在的目录为绝对路径来导入模块。在 Python 中,通常使用import语句进行绝对导入。例如:

python">import my_module

这里的my_module是相对于 Python 解释器的模块搜索路径进行查找的。如果my_module在当前目录下,或者在sys.path中的某个目录下,就可以成功导入。绝对导入的优点是路径明确,易于理解和维护,适用于大多数情况。

1.4.2 相对导入

相对导入是指以当前模块的位置为参照,通过点的方式来简写路径导入模块。相对导入主要用于模块之间的相互导入。语法如下:

python">from. import module_name
from.. import module_name

其中,一个点(.) 表示当前模块所在的目录,两个点(…) 表示当前模块所在目录的上一级目录。例如,在一个结构中:

python">my_package/__init__.pymodule1.pysub_package/__init__.pymodule2.py

如果在module2.py中要导入module1.py,可以使用相对导入:

python">from.. import module1

相对导入的好处是在模块之间的导入更加灵活,并且可以避免在结构发生变化时,绝对路径需要频繁修改的问题。但需要注意的是,相对导入只能在内使用,不能用于导入外的模块

1.5 循环导入问题及解决方法

循环导入是指两个或多个文件之间相互导入,并且在导入过程中使用了对方名称空间中的名字。例如,有两个文件module_a.py和module_b.py:

python"># module_a.py
from module_b import func_bdef func_a():func_b()# module_b.py
from module_a import func_adef func_b():func_a()

当我们尝试运行其中任何一个文件时,都会出现循环导入的错误。这是因为在 Python 中,模块的导入是自上而下顺序执行的,当module_a.py导入module_b.py时,module_b.py又尝试导入module_a.py,此时module_a.py还没有完全加载完成,导致无法找到func_a。

解决循环导入问题的方法主要有以下几种:

  1. 重构代码结构:将相互依赖的代码提取到一个独立的模块中,让module_a.py和module_b.py都从这个独立模块中导入所需的内容,避免直接相互导入。
  2. 延迟导入:将导入语句放在函数内部,而不是模块的顶部。例如:
python"># module_a.py
def func_a():from module_b import func_bfunc_b()# module_b.py
def func_b():from module_a import func_afunc_a()

这样只有在函数被调用时才会进行导入,避免了模块加载时的循环导入问题。

  1. 使用 import 语句而不是 from…import 语句:在相互导入的模块中,使用import语句导入整个模块,而不是使用from…import语句导入特定的函数或变量。例如:
python"># module_a.py
import module_bdef func_a():module_b.func_b()# module_b.py
import module_adef func_b():module_a.func_a()

这样可以确保在导入时,模块已经被正确加载,并且可以通过模块名来访问其中的成员,避免了在导入过程中对未定义成员的访问。

1.6 判断文件类型

在 Python 中,可以通过__name__属性来判断一个文件是作为主程序运行还是被导入为模块。当一个 Python 文件作为主程序运行时,name__的值为__main;当它被导入为模块时,__name__的值为模块名。例如:

python"># test.py
def main():print("This is the main function.")if __name__ == "__main__":main()

在这个例子中,if name == “main”:这行代码判断当前文件是否是主程序。如果是,就会执行main()函数。这样的好处是,当我们将test.py作为模块导入到其他文件中时,main()函数不会被自动执行,只有在直接运行test.py时才会执行。这在模块开发中非常有用,可以方便地进行测试和调试。

二、自定义模块的创建与分发

2.1 创建自定义模块

创建自定义模块其实就是创建一个含 Python 代码的文件。在这个文件中,我们可以定义函数、类和变量等。例如,我们创建一个名为math_operations.py的模块,用于进行一些基本的数学计算:

python"># math_operations.pydef add(a, b):"""返回a和b的和"""return a + bdef subtract(a, b):"""返回a减去b的结果"""return a - bdef multiply(a, b):"""返回a和b的乘积"""return a * bdef divide(a, b):"""返回a除以b的结果"""if b == 0:raise ValueError("除数不能为零")return a / b

在这个模块中,我们定义了四个函数,分别用于加法、减法、乘法和除法运算。每个函数都有一个文档字符串(docstring),用于描述函数的功能,这是一个良好的编程习惯,有助于提高代码的可读性和可维护性。

2.2 在其他脚本中使用自定义模块

要在其他 Python 脚本中使用我们创建的自定义模块,首先需要确保模块文件(math_operations.py)与使用它的脚本在同一目录下,或者在 Python 的sys.path目录中。假设我们有一个名为main.py的脚本,希望在其中使用math_operations.py模块

python"># main.py
import math_operationsresult1 = math_operations.add(5, 3)
result2 = math_operations.subtract(5, 3)
result3 = math_operations.multiply(5, 3)
result4 = math_operations.divide(5, 3)print(f"5 + 3 = {result1}")
print(f"5 - 3 = {result2}")
print(f"5 * 3 = {result3}")
print(f"5 / 3 = {result4}")

在这个例子中,我们使用import语句导入了math_operations模块,然后通过模块名.函数名的方式调用了模块中的函数,进行数学运算并输出结果。

2.3 使用 from…import 语句导入特定函数

除了导入整个模块,我们还可以使用from…import语句从模块中导入特定的函数。这样在使用函数时,就不需要再加上模块名前缀,代码会更加简洁。例如,我们只需要使用math_operations.py模块中的add和subtract函数:

python"># main.py
from math_operations import add, subtractresult1 = add(5, 3)
result2 = subtract(5, 3)print(f"5 + 3 = {result1}")
print(f"5 - 3 = {result2}")

在这个例子中,我们使用from math_operations import add, subtract语句,从math_operations模块中导入了add和subtract函数。这样在后续的代码中,就可以直接使用add和subtract函数,而不需要加上math_operations.前缀。

2.4 分发自定义模块

2.4.1 使用 setuptools 打

如果我们希望将自己创建的自定义模块分享给其他人使用,就需要将其打。setuptools是 Python 中一个常用的打和分发工具,我们可以使用它来将自定义模块成可以发布的形式。

首先,我们需要在模块的根目录下创建一个setup.py文件,用于配置打的相关信息。假设我们的模块目录结构如下:

python">my_project/math_operations.pysetup.py

在setup.py文件中,我们可以编写如下内容:

python">from setuptools import setup, find_packagessetup(name='math_operations_package',  # 的名称version='1.0.0',  # 版本号author='Your Name',  # 作者author_email='your_email@example.com',  # 作者邮箱description='A package for basic math operations',  # 的描述packages=find_packages(),  # 自动查找install_requires=[],  # 依赖项
)

在这个setup.py文件中:

  • name指定了的名称,这是在安装和发布时使用的名称。
  • version指定了的版本号,遵循语义化版本号规范,方便管理版本。
  • author和author_email分别指定了作者的姓名和邮箱。
  • description是对的简短描述,用于在发布时介绍的功能。
  • packages=find_packages()会自动查找当前目录下的所有,find_packages函数会递归查找含__init__.py文件的目录,并将其作为含进来。
  • install_requires用于指定的依赖项,如果你的模块依赖其他第三方库,可以在这里列出。

配置好setup.py文件后,我们可以在命令行中执行打命令:

python">python setup.py sdist

这个命令会在当前目录下生成一个dist目录,里面含了打好的源文件压缩(例如math_operations_package-1.0.0.tar.gz)。

2.4.2 通过 PyPI 发布

PyPI(Python Package Index)是 Python 的官方索引,我们可以将打好的模块发布到 PyPI 上,让其他人可以通过pip命令轻松安装。发布到 PyPI 的步骤如下:

  1. 注册账号:首先,需要在 PyPI 官网(https://pypi.org/)上注册一个账号。
  2. 配置.pypirc文件:在用户主目录下创建一个.pypirc文件(如果是 Windows 系统,在C:\Users\你的用户名目录下),用于存储 PyPI 的认证信息。文件内容如下:
python">[distutils]
index-servers =pypi[pypi]
username = your_username
password = your_password

将your_username和your_password替换为你在 PyPI 注册的用户名和密码。为了安全起见,也可以使用 API token 来代替密码。

  1. 注册和上传:在命令行中执行以下命令:
python">python setup.py register
python setup.py sdist upload

python setup.py register命令会将你的信息注册到 PyPI 上,python setup.py sdist upload命令会将打好的源文件上传到 PyPI。

发布成功后,其他人就可以通过以下命令安装你的模块

python">pip install math_operations_package

2.4.3 安装自定义模块

当用户下载了我们发布的模块后,可以通过以下步骤进行安装:

  1. 解压下载的,例如math_operations_package-1.0.0.tar.gz。
  2. 进入解压后的目录,在命令行中执行:
python">python setup.py install

这个命令会将模块安装到 Python 的site-packages目录下,这样在任何 Python 脚本中都可以导入和使用该模块了。

三、的结构与管理

3.1 的概念与作用

在 Python 中,是一种用于组织和管理相关模块的机制。它本质上是一个含多个模块的目录,并且这个目录中必须含一个特殊的__init__.py文件(在 Python 3.3 及以上版本,如果目录中只含 Python 模块init.py文件可以省略,但为了兼容性和明确性,通常还是建议保留),用于标识该目录是一个 Python 的主要作用是提供了一种层次化的方式来组织和管理相关模块,使得大型项目的代码结构更加清晰、易于维护。

例如,在一个大型的 Web 开发项目中,可能会有处理用户认证的模块、处理数据库操作的模块、处理页面渲染的模块等。将这些相关的模块组织在不同的中,可以更好地管理和维护代码,同时也方便其他开发者理解和使用。还可以避免模块命名冲突,因为不同中的模块可以有相同的名称,只要它们的名不同即可。

3.2 的结构

一个典型的 Python 结构如下:

python">my_package/__init__.pymodule1.pymodule2.pysub_package/__init__.pymodule3.py

在这个结构中:

  • my_package是的根目录,它的名称就是名。
  • init.py文件是的标识,它可以为空,也可以含一些初始化代码,比如导入内的其他模块、设置的元数据等。当被导入时,init.py文件会被自动执行。
  • module1.py和module2.py是中的模块文件,它们含了具体的 Python 代码,如函数、类、变量等定义。
  • sub_package是my_package的子,它也是一个目录,同样含一个__init__.py文件,用于标识它是一个子。子可以进一步组织相关的模块,形成更复杂的层次结构。
  • module3.py是子sub_package中的模块文件。

3.3 创建

创建一个 Python 可以按照以下步骤进行:

  1. 创建目录:首先,创建一个新的目录,这个目录的名称就是的名称。例如,我们要创建一个名为my_math_package的,就可以在合适的位置创建一个名为my_math_package的文件夹。
  2. 添加__init__.py 文件:在创建好的目录中,添加一个__init__.py文件。这个文件可以是空文件,也可以含一些初始化代码。在 Python 3 中,如果中只含 Python 模块init.py文件可以省略,但为了兼容性和明确性,通常建议保留。
  3. 添加模块文件和子(可选):在目录中,可以根据需要添加模块文件(.py文件),以及子含__init__.py文件的子目录)。例如,我们在my_math_package中添加一个basic_operations.py模块,用于实现基本的数学运算,代码如下:
python"># my_math_package/basic_operations.pydef add(a, b):return a + bdef subtract(a, b):return a - b

假设我们还想在中创建一个子advanced_operations,用于实现一些高级的数学运算,子的结构如下:

python">my_math_package/__init__.pybasic_operations.pyadvanced_operations/__init__.pytrigonometry.py

在trigonometry.py模块中,我们可以实现一些三角函数相关的功能,代码如下:

python"># my_math_package/advanced_operations/trigonometry.pyimport mathdef sine(x):return math.sin(x)def cosine(x):return math.cos(x)

3.4 导入中的模块

3.4.1 import 语句导入

使用import语句可以导入中的模块。语法如下:

python">import package_name.module_name

例如,要导入我们前面创建的my_math_package中的basic_operations模块,可以这样写:

python">import my_math_package.basic_operationsresult1 = my_math_package.basic_operations.add(5, 3)
result2 = my_math_package.basic_operations.subtract(5, 3)print(f"5 + 3 = {result1}")
print(f"5 - 3 = {result2}")

在这种方式下,调用模块内的函数或变量时,需要使用名.模块名.函数名(或名.模块名.变量名)的方式,这样可以明确地表明该函数或变量来自哪个中的哪个模块,避免命名冲突。

3.4.2 from…import 语句导入

使用from…import语句可以从中导入特定的模块模块中的特定函数、类等。语法如下:

python">from package_name import module_name
from package_name.module_name import function_name, class_name

例如,从my_math_package中导入basic_operations模块

python">from my_math_package import basic_operationsresult1 = basic_operations.add(5, 3)
result2 = basic_operations.subtract(5, 3)print(f"5 + 3 = {result1}")
print(f"5 - 3 = {result2}")

这种方式导入后,调用模块内的函数或变量时,直接使用模块名.函数名(或模块名.变量名)即可,不需要再加上名前缀。

如果只需要导入模块中的特定函数,例如从basic_operations模块中导入add函数:

python">from my_math_package.basic_operations import addresult = add(5, 3)
print(f"5 + 3 = {result}")

这样导入后,调用函数时直接使用函数名即可,代码更加简洁。但需要注意的是,如果多个模块中有同名的函数,使用这种方式导入可能会导致命名冲突。

3.5 的导入机制

3.5.1 绝对导入

绝对导入是指在中使用完整的路径来导入模块。在 Python 中,通常使用import语句进行绝对导入。例如:

python">import my_package.module1
from my_package.sub_package import module3

这里的my_package和my_package.sub_package都是相对于 Python 解释器的模块搜索路径进行查找的。如果my_package和my_package.sub_package在sys.path中的某个目录下,就可以成功导入。绝对导入的优点是路径明确,易于理解和维护,适用于大多数情况。

3.5.2 相对导入

相对导入是指在内部使用相对路径来导入模块。相对导入使用点号(.) 来表示当前目录和上级目录。语法如下:

python">from. import module_name
from.. import module_name
from.sub_package import module_name

其中,一个点(.) 表示当前模块所在的目录,两个点(…) 表示当前模块所在目录的上一级目录。例如,在my_math_package/advanced_operations/trigonometry.py模块中,如果要导入my_math_package/basic_operations.py模块,可以使用相对导入:

python">from.. import basic_operationsresult = basic_operations.add(1, 2)
print(result)

相对导入的好处是在模块之间的导入更加灵活,并且可以避免在结构发生变化时,绝对路径需要频繁修改的问题。但需要注意的是,相对导入只能在内使用,不能用于导入外的模块

3.6 使用__all__控制导入

在__init__.py文件中,可以使用__all__列表来控制from package_name import *语句导入的模块。__all__是一个列表,其中含的是模块名的字符串。只有在__all__列表中的模块,才会在使用from package_name import *语句时被导入。

例如,在my_math_package/init.py文件中,我们可以这样设置__all__:

python">__all__ = ['basic_operations', 'advanced_operations']

这样,当在其他脚本中使用from my_math_package import *语句时,只会导入basic_operations和advanced_operations模块,而不会导入my_math_package中的其他模块(如果有的话)。如果__init__.py文件中没有定义__all__,则from package_name import 语句不会导入任何模块(除了__init__.py文件中显式导入的模块)。这是为了避免在使用导入时,意外导入过多不必要的模块,导致命名空间混乱。通过合理设置__all__,可以更好地控制的导入行为,提高代码的可读性和可维护性。


http://www.ppmy.cn/ops/159805.html

相关文章

腾讯云DeepSeek大模型应用搭建指南

📍2月8日,腾讯云宣布上线DeepSeek-R1及V3原版模型API接口,通过强大的公有云服务,腾讯云可以为用户提供稳定优质的服务。同时,腾讯云旗下大模型知识应用开发平台知识引擎也接入了DeepSeek-R1及V3这两款模型,…

小米平板怎么和电脑共享屏幕

最近尝试使用小米平板和电脑屏幕分屏互联 发现是需要做特殊处理的,需要下载一款电脑安装包:小米妙享 关于这个安装包,想吐槽的是: 没有找到官网渠道,是通过其他网络方式查到下载的 不附录链接,原因是因为地…

Spring Cloud — 深入了解Eureka、Ribbon及Feign

Eureka 负责服务注册与发现;Ribbon负责负载均衡;Feign简化了Web服务客户端调用方式。这三个组件可以协同工作,共同构建稳定、高效的微服务架构。 1 Eureka 分布式系统的CAP定理: 一致性(Consistency)&am…

【我与开源】 | 我的开源印象

嘿~ 你好!我是董吉甫,一名开源志愿者,目前就职于南京一家小企业,担任产品经理一职。很荣幸以这样的方式为您分享一些我的开源历程。希望通过这段文字,能让您对我所参与的开源有一些了解和印象。 提到开源(O…

【前端框架】Vue3 中 `setup` 函数的作用和使用方式

在 Vue 3 里,setup 函数是组合式 API 的核心入口,为开发者提供了更灵活、高效的组件逻辑组织方式。以下为你详细介绍其作用和使用方式: 作用 1. 初始化响应式数据 在 setup 函数中,我们能够使用 ref 和 reactive 等函数来创建响…

【基础架构篇十五】《DeepSeek权限控制:RBAC+ABAC混合鉴权模型》

某天深夜,电商平台运营总监误触按钮,把价值千万的优惠券设置成全员可领。当你想追究责任时,却发现系统日志写着"操作人:admin"。这血淋淋的事故告诉我们:权限控制不是选择题,而是生死攸关的必答题。本文将深挖DeepSeek的RBAC+ABAC混合鉴权体系,看看他们如何做…

【力扣】994.腐烂的橘子

AC截图 题目 思路 1. 初始化 首先遍历整个网格: 找出所有的初始腐烂橘子,并将它们的位置加入队列。 统计新鲜橘子的数量。 2. 特殊情况处理 如果网格中没有任何新鲜橘子,直接返回 0,因为不需要任何时间让橘子腐烂。 3. 广度…

cesium基础设置

cesium官网下载&#xff1a;https://cesium.com/downloads/ 1.安装cesium 选择下载到本地使用&#xff0c;或者通过npm下载到项目中 2.代码书写 &#xff08;1&#xff09;创建容器 <div id"cesiumContainer" style"width: 100%; height: 100%"><…