整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

css面试题总汇


. link 和 @import 都能导入一个样式文件,它们有什么区别嘛?

  • link 是 HTML 标签,除了能导入 CSS 外,还能导入别的资源,比如图片、脚本和字体等;而 @import 是 CSS 的语法,只能用来导入 CSS;
  • link 导入的样式会在页面加载时同时加载,@import 导入的样式需等页面加载完成后再加载;
  • link 没有兼容性问题,@import 不兼容 ie5 以下;
  • link 可以通过 JS 操作 DOM 动态引入样式表改变样式,而@import不可以。

2.c s s 选择器优先级

  • 10000:!important;
  • 01000:内联样式;
  • 00100:ID 选择器;
  • 00010:类选择器、伪类选择器、属性选择器;
  • 00001:元素选择器、伪元素选择器;
  • 00000:通配选择器、后代选择器、兄弟选择器;

可以看到内联样式(通过元素中 style 属性定义的样式)的优先级大于任何选择器;而给属性值加上 !important 又可以把优先级提至最高,就是因为它的优先级最高,所以需要谨慎使用它,以下有些使用注意事项:

  • 一定要优先考虑使用样式规则的优先级来解决问题而不是 !important;
  • 只有在需要覆盖全站或外部 CSS 的特定页面中使用 !important;
  • 永远不要在你的插件中使用 !important;
  • 永远不要在全站范围的 CSS 代码中使用 !important;

3. c s s 继承性

字体相关:font-familyfont-stylefont-sizefont-weight 等;

文本相关:text-aligntext-indenttext-decorationtext-shadowletter-spacingword-spacingwhite-spaceline-heightcolor 等;

列表相关:list-stylelist-style-imagelist-style-typelist-style-position 等;

其他属性:visibilitycursor 等;

对于其他默认不继承的属性也可以通过以下几个属性值来控制继承行为:

inherit:继承父元素对应属性的计算值;

initial:应用该属性的默认值,比如 color 的默认值是 #000

unset:如果属性是默认可以继承的,则取 inherit 的效果,否则同 initial

revert:效果等同于 unset,兼容性差。

4. c s s 盒模型

在 CSS 中任何元素都可以看成是一个盒子,而一个盒子是由 4 部分组成的:内容(content)、内边距(padding)、边框(border)和外边距(margin)。盒模型有 2 种:标准盒模型和 IE 盒模型,本别是由 W3C 和 IExplore 制定的标准。

4.1标准盒模型

如果给元素设置如下样式:

.box {
    width: 200px;
    height: 200px;
    padding: 10px;
    border: 1px solid #eee;
    margin: 10px;
}

标准盒模型认为:盒子的实际尺寸 = 内容(设置的宽/高) + 内边距 + 边框

所以 .box 元素内容的宽度就为 200px,而实际的宽度则是 width + padding-left + padding-right + border-left-width + border-right-width = 200 + 10 + 10 + 1 + 1 = 222。

4.2 ie 盒子模型

IE 盒模型认为:盒子的实际尺寸 = 设置的宽/高 = 内容 + 内边距 + 边框

.box 元素所占用的实际宽度为 200px,而内容的真实宽度则是 width - padding-left - padding-right - border-left-width - border-right-width = 200 - 10 - 10 - 1 - 1 = 178。

现在高版本的浏览器基本上默认都是使用标准盒模型,而像 IE6 这种老古董才是默认使用 IE 盒模型的。

4.3 盒模型的转换

在 CSS3 中新增了一个属性 box-sizing,允许开发者来指定盒子使用什么标准,它有 2 个值:

  • content-box:标准盒模型;
  • border-box:IE 盒模型;

5. css四种格式化上下文

格式化上下文(Formatting Context)是 CSS2.1 规范中的一个概念,大概说的是页面中的一块渲染区域,规定了渲染区域内部的子元素是如何排版以及相互作用的。

5.1 BFC (Block Formatting Context) 块级格式化上下文;

概念:块格式化上下文,它是一个独立的渲染区域,只有块级盒子参与,它规定了内部的块级盒子如何布局,并且与这个区域外部毫不相干。

5.11 BFC 渲染规则

  1. 内部的盒子会在垂直方向,一个接一个地放置;
  2. 盒子垂直方向的距离由 margin 决定,属于同一个 BFC 的两个相邻盒子的 margin 会发生重叠;
  3. 每个元素的 margin 的左边,与包含块 border 的左边相接触(对于从左往右的格式化,否则相反),即使存在浮动也是如此;
  4. BFC 的区域不会与 float 盒子重叠;
  5. BFC 就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。
  6. 计算 BFC 的高度时,浮动元素也参与计算。

