【官方分发平台源码】【krpano开源码】【tomcat dbcp 源码】selector源码深入分析

时间:2024-11-20 20:33:21 编辑:zuul源码大全 来源:直播盒子php源码

1.Vue3中deep样式穿透的源码使用细节及源码解析
2.R爬虫必备基础——CSS+SelectorGadget
3.为什么 querySelectorAll 返回的不是 Array?
4.Spring Configuration:@Import的用法和源码解析
5.@Import({ AutoConfigurationImportSelector.class})

selector源码深入分析

Vue3中deep样式穿透的使用细节及源码解析

       在Vue3的开发中,遇到第三方UI库(如element-plus)样式失效的深入问题时,可以借助:deep()方法实现样式穿透。分析首先理解一下 scoped属性的源码作用,它在组件style标签中设置,深入能确保样式隔离,分析官方分发平台源码避免组件间的源码样式污染。

       例如,深入在element-plus的分析组件中,即使设置了宽度,源码由于 scoped属性导致的深入属性选择器不匹配,导致样式无法生效。分析这时,源码:deep()派上了用场。深入它将属性选择器前置,分析如:.el-inputwrapper::v-deep(.bar)会被转换为[data-v-xxxxxxx] .el-inputwrapper .bar,从而定位到UI库的选择器。

       源码解析在core-main/packages/compiler-sfc/src/compileStyle.ts中,当遇到 scoped时,krpano开源码会使用postcss插件将CSS转换为抽象语法树,然后在processRule函数中,rewriteSelector()方法会处理:deep,将其转换为穿透选择器。

       总结来说,当在Vue3中使用第三方UI库时,若样式设置无响应,可以考虑使用:deep()来解决样式穿透问题,以便于精确地控制和修改UI库的tomcat dbcp 源码样式。

R爬虫必备基础——CSS+SelectorGadget

        CSS,全称叫作Cascading Style Sheets,即层叠样式表。“层叠”是指当在HTML中引用了数个样式文件,并且样式发生冲突时,浏览器能依据层叠顺序处理。“样式”指网页中文字大小、颜色、元素间距、排列等格式。HTML定义了网页的结构,但是只有HTML页面的布局并不美观,可能只是简单的节点元素的排列,为了让网页看起来更好看一些,这里借助了CSS。CSS是目前唯一的网页页面排版样式标准,有了它的帮助,页面才会变得更为美观。如下图的右侧,即为CSS。

        就局部放大来看,下图所示就是一个CSS样式。大括号前面是一个CSS选择器,此选择器的意思是首先选中id为head_wrapper且class为s-ps-islite的节点,然后再选中其内部的class为s-p-top的节点。大括号内部写的就是一条条样式规则,例如position指定了这个元素的布局方式为绝对布局,bottom指定元素的下边距为像素,width指定了宽度为%占满父元素,height则指定了元素的高度。也就是说,我们将位置、宽度、高度等样式配置统一写成这样的形式,然后用大括号括起来,接着在开头再加上CSS选择器,这就代表这个样式对CSS选择器选中的元素生效,元素就会根据此样式来展示了。在网页中,一般会统一定义整个网页的样式规则,并写入CSS文件中(其后缀为css)。在HTML中,只需要用link标签即可引入写好的CSS文件,这样整个页面就会变得美观、优雅。

        在爬虫过程中都需要爬取目标的节点,我们知道网页由一个个节点组成,CSS选择器会根据不同的节点设置不同的样式规则,那什么是节点?又怎样来定位节点呢?下面围绕这两个问题进行介绍。

        在HTML中,所有标签定义的内容都是节点,它们构成了一个HTML DOM树。我们先看下什么是DOM,DOM是W3C(万维网联盟)的标准,其英文全称Document Object Model,即文档对象模型。它定义了访问HTML和XML文档的标准:W3C文档对象模型(DOM)是中立于平台和语言的接口,它允许程序和脚本动态地访问和更新文档的内容、结构和样式。W3C DOM标准被分为如下3个不同的部分:

        核心DOM:针对任何结构化文档的标准模型。

XML DOM:针对XML文档的标准模型。

