Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 国产成+人+综合+欧美亚洲,精品久久在线观看,免费一级日本c片完整版

          整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          「2022」打算跳槽漲薪,必問面試題及答案-VUE篇

          「2022」打算跳槽漲薪,必問面試題及答案-VUE篇

          、為什么選擇VUE,解決了什么問題?

          vue.js 正如官網所說的,是一套構建用戶界面的漸進式框架。與其它重量級框架不同的是,vue 被設計為可以自底向上逐層應用。vue 的核心庫只關注視圖層,不僅易于上手,還便于與第三方庫或既有項目整合。另外一方面,當與現代化工具鏈以及各種支持類庫結合使用時,vue 也完全能夠為復雜的單頁應用提供驅動。

          vue.js 有聲明式,響應式的數據綁定,組件化開發,并且還使用虛擬 DOM 等技術,統一編程規范和模塊等,將項目功能模塊化更方便組織和構建復雜應用,便于項目的擴展和維護。 vue 框架維護及時,且 Vue 3 將在 2022 年 2 月 7 日 成為新的默認版本。

          2、如果加入 keep-alive,第一次進入組件會執行哪些生命周期函數?

          會執行的鉤子函數以及它們的順序分別為:

          beforeCreat、created、beforeMount、mounted、activated

          3、key 的作用和工作原理。

          key 的作用主要是為了高效地更新虛擬 DOM,其原理是 vue 中在 patch 過程中,通過 key 可以精準判斷兩個節點是否是同一個,從而避免頻繁更新不同元素,使得整個 patch 過程更加高效,減少 DOM 操作量,提高性能。

          另外,若不設置 key 還可能在列表更新時,引發一些隱蔽的 bug 。vue 在使用相同標簽名元素的過濾或切換時,也會使用到 key 屬性,其目的也是為了讓 vue 可以區分它們,否則 vue 只會替換其內部屬性而不會觸發過濾效果。

          4、v-if 和 v-for 的優先級哪個高?

          v-for 的優先級更高。

          如果 v-if 和 v-for 同時出現,每次渲染都會先執行循環,再判斷條件,無論如何循環都不可避免,浪費了性能。

          情景一:每次遍歷時,都需要執行 v-if 解析一次,浪費性能。

          <ul>
            <li
              v-for="user in users"
              v-if="shouldShowUsers"
              :key="user.id"
            >
              {{ user.name }}
            </li>
          </ul>

          要避免出現這種情況,則在外層嵌套 template ,在這一層進行 v-if 判斷,然后在內部進行 v-for 循環。可以改為:

          <ul>
            <template v-if="shouldShowUsers">
             <li
               v-for="user in users"
              :key="user.id"
            >
              {{ user.name }}
            </li>
           </template>
          </ul>

          情景二:v-if 和 v-for 同時出現在一個標簽,過濾一個列表中的項目,比如:

          <ul>
            <li
              v-for="user in users"
              v-if="user.isActive"
              :key="user.id"
            >
              {{ user.name }}
            </li>
          </ul>

          在這種情況下,請將 users 替換為一個計算屬性,讓其返回過濾后的列表。

          <ul>
            <li
              v-for="user in activeUsers"
              :key="user.id"
            >
              {{ user.name }}
            </li>
          </ul>
          computed: {
            activeUsers: function () {
              return this.users.filter(function (user) {
                return user.isActive
              })
            }
          }

          5、談談對 vue 組件化的理解。

          5.1、組件化的定義

          組件是獨立和可復用的代碼組織單元,組件系統是 vue 核心特性之一,它使開發者使用小型、獨立和通常可復用的組件構建大型應用。

          也可以通俗介紹,把一些用戶在程序中一些獨立的功能和模塊單獨提取出來,然后切分為更小的塊,這些塊有獨立的邏輯,有更好的復用性。

          組件按照分類有:頁面組件(導航)、業務組件(登錄)、通用組件(輸入框)。

          5.2、組件化特點

          vue 的組件是基于配置的,通常編寫的組件是組件配置而非組件,框架后續會生成其構造函數,它們基于 VueComponent 這個類擴展于 vue 。

          常見的組件化技術有:prop 屬性、自定義事件、插槽等,這些主要用于組件之間的通信等。

          組件之間遵循單向數據流原則。

          5.3、組件化的優點

          組件化的開發能大幅提高開發效率、測試性和復用性等。

          合理的劃分組件能夠大幅提升應用性能,組件應該是高內聚,低耦合的。

          6、為什么 data 在組件內必須是函數,而 vue 的根實例則沒有此限制?

          vue 組件可能存在多個實例,如果使用對象形式定義 data ,則會導致它們公用一個 data 對象,那么狀態變更將會影響所有組件實例,這是不合理的。

          如果采用函數的形式,在實例化組件時,data 會被當做工廠函數返回一個全新的 data 對象,有效規避多實例之間狀態污染問題。

          所以在組件中的 data 必須是函數,不能使用對象形式。那為什么 vue 根實例沒有限制呢?

          在 vue 中根實例只能有一個,所以不需要擔心多實例的問題,所以根實例中的 data 可以是函數也可以是對象。

          7、你了解哪些 vue 性能優化的方法?

          我所了解的 vue 性能優化方法分別有:

          1>、路由懶加載

          Vue.use(VueRouter)
          // 傳統寫法
          import Home from '@/views/login/index.vue'
          
          //路由懶加載
          const  Login=()=> import('@/views/login/index.vue') 
          
          const router=new VueRouter({
           routes: [
            { path: '/login', component: Login },
            { path: '/home', component: Home },
            ]
          export default router

          使用路由懶加載,項目打包的時候體積會大幅減小,訪問項目時,這些組件也會按需進行加載,大大提升了項目性能。

          2>、keep-alive 緩存頁面

          <template>
           <keep-alive>
            <router-view /> 
           </keep-alive>  
          </template>

          使用 keep-alive 之后會緩存頁面,第一次加載之后,關閉再次打開,頁面不會重新渲染。keep-alive 的屬性:

          • include:字符串或正則表達式。如果只緩存個別頁面,可以使用 include 屬性,只緩存匹配組件。
          • exclude:字符串或正則表達式。如果個別頁面不需要緩存時,可以使用 exclude 屬性,任何匹配的組件都不會緩存。

          3>、v-for遍歷避免同時使用 v-if

          <ul>
            <li
              v-for="user in activeUsers"
              :key="user.id"
            >
              {{ user.name }}
            </li>
          </ul>
          computed: {
            activeUsers: function () {
              return this.users.filter(function (user) {
                return user.isActive
              })
            }
          }

          4>、長列表性能優化

          如果列表是純粹的數據展示,不會有任何的改變,就不需要做響應式。

          export default{
           data(){
            return {
             users:[]
            }
           },
           created(){
            const user=await axios("/api/user")
            this.users=Object.freeze(user)
           }
          }

          Object.freeze() 方法可以凍結一個對象,對象被凍結之后不能被修改,可以讓性能大幅度提升。

          如果是大數據長列表,可采用虛擬滾動,只渲染少部分區域的內容。可采用三方 vue-virtual-scroll。

          5>、事件的銷毀

          vue組件銷毀時,會自動解綁它的全部指令及事件監聽器,但是僅限于組件本身的事件。

          created(){
           this.timer=setInterval( this.refresh, 2000 )
          },
          beforeDestory(){
           clearInterval( this.timer )
          }

          6>、圖片懶加載

          對于圖片過多的頁面,為了加快頁面的加載速度,所以很多時候,需要把未出現在可視區域的圖片暫不進行加載,滾動到可視區域之后再開始加載。

          可以使用三方的 vue-lazyload 庫。

          <img v-lazy="/src/img/01.jpg" />

          7>、第三方插件按需引用

          使用三方庫時,可以按需引入避免體積太大。比如 element-ui :

          import { Button  } from "element-ui"

          8>、無狀態的組件標記為函數式組件

          <template functional>
           <div>組件內容</div>  
          </template>

          通過 functional 將組件標記為函數式組件,因為函數式組件沒有實例,所以運行時耗費資源較少。

          另外還有 v-show 復用 DOM、子組件分割、SSR 等。

          8、computed 與 methods 、watch 的區別?

          computed VS methods

          computed:{
           yyds(){
            log("computed show")
            return "計算屬性"
           }
          },
          methods:{
           show(){
            log("method show")
            return "計算屬性"
           }
          }

          computed 是計算屬性,methods 內都是方法,所以調用不同分別為:

          <div>yyds</div>
          <div>show()</div>

          computed 是有緩存的,而 methods 沒有緩存,所以 computed 性能比 methods 的好。

          computed VS watch

          computed 是計算某一個屬性的改變,如果某一個值改變了,計算屬性會監測到,然后進行返回值。

          watch 是監聽某一個數據或路由,改變了才會響應,只有改變了才會執行操作。

          9、你怎么理解 vue 中的 diff 算法?

          1.diff算法是虛擬DOM技術的必然產物:通過新舊虛擬DOM作對比(即diff),將變化的地方更新在真實DOM上;

          另外,也需要diff高效的執行對比過程,從而降低時間復雜度為O(n)。(what)

          2.vue2.x中為了降低Watcher粒度,每個組件只有一個Watcher與之對應,只有引入diff才能精確找到發生變化的地方。(why)

          3.vue中diff執行的時刻是組件實例執行其更新函數時,它會比對上一次渲染結果oldVnode和新的渲染結果newVnode,此過程稱為patch。(where)

          4.diff過程整體遵循深度優先、同層比較的策略;兩個節點之間比較會根據它們是否擁有子節點或者文本節點做不同操作;(How)

          比較兩組子節點是算法的重點,首先假設頭尾節點可能相同做4次比對嘗試,如果沒有找到相同節點才按照通用方式遍歷查找,查找結束再按情況處理剩下的節點;

          借助key通常可以非常精確找到相同節點,因此整個patch過程非常高效。

          10、props 和 data 的優先級誰高?

          vue組件內數據相關的屬性它們的樣式優先級從高到底分別為:

          props > methods > data > computed > watch

          11、vue 組件之間的通信

          vue 組件之間的關系有:父子關系、兄弟關系、隔代關系。

          所以 vue 組件之間的通信可分為:父子組件之間通信,兄弟組件之間通信和跨層組件之間通信。

          1>、父傳子

          可使用的方法有:

          • 通過 props 傳值
          • 通過 refs 傳值
          • 通過 children 傳值

          2>、子傳父

          可使用的方法:

          • $emit 自定義事件
          • provide 和 inject

          3>、兄弟組件之間

          • 利用中央事件總線 bus 的 $emit 和 $on 。
          • 笨辦法,通過父組件共同傳值

          4>、跨層組件

          • provide 和 inject

          5>、沒有關系的組件之間通信

          • 可以使用 vuex 進行數據管理

          端事件循環是什么

          前端事件循環指的是 JavaScript 在瀏覽器中運行時的一種機制,它用于處理異步事件。事件循環會不斷檢查是否有事件發生,并調用相應的回調函數來處理這些事件。

          事件循環的工作流程如下:

          1. 初始化:瀏覽器會初始化事件循環,并創建一個事件隊列。
          2. 事件發生:當用戶操作頁面、網絡請求完成或計時器超時等情況下,都會產生事件并添加到事件隊列中。
          3. 事件處理:事件循環會從事件隊列中取出事件,并調用事件的回調函數來處理事件。
          4. 重復:事件循環會不斷重復步驟 2 和 3,直到事件隊列為空。

          事件循環的優點:

          • 高效:事件循環可以高效地處理大量的異步事件。
          • 可擴展:事件循環可以擴展到支持新的事件類型。
          • 跨平臺:事件循環可以在不同的瀏覽器和操作系統上工作。

          事件循環的注意點:

          • 事件循環是單線程的:這意味著所有事件都將在同一個線程中處理。
          • 事件循環不會阻塞:即使事件循環正在處理事件,應用程序也可以執行其他操作。
          • 用戶需要確保事件回調函數是線程安全的

          瀏覽器事件循環與 Node.js 事件循環

          Node.js 和瀏覽器都使用事件循環來處理異步事件。但是,兩者之間存在一些關鍵差異:

          1. 事件隊列

          • 瀏覽器:只有一個事件隊列,用于處理所有類型的事件,包括宏任務和微任務。
          • Node.js:有兩個事件隊列,一個用于宏任務,另一個用于微任務。

          2. 任務執行順序

          • 瀏覽器:宏任務和微任務交替執行。在執行完一個宏任務后,瀏覽器會檢查微任務隊列,并執行所有待處理的微任務。
          • Node.js:宏任務和微任務是分離的。在事件循環的每個階段,Node.js 會先執行所有待處理的宏任務,然后再執行所有待處理的微任務。

          3. 事件循環的階段

          • 瀏覽器:只有一個階段,用于處理所有類型的事件。
          • Node.js:有多個階段,每個階段用于處理特定類型的事件。例如,I/O 操作會在 I/O 階段處理,計時器會在計時器階段處理。

          4. timers

          • 瀏覽器:計時器是在瀏覽器主線程中執行的。
          • Node.js:計時器是在單獨的線程中執行的。

          5. nextTick

          • 瀏覽器:nextTick 會將回調函數排隊到微任務隊列中,在下一次事件循環迭代中執行。
          • Node.js:nextTick 會將回調函數排隊到宏任務隊列中,在下一次事件循環的下一個階段執行。

          Node.js 與 libuv

          Node.js 是一個基于 JavaScript 的運行時環境,用于構建服務器端應用程序。libuv 是一個開源的 C 庫,提供了一組異步 I/O 和事件處理 API。

          Node.js 與 libuv 的關系:

          • Node.js 是建立在 libuv 之上的。libuv 為 Node.js 提供了底層的異步 I/O 和事件處理功能。
          • Node.js 提供了一組 JavaScript API,用于使用 libuv 的功能。
          • libuv 可以被其他應用程序和庫使用,而不僅僅是 Node.js。

          libuv 的主要功能:

          • 異步 I/O:libuv 提供了一組異步 I/O API,用于執行網絡操作、文件操作和其他類型的 I/O 操作。
          • 事件處理:libuv 提供了一組事件處理 API,用于處理異步事件。
          • 線程池:libuv 提供了一個線程池,用于執行 CPU 密集型任務。
          • 計時器:libuv 提供了一組計時器 API,用于執行定時任務。

          Node.js 使用 libuv 的優勢:

          • 高效:libuv 提供了高效的異步 I/O 和事件處理功能,這使得 Node.js 應用程序可以非常高效地處理大量的并發連接。
          • 可擴展:libuv 可以擴展到支持新的事件類型和新的 I/O 操作。
          • 跨平臺:libuv 是跨平臺的,這意味著 Node.js 應用程序可以在不同的操作系統上運行。

          事件循環是 libuv 的核心,也是理解 libuv 的關鍵。事件循環是一種處理事件的機制,它會不斷檢查是否有事件發生,并調用相應的回調函數來處理這些事件。

          libuv 的事件循環是基于 epoll 的,epoll 是 Linux 內核中的一種高效事件通知機制。epoll 可以監視大量的文件描述符,并通知應用程序哪些文件描述符上有事件發生。

          libuv 的事件循環主要包含以下幾個部分:

          • 事件隊列:用于存儲待處理的事件。事件隊列是一個鏈表,每個事件節點包含以下信息:事件類型事件源事件回調函數用戶數據
          • 事件源:用于生成事件。事件源可以是 I/O 操作、定時器或信號。
          • 事件回調函數:用于處理事件。事件回調函數可以執行任何操作,例如讀取數據、寫入數據或執行其他任務。

          事件循環的工作流程如下:

          1. 初始化事件循環:libuv 會調用 uv_loop_init() 函數來初始化事件循環。
          2. 注冊事件源:libuv 會調用 uv_poll()、uv_timer_init() 或 uv_signal_init() 等函數來注冊事件源到事件循環。
          3. 啟動事件循環:libuv 會調用 uv_run() 函數來啟動事件循環。
          4. 等待事件發生:libuv 會調用 epoll_wait() 函數來等待事件發生。
          5. 處理事件:如果有事件發生,libuv 會從事件隊列中取出事件節點。libuv 會調用事件節點的回調函數來處理事件。事件回調函數可以執行任何操作,例如讀取數據、寫入數據或執行其他任務。
          6. 重復步驟 4 和 5:事件循環會一直重復步驟 4 和 5,直到事件循環被停止。

          libuv 提供了以下幾種事件類型:

          • I/O 事件:用于監視 I/O 操作的完成,例如讀寫操作。
          • 定時器事件:用于定時執行某個函數。
          • 信號事件:用于處理操作系統信號。

          libuv 的事件循環具有以下優點:

          • 高效:epoll 可以高效地監視大量的文件描述符。
          • 可擴展:libuv 支持多種事件類型,可以擴展到新的事件類型。
          • 跨平臺:libuv 支持多種操作系統,可以跨平臺使用。

          以下是一些 libuv 事件循環的示例代碼:

          static void uv__poll(uv_loop_t *loop) {
            int timeout=loop->time < 0 ? -1 : loop->time;
            int nfds=epoll_wait(loop->epoll_fd, loop->watchers, ARRAY_SIZE(loop->watchers), timeout);
          
            if (nfds < 0) {
              if (errno !=EAGAIN && errno !=EINTR) {
                uv__set_error(loop, errno);
              }
              return;
            }
          
            for (i=0; i < nfds; i++) {
              uv_watcher_t *w=loop->watchers[i].data;
          
              if (w->events & UV_READABLE) {
                w->cb(w, UV_READABLE, 0);
              }
          
              if (w->events & UV_WRITABLE) {
                w->cb(w, UV_WRITABLE, 0);
              }
            }
          }
          
          

          這段代碼是 libuv 的 uv__poll() 函數,用于處理 I/O 事件。

          libuv 的事件循環是一種高效、可擴展和跨平臺的事件處理機制。理解 libuv 的事件循環對于理解 libuv 的工作原理至關重要。

          eautiful Soup 簡介

          Beautiful Soup 是一個可以從 HTML 或 XML 文件中提取數據的 Python 庫,它提供了一些簡單的操作方式來幫助你處理文檔導航,查找,修改文檔等繁瑣的工作。因為使用簡單,所以 Beautiful Soup 會幫你節省不少的工作時間。

          Beautiful Soup 安裝

          你可以使用如下命令安裝 Beautiful Soup。二選一即可。

          $ easy_install beautifulsoup4
          
          $ pip install beautifulsoup4

          Beautiful Soup 不僅支持 Python 標準庫中的 HTML 解析器,還支持很多第三方的解析器,比如 lxml,html5lib 等。初始化 Beautiful Soup 對象時如果不指定解析器,那么 Beautiful Soup 將會選擇最合適的解析器(前提是你的機器安裝了該解析器)來解析文檔,當然你也可以手動指定解析器。這里推薦大家使用 lxml 解析器,功能強大,方便快捷,而且該解析器是唯一支持 XML 的解析器。

          你可以使用如下命令來安裝 lxml 解析器。二選一即可。

          $ easy_install lxml
          
          $ pip install lxml

          Beautiful Soup 小試牛刀

          Beautiful Soup 使用來起來非常簡單,你只需要傳入一個文件操作符或者一段文本即可得到一個構建完成的文檔對象,有了該對象之后,就可以對該文檔做一些我們想做的操作了。而傳入的文本大都是通過爬蟲爬取過來的,所以 Beautiful Soup 和 requests 庫結合使用體驗更佳。

          # demo 1
          from bs4 import BeautifulSoup
          # soup=BeautifulSoup(open("index.html"))
          soup=BeautifulSoup("<html><head><title>index</title></head><body>content</body></html>", "lxml") # 指定解析器
          print(soup.head)
          
          # 輸出結果
          <head><title>index</title></head>

          Beautiful Soup 將復雜的 HTML 文檔轉換成一個復雜的樹形結構,每個節點都是 Python 對象,所有對象可以歸納為 4 種: Tag,NavigableString,BeautifulSoup,Comment。

          Tag 就是 HTML 的一個標簽,比如 div,p 標簽等,也是我們用的最多的一個對象。

          NavigableString 指標簽內部的文字,直譯就是可遍歷的字符串。

          BeautifulSoup 指一個文檔的全部內容,可以當成一個 Tag 來處理。

          Comment 是一個特殊的 NavigableString,其輸出內容不包括注視內容。

          為了故事的順利發展,我們先定義一串 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>
          """

          子節點

          Tag 有兩個很重要的屬性,name 和 attributes。期中 name 就是標簽的名字,attributes 是標簽屬性。標簽的名字和屬性是可以被修改的,注意,這種修改會直接改變 BeautifulSoup 對象。

          # demo 2
          soup=BeautifulSoup(html_doc, "lxml");
          p_tag=soup.p
          print(p_tag.name)
          print(p_tag["class"])
          print(p_tag.attrs)
          
          p_tag.name="myTag" # attrs 同樣可被修改,操作同字典
          print(p_tag)
          
          #輸出結果
          p
          ['title']
          {'class': ['title']}
          <myTag class="title"><b>首頁</b></myTag>

          由以上例子我么可以看出,可以直接通過點屬性的方法來獲取 Tag,但是這種方法只能獲取第一個標簽。同時我們可以多次調用點屬性這個方法,來獲取更深層次的標簽。

          # demo 3
          soup=BeautifulSoup(html_doc, "lxml");
          print(soup.p.b)
          
          #輸出結果
          <b>首頁</b>

          如果想獲得所有的某個名字的標簽,則可以使用 find_all(tag_name) 函數。

          # demo 4
          soup=BeautifulSoup(html_doc, "lxml");
          a_tags=soup.find_all("a")
          print(a_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>]

          我們可以使用 .contents 將 tag 以列表方式輸出,即將 tag 的子節點格式化為列表,這很有用,意味著可以通過下標進行訪問指定節點。同時我們還可以通過 .children 生成器對節點的子節點進行遍歷。

          # demo 5
          soup=BeautifulSoup(html_doc, "lxml");
          head_tag=soup.head
          print(head_tag)
          print(head_tag.contents)
          
          for child in head_tag.children:
          	print("child is : ", child)
          
          #輸出結果
          <head><title>index</title></head>
          [<title>index</title>]
          child is :  <title>index</title>

          .children 只可以獲取 tag 的直接節點,而獲取不到子孫節點,.descendants 可以滿足你。

          # demo 6
          soup=BeautifulSoup(html_doc, "lxml");
          head_tag=soup.head
          for child in head_tag.descendants:
          	print("child is : ", child)
          
          # 輸出結果
          child is :  <title>index</title>
          child is :  index

          父節點

          通過 .parent 屬性獲取標簽的父親節點。 title 的父標簽是 head,html 的父標簽是 BeautifulSoup 對象,而 BeautifulSoup 對象的父標簽是 None。

          # demo 7
          soup=BeautifulSoup(html_doc, "lxml");
          title_tag=soup.title
          
          print(title_tag.parent)
          print(type(soup.html.parent))
          print(soup.parent)
          
          # 輸出結果
          <head><title>index</title></head>
          <class 'bs4.BeautifulSoup'>
          None

          同時,我們可以通過 parents 得到指定標簽的所有父親標簽。

          # demo 8
          soup=BeautifulSoup(html_doc, "lxml");
          a_tag=soup.a
          
          for parent in a_tag.parents:
              print(parent.name)
          
          # 輸出結果
          p
          body
          html
          [document]

          兄弟節點

          通過 .next_sibling 和 .previous_sibling 來獲取下一個標簽和上一個標簽。

          # demo 9
          soup=BeautifulSoup(html_doc, "lxml");
          div_tag=soup.div
          
          print(div_tag.next_sibling)
          print(div_tag.next_sibling.next_sibling)
          
          # 輸出結果
          
          <p class="content1">...</p>

          你可能會納悶,調用了兩次 next_sibling 怎么只有一個輸出呢,這方法是不是有 bug 啊。事實上是 div 的第一個 next_sibling 是div 和 p 之間的換行符。這個規則對于 previous_sibling 同樣適用。

          另外,我們可以通過 .next_siblings 和 .previous_siblings 屬性可以對當前節點的兄弟節點迭代輸出。在該例子中,我們在每次輸出前加了前綴,這樣就可以更直觀的看到 dib 的第一個 previous_sibling 是換行符了。

          # demo 10
          soup=BeautifulSoup(html_doc, "lxml");
          div_tag=soup.div
          
          for pre_tag in div_tag.previous_siblings:
          	print("pre_tag is : ", pre_tag)
          
          # 輸出結果
          pre_tag is :  
          
          pre_tag is :  <p class="main">我常用的網站
          <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>
          </p>
          pre_tag is :  
          
          pre_tag is :  <p class="title"><b>首頁</b></p>
          pre_tag is :  

          前進和后退

          通過 .next_element 和 .previous_element 獲取指定標簽的前一個或者后一個被解析的對象,注意這個和兄弟節點是有所不同的,兄弟節點是指有相同父親節點的子節點,而這個前一個或者后一個是按照文檔的解析順序來計算的。

          比如在我們的文本 html_doc 中,head 的兄弟節點是 body(不考慮換行符),因為他們具有共同的父節點 html,但是 head 的下一個節點是 title。即soup.head.next_sibling=title soup.head.next_element=title

          # demo 11
          soup=BeautifulSoup(html_doc, "lxml");
          
          head_tag=soup.head
          print(head_tag.next_element)
          
          title_tag=soup.title
          print(title_tag.next_element)
          
          # 輸出結果
          <title>index</title>
          index

          同時這里還需要注意的是 title 下一個解析的標簽不是 body,而是 title 標簽內的內容,因為 html 的解析順序是打開 title 標簽,然后解析內容,最后關閉 title 標簽。

          另外,我們同樣可以通過 .next_elements 和 .previous_elements 來迭代文檔樹。由遺下例子我們可以看出,換行符同樣會占用解析順序,與迭代兄弟節點效果一致。

          # demo 12
          soup=BeautifulSoup(html_doc, "lxml");
          div_tag=soup.div
          for next_element in div_tag.next_elements:
          	print("next_element is : ", next_element)
          
          # 輸出結果
          next_element is :  這是注釋內容
          next_element is :  
          
          next_element is :  <p class="content1">...</p>
          next_element is :  ...
          next_element is :  
          
          next_element is :  <p class="content2">...</p>
          next_element is :  ...
          next_element is :  
          
          next_element is :  

          Beautiful Soup 總結

          本章節介紹了 Beautiful Soup 的使用場景以及操作文檔樹節點的基本操作,看似很多東西其實是有規律可循的,比如函數的命名,兄弟節點或者下一個節點的迭代函數都是獲取單個節點函數的復數形式。

          同時由于 HTML 或者 XML 這種循環嵌套的復雜文檔結構,致使操作起來甚是麻煩,掌握了本文對節點的基本操作,將有助于提高你寫爬蟲程序的效率。


          主站蜘蛛池模板: 亚洲av无码一区二区乱子伦as| 国产无线乱码一区二三区| 精品国产一区二区22| 亚洲日韩精品一区二区三区| 91一区二区在线观看精品| 国产亚洲情侣一区二区无| 日韩精品国产一区| 无码av免费毛片一区二区| 久久精品国产一区二区三区日韩| 女同一区二区在线观看| 精品无码日韩一区二区三区不卡| 亚洲欧洲一区二区三区| 国产伦精品一区二区| 免费无码一区二区三区蜜桃大| 日韩国产免费一区二区三区| 久久精品黄AA片一区二区三区| 亚洲日韩精品无码一区二区三区| 久久精品国产一区二区电影| 一区二区三区四区精品| 精品一区二区三区色花堂| av无码精品一区二区三区四区| 国产一区二区三区在线免费| 国产一区风间由美在线观看| 日本免费一区二区三区最新vr| 日韩一区二区免费视频| 八戒久久精品一区二区三区| 色欲AV无码一区二区三区| 精品乱码一区内射人妻无码| 成人免费视频一区二区| 中文字幕在线精品视频入口一区| 精品乱子伦一区二区三区高清免费播放| 天码av无码一区二区三区四区 | 亚洲一区二区三区免费| 武侠古典一区二区三区中文| 国产成人精品无人区一区| 最美女人体内射精一区二区| 精品性影院一区二区三区内射 | 亚洲视频在线一区| 69久久精品无码一区二区| 精品国产亚洲第一区二区三区| 国产亚洲综合精品一区二区三区 |