5.12 怎么触发bfc

  1. 根元素:html
  2. 非溢出的可见元素:overflow 不为 visible
  3. 设置浮动:float 属性不稳 none
  4. 设置定位:position 为 absolute 或 fixed
  5. 定义成块级的非块级元素:display: inline-block/table-cell/table-caption/flex/inline-flex/grid/inline-grid

5.13 BFC的应用场景

  1. 自适应的两栏布局 应用原理: BFC 的区域不会和浮动区域重叠,所以就可以把侧边栏固定宽度且左浮动,而对右侧内容触发 BFC,使得它的宽度自适应该行剩余宽度。
  2. 清除内部浮动 应用原理: 浮动造成的问题就是父元素高度坍塌,所以清除浮动需要解决的问题就是让父元素的高度恢复正常。而用 BFC 清除浮动的原理就是:计算 BFC 的高度时,浮动元素也参与计算。只要触发父元素的 BFC 即可。
  3. 防止垂直margin 合并 应用原理: 同一个 BFC 下的垂直 margin 会发生合并。所以如果让 2 个元素不在同一个 BFC 中即可阻止垂直 margin 合并。那如何让 2 个相邻的兄弟元素不在同一个 BFC 中呢?可以给其中一个元素外面包裹一层,然后触发其包裹层的 BFC,这样一来 2 个元素就不会在同一个 BFC 中了。

BFC的应用场景有代码

以上内容参考c s s原理-[Formatting Context]

5.2 IFC 行内格式化上下文

IFC 的形成条件非常简单,块级元素中仅包含内联级别元素,需要注意的是当IFC中有块级元素插入时,会产生两个匿名块将父元素分割开来,产生两个 IFC。

5.21IFC 渲染规则

  1. 子元素在水平方向横排排列,并且垂直方向七点为元素的顶部;
  2. 子元素只会计算横向样式空间,[padding,border,margin],垂直方向的样式空间不会被计算[padding,border,margin],
  3. 垂直方向上,子元素会以不同的形式来对齐(vertical-align)
  4. 能把在一行上的框都完全包含进去的一个矩形区域,被称为该行的线盒(行框)(line box)。线盒的宽度是由包含块(containing box)和与其中的浮动来决定;
  5. IFC 中的 line box 一般左右边贴紧其包含块,但 float 元素会优先排列。
  6. IFC 中的 line box 高度由 line-height 计算规则来确定,同个 IFC 下得多个 line box 高度可能会不同;
  7. 当内联级盒子的总宽度少于包含它们的 line box 时,其水平渲染规则由 text-align 属性值来决定;
  8. 当一个内联盒子超过父元素的宽度时,它会被分割成多盒子,这些盒子分布在多个 line box 中。如果子元素未设置强制换行的情况下,inline box 将不可被分割,将会溢出父元素。

5.22 IFC 的应用场景

  • 水平居中:当一个块要在环境中水平居中时,设置其为 inline-block 则会在外层产生 IFC,通过 text-align 则可以使其水平居中。
  • 垂直居中:创建一个 IFC,用其中一个元素撑开父元素的高度,然后设置其 vertical-align: middle,其他行内元素则可以在此父元素下垂直居中。

5.3 FFC (Flex Formatting Context) 弹性格式化上下文;

就是flex布局这里就不多介绍了请看阮一峰的文章f le x 布局

5.4 GFC (Grid Formatting Context) 栅格式化上下文;

内容过多建议查看阮一峰的文章Grid 网格布局教程

6. css的值和单位(px,em,rem, vw/vh)

6.1 px

其实屏幕分辨率是指在屏幕的横纵方向上的像素点数量,比如分辨率 1920×1080 意味着水平方向含有 1920 个像素数,垂直方向含有 1080 个像素数。px表示css像素,在css中是绝对的长度单位,也是基础单位,其他长度单位会被浏览器换算成px。但是对于设备而言p x又是相对单位,比如说宽高为2px正常屏幕下,其实就是4个像素点,而在设备像素比(devicePixelRatio) 为 2 的 Retina 屏幕下,它就有 16 个像素点。所以屏幕尺寸一致的情况下,屏幕分辨率越高,显示效果就越细腻。

6.2 相对单位em

em 是 CSS 中x相对的长度单位。

  1. 在 font-size 中使用是相对于父元素的 font-size 大小,比如父元素 font-size: 16px,当给子元素指定 font-size: 2em 的时候,经过计算后它的字体大小会是 32px;
  2. 在其他属性中使用是相对于自身的字体大小,如 width/height/padding/margin 等;

em计算的时候会层层计算:比如