HTML DOM:针对HTML文档的标准模型。

        根据W3C的HTML DOM标准,HTML文档中的所有内容都是节点。整个文档是一个文档节点;每个HTML元素是元素节点;HTML元素内的文本是文本节点;每个HTML属性是属性节点;注释是注释节点。HTML DOM将HTML文档视作树结构,这种结构被称为节点树,如下图所示。

        节点树中的节点彼此拥有层级关系。我们常用父(parent)、子(child)和兄弟(sibling)等术语描述这些关系。父节点拥有子节点,同级的子节点被称为兄弟节点。在节点树中,顶端节点称为根(root)。除了根节点之外,每个节点都有父节点,同时可拥有任意数量的子节点或兄弟节点。下图展示了节点树以及节点之间的关系。

        在CSS中,我们使用CSS选择器来定位节点。例如,下图中div节点的id为container,那么就可以表示为#container,其中#开头代表选择id,其后紧跟id的名称。另外,如果我们想选择class为wrapper的节点,便可以使用.wrapper,这里以点(.)开头代表选择class,其后紧跟class的名称。另外,还有一种选择方式,那就是根据标签名筛选,例如想选择二级标题,直接用h2即可。这是最常用的3种表示,分别是根据id、class、标签名筛选,请牢记它们的写法。

        另外,CSS选择器还支持嵌套选择,各个选择器之间加上空格分隔开便可以代表嵌套关系,如#container .wrapper p则代表先选择id为container的节点,然后选中其内部的class为wrapper的节点,然后再进一步选中其内部的p节点。另外,如果不加空格,则代表并列关系,如div#container .wrapper p.text代表先选择id为container的div节点,然后选中其内部的class为wrapper的节点,再进一步选中其内部的class为text的p节点。这就是CSS选择器,其筛选功能还是非常强大的。另外,CSS选择器还有一些其他语法规则,具体如下表所示。

        但是,这样每次都要浪费部分时间去寻找定位点,这样既不很方便,也不高效,那么如何提高爬虫中这部分工作的效率呢?今天我给大家分享一个爬虫的利器,它就是:SelectorGadget 插件。

        point and click CSS selectors,强大的谷歌插件CSS生成器,有助于我们快速找到html的节点信息,它也支持Xpath表达式。Selector Gadget是一个开源的Chrome扩展程序,可以轻松地在复杂的网站上生成和选择CSS选择器。安装扩展程序后,转到任意页面并启动它。网站右下方会打开一个方框。单击您希望选择器匹配的页面元素(它将变为绿色)。然后SelectorGadget将为该元素生成一个最小的CSS选择器,并突出显示(黄色)选择器匹配的所有内容。现在单击突出显示的元素将其从选择器中删除(红色),或单击未突出显示的元素将其添加到选择器。通过这个选择和拒绝过程,SelectorGadget可以帮助您找到满足您需求的完美CSS选择器。

        首先需要安装一下这个神器。在谷歌浏览器中的应用商店里,搜索到SelectorGadget插件,点击“添加至Chrome”即可。如果不能打开Chrome应用商店,可以通过网上的其他途径获取该插件,之后再手动添加至谷歌浏览器即可。手动添加方法是:打开谷歌浏览器扩展程序,并开启开发者模式,将该插件拖拽到浏览器里,如果不成功,可以选择“加载已解压的扩展程序”,将该文件夹先压缩再解压添加进去。

        同时在页面栏上能看到红框处的SelectorGadget标志。

        咱们以 / 网页为例,首先点击网页上方的SelectorGadget,然后在网页下方弹出SelectorGadget框。接下来,咱们尝试一下如何使用?比如我们想定位“拆弹专家2”的节点,直接点击它,则会在框内显示其节点——.item-title(如下图)。绿色:单击希望选择器匹配的页面元素。黄色:生成的这个CSS选择器【.item-title】能匹配的所有内容,从下图可以发现该CSS选择器可以抓取哪些信息。当你把鼠标放到这些高亮的元素上时,会显示红色,代表要将其从选择器中删除;而单击未突出显示的元素将其添加到选择器。

        在实际构建CSS表达式过程中,需要搭配网页开发工具里的copy selector功能使用,非常方便。比如:定位抓取以下网页( /allmovies )红框内的所有电影名称信息。

        具体操作流程如下:在某一电影名称下右击——检查,定位到电影名称的网页源码处,然后右击—copy—copy selector,再打开SelectorGadget,在框内粘贴CSS表达式,按Enter键,发现在网页中准确定位出该电影名称。但我们需要定位所有的电影名称,在已有的CSS表达式【(body > div:nth-child(5) > div.inner-wrapper > div.inner-2col-main > div > ul > li:nth-child(1) > a > span.item-title)】上进行修改,这里可以发现【li:nth-child(1)】只选取了第一个,而我们所需选取所有,因此去掉后面的【(1)】即可。在具体实践中,如何修改还有有赖于小伙伴对网页结构和CSS语法的理解。最终,获取以上红框内电影名称的CSS选择器表达式为:【body > div:nth-child(5) > div.inner-wrapper > div.inner-2col-main > div > ul > li:nth-child > a > span.item-title】。在实际应用中,不同节点标签之间用空格分隔:【body div:nth-child(5) div.inner-wrapper div.inner-2col-main div ul li:nth-child a span.item-title】。

        但在SelectorGadget使用中,发现其构建的CSS表达式往往很复杂,大部分情况下其实也是可以自己构建CSS表达式的。构建CSS选择表达式的关键在于清楚整个网页结构,找到标签之间的属于关系、属性值属于哪个标签等,就可以比较快速的构建。而且浏览器很智能,鼠标在源码上的位置,可以在网页显示上呈现阴影,这个功能简直太香了。以上红框内所有电影名字的CSS表达式也可以表示为:【div.movlist ul li a span.item-title】

        然后用SelectorGadget验证,如下图,发现高亮选中的部分就是我想要定位的信息,说明这个CSS表达式正确。

        以上简单介绍了如何构建CSS表达式,在爬虫过程中定位抓取特定节点数据是非常重要的一步,有了这步才有下游的精准数据提取与清洗。希望本次教程能给有需要的小伙伴一点小小帮助!

        更多内容可关注公共号“YJY技能修炼”~~~

        往期回顾

        R爬虫在工作中的一点妙用

        R爬虫必备基础——HTML和CSS初识

        R爬虫必备基础——静态网页+动态网页

        R爬虫必备——rvest包的使用

