ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Scrapling 自定义类型 API 详解:TextHandler、TextHandlers 与 AttributesHandler

Scrapling 自定义类型 API 详解:TextHandler、TextHandlers 与 AttributesHandler Scrapling 自定义类型 API 详解TextHandler、TextHandlers 与 AttributesHandler【免费下载链接】Scrapling️ An adaptive Web Scraping framework that handles everything from a single request to a full-scale crawl!项目地址: https://gitcode.com/GitHub_Trending/sc/Scrapling本文基于 docs/api-reference/custom-types.md 展开完整梳理 Scrapling 内置的三个自定义类型TextHandler、TextHandlers、AttributesHandler的导入方式、全部属性与方法的参数语义并结合 scrapling/core/custom_types.py 的源码实现与 tests/parser/ 下的测试用例说明它们在 Selector 解析流程中如何被创建与消费。读完本文你不仅能看懂 Scrapling 返回值的类型体系还能把这三个类单独提取到自己的项目中复用。快速导入与总体设计按照 docs/api-reference/custom-types.md 的定义这三个类都可以直接从scrapling.core.custom_types模块导入from scrapling.core.custom_types import TextHandler, TextHandlers, AttributesHandler从源码结构看三者构成一条完整的“解析结果类型链”TextHandler继承自 Python 内建str是单个文本节点如元素文本、HTML 片段的载体TextHandlers继承自内建List[TextHandler]是批量文本结果的容器等价于“带增强方法的列表”AttributesHandler继承自collections.abc.Mapping[str, TextHandler]是元素属性表的只读映射替代了普通dict。三者都声明了__slots__ ()见 scrapling/core/custom_types.py#L32不额外占用实例属性内存。此外scrapling/init.py#L14-L23 中的_LAZY_IMPORTS也把TextHandler和AttributesHandler注册为顶层惰性导入名意味着import scrapling后访问scrapling.TextHandler也能拿到同一个类。TextHandler字符串的子类TextHandler的类文档定义为 “Extends standard Python string by adding more functionality”scrapling/core/custom_types.py#L29-L30。因为它是str的子类所有标准字符串操作照常可用在类型判断时官方建议使用issubclass而非直接isinstance猜测参见 docs/development/scrapling_custom_types.md。1. 链式友好的字符串方法重写源码中最显眼的一段是第 3496 行的方法重写集合scrapling/core/custom_types.py#L34-L96。这些方法在调用父类实现后把结果重新包装回TextHandler从而保证链式调用时类型不“退化”成普通str__getitem__(key)索引或切片后仍返回TextHandlersplit(sep, maxsplit)与其他方法不同它返回的是TextHandlers每个分片都是TextHandler见 scrapling/core/custom_types.py#L38-L39strip/lstrip/rstrip、capitalize、casefold、center、expandtabs、format、format_map、join、ljust、rjust、swapcase、title、translate、zfill、replace、upper、lower均返回TextHandler。这意味着page.css(title).text.strip().upper().replace(X, Y)每一步拿到的都是TextHandler可以继续调用clean()、re()等增强方法而普通str则做不到。2. 增强方法sort(reverseFalse)返回按字符排序后的新字符串scrapling/core/custom_types.py#L100-L102TextHandler(dcba).sort() # abcd TextHandler(dcba).sort(reverse) # dcbatests/parser/test_parser_advanced.py#L249 中text.sort() abcd的断言验证了该行为。clean(remove_entitiesFalse)这是清洗 HTML 文本最实用的方法之一实现见 scrapling/core/custom_types.py#L104-L109先用模块级转换表__CLEANING_TABLE__ str.maketrans(\t\r\n, )第 26 行把制表符、回车、换行统一替换为空格若remove_entitiesTrue调用w3lib.html.replace_entities将 HTML 实体如amp;还原为对应字符用 scrapling/core/utils/_utils.py#L16 中预编译的正则__CONSECUTIVE_SPACES_REGEX__ re_compile(r )折叠连续空格最后strip()。TextHandler( Hellonbsp; World\t\r\n ).clean(remove_entitiesTrue) # Hello World默认remove_entitiesFalse时实体引用会被保留tests/parser/test_parser_advanced.py#L305-L316 分别验证了两种模式的行为。json()把字符串当作 JSON 解析scrapling/core/custom_types.py#L121-L125。内部通过loads(str(self))使用orjson解析——先显式转str是绕过 orjson 对str子类支持问题的已知 workaround。它非常适合直接解析data-*属性里内嵌的 JSONtests/parser/test_attributes_handler.py#L93-L110 覆盖了对象、数组、嵌套对象与null四种场景并在 第 112-120 行 验证了非法 JSON 会抛出异常。get(default)/getall()/extract/extract_first这一组方法scrapling/core/custom_types.py#L111-L119是 Scrapy/parsel 的兼容层源码注释写明 “For easy copy-paste from Scrapy/parsel code when needed”即get()与getall()/extract()直接返回自身extract_first get。如果你把旧的 Scrapy 解析代码迁移到 Scrapling这些别名可以让node.get()、node.extract()之类的写法继续工作。re(regex, replace_entitiesTrue, clean_matchFalse, case_sensitiveTrue, check_matchFalse)对当前文本执行正则匹配参数与返回值scrapling/core/custom_types.py#L127-L182参数默认值说明regex必填正则字符串或已编译的re.Pattern字符串形式下按case_sensitive编译始终带UNICODE标志replace_entitiesTrue匹配结果中的 HTML 字符实体引用是否还原为对应字符clean_matchFalse为True时先对输入文本执行clean()再去匹配可忽略空白与连续空格case_sensitiveTrue为False时编译时追加IGNORECASE标志check_matchFalse为True时只返回bool用于快速判断是否命中不产出结果通过overload声明check_matchTrue时返回类型被标注为bool否则返回TextHandlers。两个实现细节值得注意若findall结果全是可迭代对象即正则含多个捕获组会用flatten()打平第 176-177 行因此re(rname(\w) age(\d))得到的是扁平的匹配字符串序列而非元组列表tests/parser/test_parser_advanced.py#L284-L286 验证了这一点clean_matchTruecase_sensitiveFalse的组合可以对排版杂乱的文本做宽松匹配见 tests/parser/test_parser_advanced.py#L267 中re(rHe l lo, clean_matchTrue, case_sensitiveFalse)的用例。text page.css(h1).text text.re(r\$[\d.]) # TextHandlers所有价格 text.re(r\$\d, check_matchTrue) # bool是否存在价格 text.re(rhello, case_sensitiveFalse) # 忽略大小写re_first(regex, defaultNone, replace_entitiesTrue, clean_matchFalse, case_sensitiveTrue)对文本执行re()并返回第一个匹配无匹配时返回defaultscrapling/core/custom_types.py#L184-L207element.re_first(r[\.\d]) # 提取版本号/数字 text.re_first(r\d, defaultN/A) # 无数字时得到 N/Adefault参数让它在“可能不存在”的提取场景下避免IndexError测试见 tests/parser/test_parser_advanced.py#L291-L301。TextHandlers增强型列表TextHandlers是List[TextHandler]的子类scrapling/core/custom_types.py#L210-L213提供的方法索引与切片的类型保持__getitem__通过重载声明区分两种索引scrapling/core/custom_types.py#L217-L229整数下标返回单个TextHandler切片返回新的TextHandlers。因此matches[0].clean()、matches[1:3]这样的链式写法都能保持类型。re(regex, replace_entitiesTrue, clean_matchFalse, case_sensitiveTrue)对列表中每个元素调用TextHandler.re()再把结果打平成一个新的TextHandlersscrapling/core/custom_types.py#L231-L247。这比在普通list上手动flatten更简洁——Selector.re()正是建立在这一步之上的见 scrapling/parser.py#L1287-L1297 中TextHandlers(flatten(results))的返回。re_first(regex, defaultNone, replace_entitiesTrue, clean_matchFalse, case_sensitiveTrue)遍历列表中的每个元素及其匹配结果返回遇到的第一个匹配全部无匹配时返回defaultscrapling/core/custom_types.py#L249-L269。Scrapy/parsel 兼容别名get(default)返回列表第一项或默认值extract()返回自身extract_first get、getall extractscrapling/core/custom_types.py#L271-L282与TextHandler的兼容策略一致。AttributesHandler只读属性映射AttributesHandler是解析器中Selector.attrib属性的实际类型。scrapling/parser.py#L334-L339 中attrib属性会把 lxml 节点的attrib字典包装成AttributesHandler空属性时返回AttributesHandler({})而Selector的__getitem__scrapling/parser.py#L183也按TextHandler返回属性值——也就是说你在选择器上用page.css(div)[0][class]取到的属性值天然是TextHandler可以直接.clean()、.json()、.re()。构造字符串值自动升级整体只读构造函数scrapling/core/custom_types.py#L292-L305接受映射或关键字参数两种形式somedict_1 AttributesHandler({a: 1}) somedict_2 AttributesHandler(a1)构造逻辑若传入mapping遍历其键值对字符串值统一转为TextHandler非字符串值原样保留kwargs中的条目以同样规则合并进去最终用types.MappingProxyType包裹后存入_data属性第 305 行源码注释将其称为 “Fastest read-only mapping type”即最快的只读映射形态。因此AttributesHandler支持标准dict的全部只读操作keys()、values()、items()、in、len()、/!比较等继承自Mapping但任何写操作都会失败。要修改数据需先dict(handler)转换后再改——这一点在 docs/development/scrapling_custom_types.md 中也有明确说明。tests/parser/test_attributes_handler.py#L177-L194 专门验证了赋值attrs[id] new-id不会生效。get(key, defaultNone)等价于标准字典的.get()scrapling/core/custom_types.py#L307-L309attributes.get(id) attributes.get(nonexistent, default)search_values(keyword, partialFalse)按值搜索属性返回生成器每次yield一个只含单个匹配键值对的AttributesHandlerscrapling/core/custom_types.py#L311-L322partialFalse默认精确匹配keyword value且大小写敏感partialTrue判断keyword in value的子串包含关系。attrs page.css(#main)[0].attrib list(attrs.search_values(main)) # 精确匹配 idmain list(attrs.search_values(container, partialTrue)) # 模糊匹配 class 等tests/parser/test_attributes_handler.py#L133-L158 覆盖了精确/模糊匹配、大小写敏感search_values(MAIN)得到空列表、多命中与零命中场景第 294-315 行 进一步验证了 Unicode 值中文、Emoji下partialTrue的搜索行为。json_string属性把所有属性序列化为 JSON字节串scrapling/core/custom_types.py#L324-L327内部是dumps(dict(self._data))即先把代理映射转回普通dict再用orjson序列化。若属性值不可序列化则抛异常。tests/parser/test_attributes_handler.py#L122-L131 验证了返回类型为bytes且可被json.loads还原。在 Selector 解析流程中的落点把源码串起来看这三个类型的创建点集中在 scrapling/parser.pySelector.text第 269-276 行返回TextHandler(self._root.text or )空元素得到空TextHandlerSelector.attrib第 334-339 行返回AttributesHandler(self._root.attrib)Selector.getall()第 471-473 行返回TextHandlers([self.get()])属性访问下标Selector.__getitem__第 183 行返回TextHandler。因此一次典型的提取链——page.css(.price).text.clean().re(r\d)或page.css(div)[0].attrib[data-config].json()——全程都在TextHandler/TextHandlers/AttributesHandler三个类型上运行无需手动转换。更完整的用法可以参考 tests/parser/test_general.py 中对sort()、json()、search_values的综合断言如 第 255-283 行。脱离 Scrapling 单独使用除了服务解析器这三个类也可以作为独立工具使用docs/development/scrapling_custom_types.md 给出了最小示例from scrapling.core.custom_types import TextHandler, AttributesHandler somestring TextHandler({}) somestring.json() # {} somedict_1 AttributesHandler({a: 1}) somedict_2 AttributesHandler(a1)几个使用要点TextHandler是str子类凡是str能做的它都能做类型检查推荐issubclass(type(x), str)这类方式AttributesHandler是collections.abc.Mapping的子类除写操作外与dict行为一致需要可变副本时先dict()转换序列化路径上TextHandler.json()与AttributesHandler.json_string均基于orjson比标准库json更快适合高频解析场景。参考文件API 参考文档docs/api-reference/custom-types.md类型实现源码scrapling/core/custom_types.py清洗正则与flatten工具scrapling/core/utils/_utils.py解析器中的使用点scrapling/parser.py顶层惰性导入注册scrapling/init.py独立使用指南docs/development/scrapling_custom_types.md测试用例tests/parser/test_attributes_handler.py、tests/parser/test_parser_advanced.py、tests/parser/test_general.py【免费下载链接】Scrapling️ An adaptive Web Scraping framework that handles everything from a single request to a full-scale crawl!项目地址: https://gitcode.com/GitHub_Trending/sc/Scrapling创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表