<div>
    <p></p>
</div>
div { font-size: 2em; }
p { font-size: 2em; }

对于上面的例子 由于html 的字体大小是16px,所以p标签最终计算出来后的字体大小是 16 * 2 * 2 = 64px

6.3 相对单位rem

rem(root em) 和em一样也是相对长度单位,不过rem 相对的是html 根元素的font-size 值。

rem 由于是基于 html 的 font-size 来计算,所以通常用于自适应网站或者 H5 中。

比如在做 H5 的时候,前端通常会让 UI 给 750px 宽的设计图,而在开发的时候可以基于 iPhone X 的尺寸 375px * 812px 来写页面,这样一来的话,就可以用下面的 JS 依据当前页面的视口宽度自动计算出根元素 html 的基准 font-size 是多少。

(function (doc, win) {
    var docEl = doc.documentElement,
        resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize',
        psdWidth = 750,  // 设计图宽度
        recalc = function () {
            var clientWidth = docEl.clientWidth;
            if ( !clientWidth ) return;
            if ( clientWidth >= 640 ) {
                docEl.style.fontSize = 200 * ( 640 / psdWidth ) + 'px';
            } else {
                docEl.style.fontSize = 200 * ( clientWidth / psdWidth ) + 'px';
            }
        };

    if ( !doc.addEventListener ) return;
    // 绑定事件的时候最好配合防抖函数
    win.addEventListener( resizeEvt, debounce(recalc, 1000), false );
    doc.addEventListener( 'DOMContentLoaded', recalc, false );
    
    function debounce(func, wait) {
        var timeout;
        return function () {
            var context = this;
            var args = arguments;
            clearTimeout(timeout)
            timeout = setTimeout(function(){
                func.apply(context, args)
            }, wait);
        }
    }
})(document, window);

比如当视口是 375px 的时候,经过计算 html 的 font-size 会是 100px,这样有什么好处呢?好处就是方便写样式,比如从设计图量出来的 header 高度是 50px 的,那我们写样式的时候就可以直接写:

header {
    height: 0.5rem;
}

6.4 vw/vh (相对单位)

vw 和 vh 分别是相对于屏幕视口宽度和高度而言的长度单位:

  • 1vw = 视口宽度均分成 100 份中 1 份的长度;
  • 1vh = 视口高度均分成 100 份中 1 份的长度;

相对视口的单位,除了 vw/vh 外,还有 vmin 和 vmax:

  • vmin:取 vw 和 vh 中值较小的;
  • vmax:取 vw 和 vh 中值较大的;

image-20211118100339533

7. 1px边框线问题

Retina 显示屏比普通的屏幕有着更高的分辨率,所以在移动端的 1px 边框就会看起来比较粗,为了美观通常需要把这个线条细化处理。

最完美的解决方案:媒体查询+伪类+ transform 实现

.scale-1px-bottom {
    position: relative;
    border:none;
}
@media (-webkit-min-device-pixel-ratio: 2) {
  .scale-1px-bottom::after {
    content: '';
    position: absolute;
    left: 0;
    bottom: 0;
    background: #000;
    width: 100%;
    height: 1px;
    -webkit-transform: scaleY(0.5);
    transform: scaleY(0.5);
    -webkit-transform-origin: 0 0;
    transform-origin: 0 0;
     }
  }



同时设置4个方向的边框线 写在项目里自己要添加关于媒体查询的内容哟

.scale-1px {
    position: relative;
    margin-bottom: 20px;
    border:none;
}
.scale-1px::after {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    border: 1px solid #000;
    -webkit-box-sizing: border-box;
    box-sizing: border-box;
    width: 200%;
    height: 200%;
    -webkit-transform: scale(0.5);
    transform: scale(0.5);
    -webkit-transform-origin: left top;
    transform-origin: left top;
}

8.清除浮动

浮动概念: 浮动元素会脱离文档流并向左/向右浮动,直到碰到父元素或者另一个浮动元素。

需要清除浮动的原因,它造成的问题?

因为浮动元素会脱离正常的文档流,并不会占据文档流的位置,所以如果一个父元素下面都是浮动元素,那么这个父元素就无法被浮动元素所撑开,这样一来父元素就丢失了高度,这就是所谓的浮动造成的父元素高度坍塌问题。

父元素高度一旦坍塌将对后面的元素布局造成影响,为了解决这个问题,所以需要清除浮动,让父元素恢复高度,那该如何做呢?

清除浮动的两种方式:1BFC 清除浮动,2.clear清除浮动

8.1 BFC清除浮动

原理: 计算BFC元素的高度的时候浮动的子元素的高度也会计算在内,就是利用这条规则清除浮动的。

