1. 请解释 Python 中的模块和包
回答
在 Python 中,模块和包是组织代码的重要工具,它们有助于代码的重用和结构化。
Python 面试涵盖模块包管理、字符串处理、面向对象特性、爬虫技术、框架应用、装饰器与异步编程等核心知识点。文章通过代码示例详解各概念原理,指出常见误区与注意事项,并列举面试官可能追问的深入问题,旨在帮助求职者系统掌握 Python 基础与进阶技能,提升面试表现。

在 Python 中,模块和包是组织代码的重要工具,它们有助于代码的重用和结构化。
模块是一个包含 Python 代码的文件,通常以 .py 作为文件扩展名。模块可以定义函数、类和变量,也可以包含可执行的代码。通过模块,可以将相关的功能分组到一个文件中,从而使得代码更加结构化和可维护。
使用模块:在其他 Python 文件或解释器中,可以使用 import 语句导入模块:
import mymodule
print(mymodule.greet("Alice"))
print(mymodule.pi)
创建模块:你可以创建一个 Python 文件(例如 mymodule.py),并在其中定义函数或变量:
# mymodule.py
def greet(name):
return f"Hello, {name}!"
pi = 3.14159
包是一种组织多个模块的方式。它实际上是一个包含多个模块的文件夹,同时该文件夹下应该包含一个子文件 __init__.py(可以是空的),这个文件告诉 Python 将该文件夹视为一个包。包可以帮助层次化地组织模块,从而便于管理较大的项目。
使用包:在其他文件中,可以使用 import 语句导入包中的模块:
from mypackage import module1, module2
print(module1.func1())
print(module2.func2())
创建包:你可以创建一个文件夹,例如 mypackage,并在其中放入多个模块(如 module1.py 和 module2.py),同时在文件夹下创建一个 __init__.py 文件:
mypackage/
__init__.py
module1.py
module2.py
module1.py 可以是:
def func1():
return "Function 1"
module2.py 可以是:
def func2():
return "Function 2"
__init__.py 文件来被识别。在回答这个关于 Python 中的模块和包的问题时,面试者可以考虑以下建议,以确保回答既全面又准确:
__init__.py 文件。import 语句来引入模块,或者如何创建一个简单的包。import 语句的不同方式(如 from module import something)以及相应的优缺点。常见的误区和错误包括:
__init__.py 的重要性,可能导致对包概念的误解。总之,清晰、精确且有实例的回答会使面试者在此问题上表现更佳。
面试官可能会进一步问:
import 语句。__init__.py 文件的作用是什么? 提示:想一下它如何影响包的导入行为。math、datetime、os 等。pip、requirements.txt 或虚拟环境。conda? 提示:谈谈工具的优缺点和使用场景。在 Python 中,可以使用切片来反转字符串。下面是一行代码实现字符串反转的示例:
reversed_string = original_string[::-1]
其中,original_string 是你要反转的字符串。这段代码的意思是从字符串的末尾开始到开头,以步长为 -1 进行切片,从而实现反转。
当面试者被问到用一行代码反转字符串时,以下是一些建议和常见误区需要避免:
reversed() 函数、或者使用循环等。虽然面试题要求'一行代码',建议尽量使用切片这种优雅且简洁的方式,比如 s[::-1]。总结来说,确保代码简洁、易于理解,考虑边界情况,并保持良好的编程习惯,这些都将有助于提升你的代码和面试表现。
面试官可能会进一步问:
在 Python 中,带双下划线的特殊方法(通常称为'魔法方法'或'dunder methods')用于实现类的特定行为。以下是一些常见的带双下划线的特殊方法:
__new__(cls, ...):用于创建实例。在实例化一个对象时调用,通常与 __init__ 一起使用。__init__(self, ...):用于初始化新创建的对象,是构造函数。__str__(self):返回对象的可读字符串表示形式,通常用于 print。__repr__(self):返回对象的官方字符串表示,应该尽可能能够用来重新创建该对象。__len__(self):定义对象的长度,使用 len() 函数时调用。__getitem__(self, key):定义对象的索引访问,使用 obj[key] 语法时调用。__setitem__(self, key, value):定义对象的索引赋值,使用 obj[key] = value 语法时调用。__delitem__(self, key):定义对象的索引删除,使用 del obj[key] 语法时调用。__iter__(self):返回一个迭代器,允许使用 for 循环遍历对象。__next__(self):返回下一个可迭代的值,通常与 __iter__ 一起使用。__contains__(self, item):定义成员检查,使用 item in obj 语法时调用。__call__(self, ...):允许类实例像函数一样被调用。__eq__(self, other):定义相等性比较,使用 == 运算符时调用。__ne__(self, other):定义不相等性比较,使用 != 运算符时调用。__lt__(self, other):定义小于比较,使用 < 运算符时调用。__le__(self, other):定义小于或等于比较,使用 <= 运算符时调用。__gt__(self, other):定义大于比较,使用 > 运算符时调用。__ge__(self, other):定义大于或等于比较,使用 >= 运算符时调用。__hash__(self):定义对象的哈希值,通常用于集合和字典中的键。__enter__(self) 和 __exit__(self, exc_type, exc_value, traceback):用于上下文管理器,支持 with 语句。这些方法可以帮助你自定义类的行为,增强与 Python 内建操作和语法的兼容性。
当讨论面向对象编程中的双下划线特殊方法时,面试者应该注意以下几点:
__new__ 用于创建实例,而 __init__ 用于初始化实例属性。这能展示他们对面向对象概念的深入理解。__str__、__repr__、__eq__),而不是试图列出所有可能的双下划线方法。专注于重要的、实际工作中常用的功能。__method__)和单下划线(如 _method)的方法,以免混淆它们的作用和访问级别。总之,全面理解这些特殊方法的内涵和用途,适当举例,能够有效表达面试者的深度和广度,将会是非常加分的一环。
面试官可能会进一步问:
__new__ 与 __init__ 的区别是什么? 提示:考虑创建对象的过程,哪个负责实例化,哪个负责初始化。__str__ 和 __repr__ 的区别,并举例说明? 提示:思考这两个方法在打印和调试时的用途。__getitem__ 和 __setitem__ 的应用场景是什么? 提示:想想如何通过列表或字典的方式来访问和管理对象属性。__slots__,并给出一个示例? 提示:考虑内存优化和属性限制的影响。__call__ 使得一个对象可以像函数一样被调用? 提示:需要看如何定义和使用 __call__ 方法。__del__ 方法吗?它的作用是什么? 提示:反思对象销毁时的行为以及资源管理。__add__ 或 __sub__? 提示:考虑自定义对象的数学操作如何实现。__enter__ 和 __exit__ 的作用,以及它们如何与上下文管理器结合使用? 提示:想想如何管理资源的分配与释放。__getattr__ 和 __getattribute__ 时会有什么效果? 提示:深思两者的调用顺序及场景。__eq__ 与 __ne__ 方法的实现有什么注意事项? 提示:关注对象相等性和不等性的定义。@property 装饰器来管理类属性的访问权限? 提示:想想哪些情况下需要控制属性的读取和写入。__hash__ 方法,为什么 hashable 对象重要? 提示:结合集合和字典的使用背景。在数据爬虫中,遇到验证码是一个常见的挑战。验证码的主要目的是防止自动化程序访问网站,因此解决这个问题通常需要一些额外的手段。以下是一些解决实例和建议:
如果验证码图像比较简单,你可以尝试使用图像识别库(如 OpenCV、Pillow 和 Tesseract)来识别验证码:
from PIL import Image
import pytesseract
img = Image.open('captcha.png')
captcha_text = pytesseract.image_to_string(img)
robots.txt 文件,确保你的行为遵循网站的爬虫规范。import requests
import time
# 发送验证码到 2Captcha
response = requests.post('http://2captcha.com/in.php', data={'key': 'YOUR_API_KEY', 'method': 'post', 'json': 1, 'file': open('captcha.png', 'rb')})
captcha_id = response.json().get('request')
# 等待验证码处理完成
for _ in range(30): # 最多等 30 秒
time.sleep(5)
response = requests.get(f'http://2captcha.com/res.php?key=YOUR_API_KEY&action=get&id={captcha_id}&json=1')
if response.json()['status'] == 1:
captcha_text = response.json()['request']
break
print(captcha_text)
不同类型的验证码可能需要不同的解决方案,有时需要结合多种方法。重要的是遵循网站的服务条款,合理、合法地进行数据爬取。
在回答有关数据爬虫中遇到验证码问题时,面试者应注意以下几点:
保持清晰、合理、有条理的回答,不仅能够展现面试者的专业能力,也体现出其对复杂问题的深入思考。
面试官可能会进一步问:
在 Scrapy 框架中,Item Pipeline 是处理爬虫提取的数据的一个重要组件。它允许您对爬取到的数据进行清洗、验证和存储等后处理操作。Item Pipeline 是由一系列处理器组成,Scrapy 会依次将 Item 传递给这些处理器。
以下是 Item Pipeline 的工作原理的简要概述:
在 Scrapy 中,你可以在 pipelines.py 文件中定义多个 Pipeline 类。每个类负责处理特定的逻辑,比如数据清洗、数据验证、持久化存储等。
在你的项目的设置文件 settings.py 中,你需要通过配置 ITEM_PIPELINES 启用相应的 Pipeline。示例配置如下:
ITEM_PIPELINES = {
'myproject.pipelines.MyPipeline': 300,
}
这里,字典的键是你的 Pipeline 类的路径,值是一个优先级(数字越小,优先级越高)。
process_item(self, item, spider):这是最重要的方法。Scrapy 会在抓取项时调用它,您可以在这里对 Item 进行任何处理,如清洗、验证或存储。该方法必须返回一个 Item。open_spider(self, spider):在爬虫开始工作时(即爬虫启动时)调用,可以用来初始化数据库连接等操作。close_spider(self, spider):在爬虫结束工作时调用,用于关闭数据库连接等清理工作。下面是一个简单的 Pipeline 示例:
class MyPipeline:
def open_spider(self, spider):
self.file = open('output.json', 'w')
def close_spider(self, spider):
self.file.close()
def process_item(self, item, spider):
# 对 Item 进行处理,例如清洗数据
item['field'] = item['field'].strip()
# 将处理后的 Item 写入文件或数据库
line = json.dumps(dict(item)) + "\n"
self.file.write(line)
return item
Item Pipeline 最常见的用途是将处理后的数据存储到数据库、文件、API 等。Scrapy 提供了很多灵活的方式来实现这一点。
通过 Item Pipeline,Scrapy 允许你在数据提取后以模块化和可扩展的方式进行数据处理。通过定义不同的 Pipeline 类,您可以根据需要轻松添加或修改数据处理逻辑。
当你被问到 Scrapy 中的 pipelines 工作原理时,有几个建议和常见的误区需要注意,以确保你的回答更具深度和准确性。
总之,回答时保持逻辑清晰、简单明了,同时展现出你对 Scrapy 的实际理解,会更有助于让面试官接受你的回答。
面试官可能会进一步问:
在 Python 中,类可以通过继承来获取另一个类的属性和方法。通过继承,子类可以重用父类的代码,并添加或重写功能。下面是一个简单的示例,展示了如何实现类的继承:
# 定义一个父类(基类)
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
return "I am an animal."
# 定义一个子类(派生类),从 Animal 继承
class Dog(Animal):
def speak(self):
return "Woof! My name is " + self.name
# 定义另一个子类(派生类),从 Animal 继承
class Cat(Animal):
def speak(self):
return "Meow! My name is " + self.name
# 实例化对象
dog = Dog("Buddy")
cat = Cat("Whiskers")
# 调用方法
print(dog.speak()) # 输出:Woof! My name is Buddy
print(cat.speak()) # 输出:Meow! My name is Whiskers
Animal 的类,在其初始化方法中接收一个 name 参数,并有一个基方法 speak。Dog 和 Cat,这两个类都从 Animal 类继承。在子类中,我们重写了 speak 方法。Dog 和 Cat 类创建了对象 dog 和 cat,并且调用它们的 speak 方法。通过这种方式,子类可以继承父类的属性和方法,同时也可以根据需要重写它们。
在回答关于类继承的问题时,有几个建议可以帮助面试者清晰和准确地表达自己的理解:
super() 函数及其在调用父类方法时的应用,强调 Python 的 __init__ 方法的继承。常见的误区和错误包括:
object 类。通过关注这些建议和避免常见误区,能够更好地展示在面向对象编程中对继承的理解。
面试官可能会进一步问:
abc 模块。__repr__ 和 __str__ 方法之间的区别。在 Python 中,__repr__ 和 __str__ 是两个用于定义对象字符串表示的方法,它们之间有一些重要的区别。
__repr__ 方法__repr__ 的主要目的是为了提供一个'官方'的字符串表示,通常用于开发和调试。eval() 函数来重建原对象。repr() 函数或直接在交互式解释器中输入对象名时,会调用 __repr__ 方法。class Example:
def __init__(self, value):
self.value = value
def __repr__(self):
return f'Example(value={self.value!r})'
obj = Example(42)
print(repr(obj)) # 输出:Example(value=42)
__str__ 方法__str__ 的主要目的是为用户提供一个可读性好的字符串表示,适合展示给用户看。print() 函数或 str() 函数时,会调用 __str__ 方法。class Example:
def __init__(self, value):
self.value = value
def __str__(self):
return f'The value is {self.value}'
obj = Example(42)
print(str(obj)) # 输出:The value is 42
print(obj) # 输出:The value is 42, 因为 print() 内部调用了 __str__
__repr__ 来提供开发者用的正式字符串表示,而 __str__ 用于提供用户友好的字符串表示。__str__,则在需要字符串表现的地方,Python 会退回使用 __repr__。__repr__ 设计得尽可能详细,而将 __str__ 设计得简洁明了。当面试者回答关于 Python 中 __repr__ 和 __str__ 方法的问题时,有几个方面需要注意,以确保他们的回答清晰准确。
__repr__ 旨在提供一个正式的字符串表示,通常应当能够用来重新创建该对象;而 __str__ 更侧重于可读性,应该为终端用户提供友好的输出。__repr__ 和 __str__。例如,__repr__ 更适合调试使用,适合在控制台中查看对象状态,而 __str__ 更适用于打印给最终用户的结果。__repr__ 而未实现 __str__,那么 print() 函数将回退到 __repr__,这种细节常常被忽视。print() 和 repr() 函数时会调用这些方法。这可以帮助他们更好地理解,如何在实际使用中与这些方法互动。如果面试者能在这些方面表现出色,将有助于展示他们对 Python 面向对象设计的理解和掌握。
面试官可能会进一步问:
__repr__ 和 __str__ 两个方法? 提示:讨论它们的用途以及何时使用它们。__repr__ 和 __str__。__repr__ 和 __str__ 以提供有用的信息? 提示:考虑出错信息、调试兼容性和用户理解。__format__? 提示:讨论 Python 的字符串格式化机制以及它们之间的关联。__repr__ 和 __str__ 来提高类的可维护性? 提示:思考如何提供清晰的文档和可读性。__str__ 或 __repr__ 时的性能问题?你是如何解决的? 提示:考虑性能优化或替代方案的场景。在 Python 中,装饰器是一种用于修改或增强函数(或方法)行为的工具。下面是一个简单的装饰器示例,显示如何在 Python 中实现一个装饰器。
装饰器实际上是一个函数,它接受一个函数作为参数,并返回一个新的函数(通常是对原函数的增强或修改)。
下面的代码实现了一个记录函数执行时间的装饰器:
import time
# 定义装饰器
def timing_decorator(func):
def wrapper(*args, **kwargs):
start_time = time.time() # 记录开始时间
result = func(*args, **kwargs) # 调用原函数
end_time = time.time() # 记录结束时间
print(f"Function {func.__name__} took {end_time - start_time:.4f} seconds")
return result # 返回原函数的返回值
return wrapper
# 使用装饰器
@timing_decorator
def example_function(n):
total = 0
for i in range(n):
total += i
return total
# 调用被装饰的函数
result = example_function(1000000)
print(f"Result: {result}")
timing_decorator,该函数接受一个函数 func 作为参数。wrapper 函数来包装原有函数的调用。time.time() 记录函数开始和结束的时间,并计算执行时间。wrapper 函数调用 func(*args, **kwargs),这允许它接受任意数量的位置参数和关键字参数。result,即原函数的返回值。@timing_decorator 语法来装饰 example_function 函数。example_function,并观察执行时间的输出。通过这种方式,你就实现了一个简单的装饰器,并可用于任何需要记录执行时间的函数。
在回答有关简单装饰器的问题时,有几个方面需要注意:
functools.wraps 来保留原始函数的元数据,避免出现因装饰而导致的属性丢失问题。总的来说,通过清晰简洁的示例来演示基本概念,同时展开讨论一些常见的使用场景和注意事项,可以帮助面试者在回答中更好地展现自己的理解和思考能力。
面试官可能会进一步问:
asyncio 模块是 Python 内置的库,用于编写单线程的异步代码。它提供了事件循环、协程和任务的功能,使得程序能够在等待 I/O 操作(例如网络请求、文件操作等)时,不会阻塞整个程序的执行。
asyncio 的核心是事件循环,它负责调度和执行异步任务。事件循环不断检查是否有准备好的任务,执行这些任务并处理 I/O 事件。async def 定义的函数,允许在执行时被中断,等待某个操作完成后再恢复执行。使用 await 关键词可以暂停协程的执行,等待另一个协程或 I/O 操作完成。asyncio.create_task() 方法来创建任务。asyncio 允许运行多个协程而不是并行执行多个线程,减少上下文切换的开销。任务:
async def main():
task = asyncio.create_task(greet())
await task
asyncio.run(main())
协程:
import asyncio
async def greet():
print("Hello!")
await asyncio.sleep(1) # 模拟非阻塞 I/O
print("World!")
asyncio 特别适合 I/O 密集型的应用程序,比如网络请求、文件读写等,因为这些操作通常会导致阻塞。使用 asyncio 可以提高程序的响应性。asyncio 可用于构建高性能的 TCP/UDP 服务器和客户端。库如 aiohttp 基于 asyncio,用于异步 HTTP 请求处理。asyncio 可以显著提高性能。下面是一个简单的使用 asyncio 的示例,异步地进行 HTTP 请求:
import asyncio
import aiohttp
async def fetch(url):
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
return await response.text()
async def main():
urls = ['https://example.com' for _ in range(5)]
tasks = [fetch(url) for url in urls]
results = await asyncio.gather(*tasks)
for content in results:
print(content)
if __name__ == '__main__':
asyncio.run(main())
这个示例中,我们创建了多个异步 HTTP 请求,asyncio.gather() 用于并行等待所有任务完成。
asyncio 模块为 Python 提供了强大的异步编程能力,使得开发高效、响应迅速的网络应用成为可能。随着异步编程在现代软件开发中的普及,掌握 asyncio 变得越来越重要。
在回答关于 Python 中 asyncio 模块的问题时,有几点建议可以帮助面试者更好地展示他们的理解:
asyncio 的基本概念有清晰的理解。可以简要介绍它是一个用于编写单线程并发代码的库,主要用于处理 I/O 密集型的任务。asyncio 是通过协程来实现异步操作的,而不是多线程。asyncio 的基本用法,如协程的定义和使用 async 和 await 关键字。这会帮助面试官直观理解你的思路。asyncio 的实际应用场景,例如网络请求、爬虫、聊天应用等,以及在这些场景中它所带来的性能优势。asyncio 与多线程混淆,它们适用于不同类型的任务。并且,不要忽视 asyncio 的特点,比如事件循环和任务调度的重要性。asyncio 的局限性,例如它不适合 CPU 密集型任务,因为单线程的方式可能导致性能瓶颈。其实,理解 asyncio 的适用场景同样重要。asyncio 的一些更新(如 Python 3.7 后引入的新特性),以展示与时俱进的学习态度。此外,面试者还应该注意控制回答的节奏,避免过于简略或冗长,同时保持清晰的结构。这样才能让面试官更容易理解你的观点和思路。
面试官可能会进一步问:
Lock,以及如何避免竞态条件。os.path 模块提供的功能及其在文件路径操作中的应用。os.path 模块是 Python 标准库 os 模块的一部分,专门用于处理文件和目录的路径。它提供了一系列方便的函数,帮助开发者执行多种文件路径操作,确保代码的跨平台兼容性。
os.path 模块提供的主要功能路径比较:
os.path.samefile(path1, path2)
检查两个路径是否指向同一个文件。
路径规范化:
os.path.normpath(path)
规范化路径,消除路径中的冗余分隔符和上级目录引用。
路径操作:
os.path.split(path)
将路径分割成目录和文件名,并返回一个元组。
os.path.splitext(path)
将路径分割成文件名和扩展名,并返回一个元组。
路径检查:
os.path.exists(path)
检查给定路径是否存在。
os.path.isfile(path)
检查给定路径是否指向一个文件。
os.path.isdir(path)
检查给定路径是否指向一个目录。
路径解析:
os.path.abspath(path)
返回给定路径的绝对路径。
os.path.basename(path)
返回路径中最后一个文件或目录的名称。
os.path.dirname(path)
返回路径中最后一个文件或目录之前的部分。
路径拼接:
os.path.join(path1, path2,...)
用于安全地拼接多个路径部分,适应不同操作系统的路径分隔符(如 Windows 的 ackslash 与 Unix 的 /)。
import os
file_dir = os.path.join('folder', 'subfolder')
file_path = os.path.join(file_dir, 'file.txt')
if os.path.isfile(file_path):
with open(file_path, 'r') as f:
content = f.read()
这种方式确保了在不同操作系统下正确拼接路径。
import os
base_dir = 'my_directory'
for root, dirs, files in os.walk(base_dir):
for file in files:
full_path = os.path.join(root, file)
print(full_path)
该脚本能在不同操作系统上无缝运行,确保文件路径的正确处理。
import os
file_path = 'example.txt'
name, ext = os.path.splitext(file_path)
print(f'Name: {name}, Extension: {ext}')
明晰地获得文件名和扩展名,有助于处理文件。
os.path 模块极大地简化了文件路径操作,为开发者提供了跨平台的兼容性和便利性。在编写涉及文件和目录操作的 Python 代码时,使用 os.path 模块是最佳实践。
在回答关于 os.path 模块的问题时,有几个方面需要注意,以确保你的回答既全面又准确。以下是一些建议和避免的常见误区:
os.path 模块的核心功能,如路径拼接、分割、规范化、绝对路径和相对路径的转换等。简洁明了的表达有助于突出你的理解。os.path 的一个重要特点是它的跨平台性,可以在不同操作系统上处理路径。避免只局限于某一操作系统的特性,比如只讨论 Linux 或 Windows 的路径格式。os.path 模块。例如,使用 os.path.join() 进行路径拼接,或者使用 os.path.exists() 检查文件是否存在。确保示例是简单明了的,不要过于复杂。os.path 模块中的函数和其它类似模块(如 pathlib)。pathlib 是较新的模块,提供了更面向对象的路径操作,如果说明时混合使用,可能让面试官觉得你对模块的认识不够清晰。pathlib 逐渐被用作 os.path 的替代。如果只说到旧版本的特性,可能显得你对 Python 的发展缺乏关注。通过关注这些要点,并避免这些常见的误区和错误,可以提高你对 os.path 模块的理解深度和广度,使你的回答更具针对性和专业性。
面试官可能会进一步问:
os.path 模块中常用的方法吗? 提示:例如 join, exists, isfile, isdir 等方法的作用和应用场景。os.path.join 在路径连接时的优势是什么? 提示:讨论操作系统的兼容性和避免手动处理路径分隔符的问题。os.path.normpath,以及在什么情况下需要规范化路径。isfile 和 isdir 的使用,讨论它们的区别。os.path 中处理它们。 提示:讨论如何使用 os.path.abspath 和 os.path.dirname 来转换路径。os.path.splitext 的用法以及如何从文件名中提取扩展名。os.path 模块如何做到操作系统无关性。os.path 模块进行文件搜索或文件遍历的经验?可以分享一下吗? 提示:引入 os.walk 或结合 os.path 的其他方法。os.path 处理文件路径的实际案例。 提示:真实案例可以涉及文件读取、写入或路径转换的具体场景。
微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online