为什么 querySelectorAll 返回的不是 Array?

       查询所有元素涉及到的规范与数组规范不同,因此查询所有元素返回的不是数组类型。

       从规范角度看,查询所有元素属于 DOM 规范,而数组属于 ECMAScript 规范。DOM 规范强调平台中立性,但并未在规范中提及与数组相关的概念。

       实际上,查询所有元素返回的源码管理 svn是 NodeList 类型,这与数组有本质区别。Array 类型来源于 ECMAScript 规范,而 NodeList 则是 DOM 中用于表示一组节点的类。

       具体到源码层面,Chromium 的实现中,查询所有元素返回的是 StaticElementList 类型。该类封装了选择器字符串并提供了节点集合,但与 JavaScript 数组的实现不同。

       JavaScript 数组由 V8 引擎实现,科煌源码其长度属性通过特定的偏移量在 JSArray 对象上获取。与此相反,StaticElementList 的长度属性计算逻辑与 JavaScript 数组完全不同。

       综上,查询所有元素返回的 NodeList 不是 Array 类型的原因,主要在于两者所属的规范体系不同,以及在实现细节上的差异。

Spring Configuration:@Import的用法和源码解析

       Spring 3.0之后的@Configuration注解和注解配置体系替代了XML配置,本文主要讲解@Import的用法和源码解析。

       @Import的用法

       配置类(带有@Configuration注解)不仅可通过@Bean声明bean,还可通过@Import导入其他类。例如,WebMvcConfig类通过@Import导入其他配置类,同时启用@EnableWebMvc。

       直接导入

       配置类上使用@Import可以导入一个或多个类,甚至可以出现在父类注解中。如WebMvcConfig导入DelegatingWebMvcConfiguration等。

       ImportBeanDefinitionRegistrar和ImportSelector

       @Import除了导入配置类,还可以导入实现了ImportBeanDefinitionRegistrar(如@EnableAspectJAutoProxy)和ImportSelector(如@EnableTransactionManagement)的类。

       源码解析

       ConfigurationClassPostProcessor负责处理@Configuration类,通过ConfigurationClassParser解析配置和导入,由ConfigurationClassBeanDefinitionReader注册BeanDefinition。在解析过程中,处理@Import避免循环导入,通过导入链和ImportStack进行判断。

       处理直接导入时,通过导入链判断循环。

       处理注册器和选择器时,提前触发Aware接口方法,然后在适当时机注册导入的类。

       总结来说,@Import提供了多种导入方式的灵活性,Spring的源码设计考虑了循环导入和重复解析的处理,展示了其强大的自定义配置能力。