假设一个父元素 parent 内部只有 2 个人元素 child,且它们都是左浮动的,这个时候 parent 如果没有设置高度的话,因为浮动造成了高度坍塌,所以 parent 的高度会是 0,此时只要给 parent 创造一个 BFC,那它的高度就能恢复了。

而产生 BFC 的方式很多,我们可以给父元素设置overflow: auto 来简单的实现 BFC 清除浮动,但是为了兼容 IE 最好用 overflow: hidden。

.parent {
    overflow: hidden;
}

8.2 通过clear 清除浮动

.clearfix {  // ie低版本浏览器兼容
    zoom: 1;
}
.clearfix::after {
    content: ""; // 内容为空保证高度为0
    display: block;  //clear: both; 只对块元素起作用
    clear: both;  // 清除浮动的关键
}

可以结合这个 codepen demo 一起理解上图的 clear 清楚浮动原理。

上面这个 demo 或者图里为了展示需要所以给伪元素的内容设置为了 ::after,实际使用的时候需要设置为空字符串,让它的高度为 0,从而父元素的高度都是由实际的子元素撑开。

参考:CSS中的浮动和清除浮动,梳理一下

9. 清除浏览器的默认样式

针对同一个类型的 HTML 标签,不同的浏览器往往有不同的表现,所以在网站制作的时候,开发者通常都是需要将这些浏览器的默认样式清除,让网页在不同的浏览器上能够保持一致。

针对清楚浏览器默认样式参考CSS 大师 Eric A. Meyer 写的reset.css ;

html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed, 
figure, figcaption, footer, header, hgroup, 
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
    margin: 0;
    padding: 0;
    border: 0;
    font-size: 100%;
    font: inherit;
    vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure, 
footer, header, hgroup, menu, nav, section {
    display: block;
}
body {
    line-height: 1;
}
ol, ul {
    list-style: none;
}
blockquote, q {
    quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
    content: '';
    content: none;
}
table {
    border-collapse: collapse;
    border-spacing: 0;
}

除了 reset.css 外,后来又出现了 Normalize.css 。关于 Normalize.css, 其作者 necolas 专门写了一篇文章介绍了它,并谈到了它和 reset.css 的区别。这个是他写那篇文章的翻译版:让我们谈一谈 Normalize.css。

9. 长文本溢出处理

这个偷个懒就不写写那么多描述

查看以上这些方案的示例: codepen demo

10. 常用的布局方,两栏布局三栏布局

这里不多写了看我之前的知乎文章:常见的两栏布局三栏布局,圣杯双飞翼布局方案

11.响应式布局方案

对响应式布局的理解: 就是根据网页页面的放大缩小或者不同的机型,显示出来的页面效果是一样美观的。

11.1 移动端响应式布局方案。

  • Rem 等比缩放,根据根元素字体设定rem的值
  • 设备尺寸发生变化,从写计算根元素的字体大小,这样说有元素的大小就会跟着自适应
  • 用flex 辅助布局

11.2 手机端p c 端公用同一套代码

  • 用媒体查询呀 媒体查询规则
  • 用flex 辅助布局

11.3 大屏幕适配

  • 大块轮廓用vw vh(百分比布局):小块写固定
  • 样式不满意在用媒体查询微调
  • 用flex 辅助布局

12. 前端需要注意哪些SEO

  1. 合理的titledescriptionkeywords:搜索对着三项的权重逐个减小,title值强调重点即可,重要关键词出现不要超过2次,而且要靠前,不同页面title要有所不同;description把页面内容高度概括,长度合适,不可过分堆砌关键词,不同页面description有所不同;keywords列举出重要关键词即可
  2. 语义化的HTML代码,符合W3C规范:语义化代码让搜索引擎容易理解网页
  3. 重要内容HTML代码放在最前:搜索引擎抓取HTML顺序是从上到下,有的搜索引擎对抓取长度有限制,保证重要内容一定会被抓取
  4. 重要内容不要用js输出:爬虫不会执行js获取内容
  5. 少用iframe:搜索引擎不会抓取iframe中的内容
  6. 非装饰性图片必须加alt
  7. 提高网站速度:网站速度是搜索引擎排序的一个重要指标

13. 如何进行网站性能优化

  • content方面 减少HTTP请求:合并文件、CSS精灵、inline Image减少DNS查询:DNS缓存、将资源分布到恰当数量的主机名减少DOM元素数量
  • Server方面 使用CDN配置ETag对组件使用Gzip压缩
  • Cookie方面 减小cookie大小
  • css方面 将样式表放到页面顶部不使用CSS表达式使用<link>不使用@import
  • Javascript方面 将脚本放到页面底部将javascriptcss从外部引入压缩javascriptcss删除不需要的脚本减少DOM访问
  • 图片方面 优化图片:根据实际颜色需要选择色深、压缩优化css精灵不要在HTML中拉伸图片

你有用过哪些前端性能优化的方法?

  • 减少http请求次数:CSS Sprites, JS、CSS源码压缩、图片大小控制合适;网页Gzip,CDN托管,data缓存 ,图片服务器。
  • 前端模板 JS+数据,减少由于HTML标签导致的带宽浪费,前端用变量保存AJAX请求结果,每次操作本地变量,不用请求,减少请求次数
  • 用innerHTML代替DOM操作,减少DOM操作次数,优化javascript性能。
  • 当需要设置的样式很多时设置className而不是直接操作style
  • 少用全局变量、缓存DOM节点查找的结果。减少IO读取操作
  • 避免使用CSS Expression(css表达式)又称Dynamic properties(动态属性)
  • 图片预加载,将样式表放在顶部,将脚本放在底部 加上时间戳
  • 避免在页面的主体布局中使用table,table要等其中的内容完全下载之后才会显示出来,显示比div+css布局慢

谈谈性能优化问题

  • 代码层面:避免使用css表达式,避免使用高级选择器,通配选择器
  • 缓存利用:缓存Ajax,使用CDN,使用外部js和css文件以便缓存,添加Expires头,服务端配置Etag,减少DNS查找等
  • 请求数量:合并样式和脚本,使用css图片精灵,初始首屏之外的图片资源按需加载,静态资源延迟加载
  • 请求带宽:压缩文件,开启GZIP

前端性能优化最佳实践?

  • 性能评级工具(PageSpeed 或 YSlow)
  • 合理设置 HTTP 缓存:Expires 与 Cache-control
  • 静态资源打包,开启 Gzip 压缩(节省响应流量)
  • CSS3 模拟图像,图标base64(降低请求数)
  • 模块延迟(defer)加载/异步(async)加载
  • Cookie 隔离(节省请求流量)
  • localStorage(本地存储)
  • 使用 CDN 加速(访问最近服务器)
  • 启用 HTTP/2(多路复用,并行加载)
  • 前端自动化(gulp/webpack)

eautiful Soup 简介

Beautiful Soup 是一个可以从 HTML 或 XML 文件中提取数据的 Python 库,它提供了一些简单的操作方式来帮助你处理文档导航,查找,修改文档等繁琐的工作。因为使用简单,所以 Beautiful Soup 会帮你节省不少的工作时间。

上一篇文章我们介绍了如何使用 Beautiful Soup 来遍历文档中的节点,这片文章我们继续血学习如何使用 Beautiful Soup 指定文档中搜索到你想要的内容。

Beautiful Soup 搜索文档

同样为了故事的顺利发展,我们继续使用之前的 HTML 文本,下文的所有例子都是基于这段文本的。

html_doc = """
<html><head><title>index</title></head>
<body>
<p class="title"><b>首页</b></p>
<p class="main">我常用的网站
<a href="https://www.google.com" class="website" id="google">Google</a>
<a href="https://www.baidu.com" class="website" id="baidu">Baidu</a>
<a href="https://cn.bing.com" class="website" id="bing">Bing</a>
</p>
<div><!--这是注释内容--></div>
<p class="content1">...</p>
<p class="content2">...</p>
</body>
"""
soup = BeautifulSoup(html_doc, "lxml")

过滤器

正式讲解搜索文档之前,我们有必要了解下 Beautiful Soup 的过滤器,这些过滤器在整个搜索的 API 中都有所体现,他们可以被用在 TAG 的 name 中,属性中,字符串中或他们的混合中。听起来有点绕是么,看几个例子就懂了。

1、根据 TAG 的 name 来查找标签,下面的例子会查找文档中的所有 b 标签。同时要注意统一传入 Unicode 编码以避免 Beautiful Soup 解析编码出错。

# demo 1
tags = soup.find_all('b')
print(tags)

#输出结果
[<b>首页</b>]

2、如果传入正则表达式作为参数,那么 Beautiful Soup 会通过正则表达式的 match() 来匹配内容。

# demo 2
import re
for tag in soup.find_all(re.compile("^b")):
    print(tag.name)

#输出结果
body
b

3、如果传入列表参数,那么 Beautiful Soup 会将与列表中任一一个元素匹配的内容返回。

# demo 3
for tag in soup.find_all(['a', 'b']):
    print(tag)