@Import({ AutoConfigurationImportSelector.class})

       ï¼ˆ2)@Import({ AutoConfigurationImportSelector.class}):将AutoConfigurationImportSelector这个类导入到spring容器中,AutoConfigurationImportSelector可以帮助springboot应用将所有符合条件的@Configuration配置都加载到当前SpringBoot创建并使用的IoC容器(ApplicationContext)中

       ç»§ç»­ç ”究AutoConfigurationImportSelector这个类,通过源码分析这个类中是通过selectImports这个方法告诉springboot都需要导入那些组件:

       ![image-](./images/image-.png)

       æ·±å…¥ç ”究loadMetadata方法

       ![image-](./images/image-.png)      

       æ·±å…¥getCandidateConfigurations方法

       ä¸ªæ–¹æ³•ä¸­æœ‰ä¸€ä¸ªé‡è¦æ–¹æ³•loadFactoryNames,这个方法是让SpringFactoryLoader去加载一些组件的名字。

       ![image-](./images/image-.png)

       ç»§ç»­ç‚¹å¼€loadFactory方法

       ```java

         public static ListloadFactoryNames(Class factoryClass, @Nullable ClassLoaderclassLoader) {

              //获取出入的键

               String factoryClassName = factoryClass.getName();

               return(List)loadSpringFactories(classLoader).getOrDefault(factoryClassName,Collections.emptyList());

            }

          private static Map>loadSpringFactories(@Nullable ClassLoader classLoader) {

               MultiValueMap result =(MultiValueMap)cache.get(classLoader);

               if (result != null) {

                   return result;

               } else {

                   try {

                       //如果类加载器不为null,则加载类路径下spring.factories文件,将其中设置的配置类的全路径信息封装为Enumeration类对象

                        Enumeration urls =classLoader != null ?classLoader.getResources("META-INF/spring.factories") :ClassLoader.getSystemResources("META-INF/spring.factories");

                        LinkedMultiValueMap result =new LinkedMultiValueMap();

                       //循环Enumeration类对象,根据相应的节点信息生成Properties对象,通过传入的键获取值,在将值切割为一个个小的字符串转化为Array,方法result集合中

                        while(urls.hasMoreElements()) {

                            URL url =(URL)urls.nextElement();

                            UrlResource resource = newUrlResource(url);

                            Properties properties =PropertiesLoaderUtils.loadProperties(resource);

                            Iterator var6 =properties.entrySet().iterator();

                           while(var6.hasNext()) {

                                Entry entry= (Entry)var6.next();

                                String factoryClassName= ((String)entry.getKey()).trim();

                                String[] var9 =StringUtils.commaDelimitedListToStringArray((String)entry.getValue());

                                int var =var9.length;

                               for(int var = 0;var < var; ++var) {

                                    String factoryName= var9[var];

                                   result.add(factoryClassName, factoryName.trim());

                                }

                            }

                        }

                       cache.put(classLoader, result);

                        return result;

        ```

       ä¼šåŽ»è¯»å–一个sprin  g.factories的文件,读取不到会表这个错误,我们继续根据会看到,最终路径的长这样,而这个是spring提供的一个工具类

       ```java

        public final class SpringFactoriesLoader {

           public static final String FACTORIES_RESOURCE_LOCATION ="META-INF/spring.factories";

        }

        ```

       å®ƒå…¶å®žæ˜¯åŽ»åŠ è½½ä¸€ä¸ªå¤–部的文件,而这文件是在

       ![image-](./images/image-.png)

       ![image-](./images/image-.png)

       @EnableAutoConfiguration就是从classpath中搜寻META-INF/spring.factories配置文件,并将其中org.springframework.boot.autoconfigure.EnableutoConfiguration对应的配置项通过反射(Java Refletion)实例化为对应的标注了@Configuration的JavaConfig形式的配置类,并加载到IOC容器中      

        ä»¥åˆšåˆšçš„项目为例,在项目中加入了Web环境依赖启动器,对应的WebMvcAutoConfiguration自动配置类就会生效,打开该自动配置类会发现,在该配置类中通过全注解配置类的方式对Spring MVC运行所需环境进行了默认配置,包括默认前缀、默认后缀、视图解析器、MVC校验器等。而这些自动配置类的本质是传统Spring MVC框架中对应的XML配置文件,只不过在Spring Boot中以自动配置类的形式进行了预先配置。因此,在Spring Boot项目中加入相关依赖启动器后,基本上不需要任何配置就可以运行程序,当然,我们也可以对这些自动配置类中默认的配置进行更改 

       **总结

**

          因此springboot底层实现自动配置的步骤是:

       1. springboot应用启动;

       2. @SpringBootApplication起作用;

       3. @EnableAutoConfiguration;

       4. @AutoConfigurationPackage:这个组合注解主要是@Import(AutoConfigurationPackages.Registrar.class),它通过将Registrar类导入到容器中,而Registrar类作用是扫描主配置类同级目录以及子包,并将相应的组件导入到springboot创建管理的容器中;

       5.

        @Import(AutoConfigurationImportSelector.class):它通过将AutoConfigurationImportSelector类导入到容器中,AutoConfigurationImportSelector类作用是通过selectImports方法执行的过程中,会使用内部工具类SpringFactoriesLoader,查找classpath上所有jar包中的META-INF/spring.factories进行加载,实现将配置类信息交给SpringFactory加载器进行一系列的容器创建过程

       åˆšå­¦äº†æ‹‰å‹¾æ•™è‚²çš„《Java工程师高薪训练营》,看到刚学到的点就回答了。希望拉勾能给我推到想去的公司,目标:字节!!