#输出结果
<b>首页</b>
<a class="website" href="https://www.google.com" id="google">Google</a>
<a class="website" href="https://www.baidu.com" id="baidu">Baidu</a>
<a class="website" href="https://cn.bing.com" id="bing">Bing</a>

4、True 可以匹配任何值,下面的例子是查找所有的 TAG 但不会返回字符串。

# demo 4
for tag in soup.find_all(True):
    print(tag.name, end=', ')
 
#输出结果
html, head, title, body, p, b, p, a, a, a, div, p, p, 

5、方法。我们可以定义一个方法,该方法只接受一个参数,若该方法返回 True 则表示当前元素匹配并且被找到,返回 False 意味着没找到。下面的例子展示了查找所有同时包含 class 属性和 id 属性的节点。

# demo 5
def has_id_class(tag):
    return tag.has_attr('id') and tag.has_attr('class')

tags = soup.find_all(has_id_class)
for tag in tags:
	print(tag)
	
#输出结果
<a class="website" href="https://www.google.com" id="google">Google</a>
<a class="website" href="https://www.baidu.com" id="baidu">Baidu</a>
<a class="website" href="https://cn.bing.com" id="bing">Bing</a>

大部分情况字符串过滤器就可以满足我们的需求,外加这个神奇的方法过滤器,我们就可以实现各种自定义需求了。

find_all() 函数

该函数搜索当前节点下的所有子节点,其签名如下find_all( name , attrs , recursive , text , **kwargs )。我们可以传入指定 TAG 的 name 来查找节点,上面已经举过例子了,这里不在赘述。我们来看几个其他的用法。

1、如果我们传入 find_all() 函数不是搜索内置的参数名,那么搜索是就会将该参数对应到属性上去。下文的例子表示查找 id 为 google 的节点。

搜索指定名字的属性时可以使用的参数值包括:字符串,正则表达式,列表,True。也就是我们上文介绍过的过滤器。

# demo 6
tags = soup.find_all(id='google')
print(tags[0]['href'])

for tag in soup.find_all(id=True): # 查找所有包含 id 属性的 TAG
	print(tag['href'])

#输出结果
https://www.google.com
https://www.google.com
https://www.baidu.com
https://cn.bing.com

2、按照 CSS 类名搜索,但是镖师 CSS 的关键字 class 在 Python 中是内置关键字,从 Beautiful Soup 4.1.1 版本开始,可以通过 class_ 参数搜索有指定 CSS 类名的 TAG:

class_ 参数同样接受不同类型的过滤器:字符串,正则表达式,方法,True。

# demo 7
tags = soup.find_all("a", class_="website")
for tag in tags:
	print(tag['href'])

def has_seven_characters(css_class):
    return css_class is not None and len(css_class) == 7

for tag in soup.find_all(class_=has_seven_characters):
	print(tag['id'])

#输出结果
https://www.google.com
https://www.baidu.com
https://cn.bing.com
google
baidu
bing

同时,因为 CSS 可以有多个值,所以我们可以分别搜索 CSS 中的每个值。

# demo 8
css_soup = BeautifulSoup('<p class="body strikeout"></p>', 'lxml')
tags = css_soup.find_all("p", class_="strikeout")
print(tags)

#输出结果
[<p class="body strikeout"></p>]

3、不仅可以按照标签和 CSS 来搜索整个文档,还可以使用 text 来按照内容来搜索。同时 text 还可以配合其他属性一起来完成搜索任务。

# demo 9
tags = soup.find_all(text="Google")
print("google : ", tags)

tags = soup.find_all(text=["Baidu", "Bing"])
print("baidu & bing : ", tags)

tags = soup.find_all('a', text="Google")
print("a[text=google] : ", tags)

#输出结果
google :  ['Google']
baidu & bing :  ['Baidu', 'Bing']
a[text=google] :  [<a class="website" href="https://www.google.com" id="google">Google</a>]

4、限制返回数量

有时候文档树过于庞大,我们不想查查找整棵树,只想查找指定数量的节点,或者只想查找子节点,而不想查找孙子节点,指定 limit 或者 recursive 参数即可。

# demo 10
tag = soup.find_all("a", limit=1)
print(tag)

tags = soup.find_all("p", recursive=False)
print(tags)

#输出结果
[<a class="website" href="https://www.google.com" id="google">Google</a>]
[]

因为该对象的儿子节点没有 p 标签,所以返回的是空列表。

find() 函数

该函数只会返回一个结果,与 find_all(some_args, limit=1) 是等价的,唯一的区别就是该函数直接返回结果,而 find_all() 函数返回包含一个结果的列表。另外 find_all() 方法没有找到目标是返回空列表, find() 方法找不到目标时,返回 None。除此之外使用上没有其他差别。

其他函数

除了 find_all() 和 find() 外,Beautiful Soup 中还有 10 个用于搜索的 API,其中中五个用的是与 find_all() 相同的搜索参数,另外 5 个与 find() 方法的搜索参数类似,区别仅是它们搜索文档的范围不同。

find_parents() 和 find_parent() 用来搜索当前节点的父节点。

find_next_siblings() 和 find_next_sibling() 对在当前节点后面解析的所有兄弟节点进行迭代。

find_previous_siblings() 和 find_previous_sibling() 对在当前节点前面解析的所有兄弟节点进行迭代。

find_all_next() 和 find_next() 对当前节点之后的 TAG 和字符串进行迭代。

find_all_previous() 和 find_previous() 对当前节点之前的 TAG 和字符串进行迭代。

以上五组函数的区别仅仅是前者返回一个所有符合搜索条件的节点列表,而后者只返回第一个符合搜索条件的节点。

因为这 10 个 API 的使用和 find_all() 与 find() 大同小异,所有i这里不在举例,读者可以自己探索。

CSS 选择器

在 Tag 或 BeautifulSoup 对象的 .select() 方法中传入字符串参数即可使用 CSS 选择器的语法找到 TAG。

1、通过某个标签逐层查找。

# demo 11
tags = soup.select("body a")
for tag in tags:
	print(tag['href'])

#输出结果
https://www.google.com
https://www.baidu.com
https://cn.bing.com

2、查找某个标签下的直接子标签

# demo 12
tags = soup.select("p > a")
print(tags)

tags = soup.select("p > #google")
print(tags)

#输出结果
[<a class="website" href="https://www.google.com" id="google">Google</a>, <a class="website" href="https://www.baidu.com" id="baidu">Baidu</a>, <a class="website" href="https://cn.bing.com" id="bing">Bing</a>]
[<a class="website" href="https://www.google.com" id="google">Google</a>]

3、通过 CSS 类名直接查找

# demo 13
tags = soup.select(".website")
for tag in tags:
	print(tag.string)

#输出结果
Google
Baidu
Bing

4、通过标签的 id 属性查找

# demo 14
tags = soup.select("#google")
print(tags)

#输出结果
[<a class="website" href="https://www.google.com" id="google">Google</a>]

5、通过属性的值来查找

# demo 15
tags = soup.select('a[href="https://cn.bing.com"]')
print(tags)

#输出结果
[<a class="website" href="https://cn.bing.com" id="bing">Bing</a>]

Beautiful Soup 总结

本章节介绍了 Beautiful Soup 关于文档搜索的相关操作,熟练掌握这些 API 的操作可以让我们更快更好找到我们想要定位的节点,不要看到这么多函数吓怕了,其实我们只需要熟练掌握 find_all() 和 find() 两个函数即可,其余 API 的使用都大同小异,稍加练习即可快速上手。

avaScript 是互联网上最流行的脚本语言,这门语言可用于 HTML 和 web,可广泛用于服务器、PC、笔记本电脑、平板电脑和智能手机等设备。它是一个脚本语言,它是一个轻量级,但功能强大的编程语言,它也是有语法规则,有变量定义的编程语言。

15.1 变量常量

在js中,声明变量,可以用var或let关键字。在ES6之前,我们都是用var来声明变量,而且JS只有函数作用域和全局作用域,没有块级作用域,所以{}限定不了var声明变量的访问范围,而let解决了这个问题。在ES6中,还新增了const关键字,用于声明常量。

let s = "老陈说编程"
var i = 100;
const PI = 3.14;

15.2 数据类型

在js中,数据类型有值类型:字符串(String)、数字(Number)、布尔(Boolean)、对空(Null)、未定义(Undefined),还有引用数据类型:对象(Object)、数组(Array)和函数(Function)。可以使用 typeof 操作符来检测变量的数据类型。

// 字符串
var laochen="老陈说编程";
// 数字
var num = 10;
// 布尔
var x = true;
// 数组
var p = new Array("Python","前端","Java","App");
p[1]="前端+小程序"
/*对象*/
var person={
      id:  666,
      firstname : "老陈",
      lastname  : "陈老"
           };
/* 访问对象属性 */
firstname =person.firstname;
lastname =person["lastname"];

15.3 字符串

字符串用于存储和处理文本。在日常,在编程中,都是经常见到,以至于大多数编程语言,都对其特别"照顾",提供好多专门用于处理字符串的方法。在Javascript中,字符串可以使用单引号或双引号声明。方法挺多的,用到时,自己查一下就好了,我只说几个关键的。

var s = "老陈说编程";
// 用索引访问字符
var c = s[2];
// 计算字符串的长度
var len = s.length;
// 用加号或concat()附件其他字符串
var new_str = s + ",只说实用的技术";
new_str = new_str.concat(",如Python、Java、App等。");
// 获取子字符串
var sub = new_str.substring(0,11);

15.4 运算符

上过幼儿园的朋友都知道,要进行数学运算时, 要用到+、-、*、/等运算符。有了运算符,计算方便的不得了,特别是1+1这种。好了,不开玩笑了,说下Javascript的4种运算符。

1. 算术运算符

在大多数编程语言中,算术运算符都会有+(加法)、-(减法)、*(乘法)、/(除法)、%(取模-余数)、++(自增)、--(自减)这几种,你学会了Js的,在其他编程语言中,用法也是一样的。

var x = 100, y = 8;
// 自增
y++;
// 自减
x--;
// 加法
x = x + y;
// 减法
x = x - y;
// 乘法
x = x * y;
// 除法
x = x / y;
// 取模
x = x % y;

2. 赋值运算符

同大多数编程语言一样,Js的赋值也是用=,同运算符结合之后,便有了+=、-=、*=、/=和%=。

var x = 100, y = 8;
// 加法
x += y;
// 减法
x -= y;
// 乘法
x *= y;
// 除法
x /= y;
// 取模
x %= y;

3. 比较运算符

比较运算符在逻辑语句中使用,以测定变量或值是否相等,结果返回true或者false。在Js中,比较两个数用==符号, 不等于!=, 大于>,小于<,大于或等于>=和小于或等于<= 。

var x = 100, y = 8;
var result = (x>=y);

4. 逻辑运算符

逻辑运算符用于测定变量或值之间的逻辑,常用多个组合式的判断。大多数编程语言,常用的逻辑运算符有和&&、或||和非!,这3个符号。

var x = 1001, y = 11;
var result = (x>80) && y > 10;

15.5 语句

语句,是一门编程语言的核心内容,有了语句,编程的世界才精彩。JavaScritp语句内有有条件语句、for循环语句和while语句。

1. 条件语句

条件语句用于基于不同的条件来执行不同的动作(业务),在 JavaScript 中,我们可使用的条件语句有if、if...else、if...else if....else和switch 语句。

let lang = 1;
let result = ""
switch (lang) {
    case 1:
        result = "Python";
        break;
    case 2:
        result = "前端";
        break;
    case 3:
        result = "App";
        break;
    default:
        result = "Java";
}

2. for循环

for循环可以将代码块执行指定的次数,如果您希望一遍又一遍地运行相同的代码,并且每次的值都不同,那么使用循环是很方便的。

for 循环的语法:for (语句 1; 语句 2; 语句 3) { 被执行的代码块 } 。

let result = ""
for (let i=0; i<10; i++)
{
    result += i + "<br/>";
}

3. while循环

while 循环会在指定条件下循环执行代码块。只要符合指定条件为 true,循环就可以一直执行代码块。

while (条件)

{

需要执行的代码

}

let i = 1;
let result = "";
while (i < 6) {
    result += i + "<br/>";
    i++;
}

do/while 循环是 while 循环的变体。该循环会在检查条件是否为真之前执行一次代码块,然后如果条件为真的话,就会重复这个循环。

do
{
需要执行的代码
}
while (条件);

let i = 1;
let result = ""
do {
    result += i + "<br/>";
    i++;
}
while (i < 5);

15.6 函数

函数是可重复使用的代码块,在面向对象里,函数也叫作方法。JavaScript 函数语法:

function 函数名(argument1,argument2)
{
// 执行代码
}

函数参数可以是0个,也可以是多个。

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Javascript语法</title>
    <style>
        button {
            border: none;
            color: white;
            padding: 8px 32px;
            font-size: 16px;
            margin-top: 15px;
        }

        .bl {
            background-color: #4CAF50; /* Green */
        }
    </style>
    <script>
        function myFun(name) {
            alert(name + "说编程");
        }
    </script>
    </script>
</head>
<body>
<button class="bl" onclick="myFun('老陈')">调用函数</button>
</body>
</html>

好了,有关javascript语法的内容,老陈讲完了,如果觉得对你有所帮助,希望老铁能转发点赞,让更多的人看到这篇文章。你的转发和点赞,就是对老陈继续创作和分享最大的鼓励。

一个当了10年技术总监的老家伙,分享多年的编程经验。想学编程的朋友,可关注:老陈说编程。分享Python,前端(小程序)、App和嵌入式方面的干货。关注我,没错的。

#前端##HTML5##JavaScript##程序员##Web#